forked from LeenkxTeam/LNXSDK
Compare commits
178 Commits
Author | SHA1 | Date | |
---|---|---|---|
cdc425fbcb | |||
846bb28c86 | |||
7fabd77ef8 | |||
fb1a5c88bf | |||
e05c83a8bb | |||
ee4f62e881 | |||
59f8dff22f | |||
5572226ac5 | |||
d04874e0b3 | |||
ef8b3a99ab | |||
1d3254a237 | |||
188af4a50f | |||
c45baaf396 | |||
4b1da08819 | |||
aeb353fb20 | |||
65961b1593 | |||
1c472155e2 | |||
4238f0b2a0 | |||
b40aadf76c | |||
7277987335 | |||
a48ec4d034 | |||
7f0153f816 | |||
40d893e139 | |||
9b9289d27d | |||
8786798edd | |||
fa425a98a5 | |||
5165769088 | |||
feabf446db | |||
e770120f7d | |||
7c1b1f2dd9 | |||
88a4f0e76a | |||
d9e613b3eb | |||
a0c84dc807 | |||
5a92920b1f | |||
30a624c857 | |||
8153d67eac | |||
9963a42c76 | |||
885385d7cb | |||
c433a7f09e | |||
c7e2c7d452 | |||
2a1235b3d8 | |||
074962d158 | |||
3ea0d7da9d | |||
00b580a4fa | |||
f779462f36 | |||
2c7343aa31 | |||
85912d84fb | |||
ad0d750dd0 | |||
9914d53045 | |||
9daf6c15ab | |||
9ac3de67aa | |||
fd02f6bca3 | |||
2cc0d3db3b | |||
fe730a65ee | |||
18ec9712fd | |||
0d80f3fb6d | |||
be06b222cb | |||
3f0984e227 | |||
15a10ea3aa | |||
012abfeaf6 | |||
dd6cd16661 | |||
d8b37efe1b | |||
a40a035c03 | |||
a318758cbf | |||
7c13a25caf | |||
141567467f | |||
047983a280 | |||
48ad4322cf | |||
eaa34308d0 | |||
741a12de78 | |||
9749467cd7 | |||
91ae053346 | |||
b7b7edb5e2 | |||
dfa99fcb14 | |||
bc0bf41b91 | |||
535e69dcd0 | |||
2eaf83d89c | |||
6e62917819 | |||
03106eff02 | |||
0c5d71ecd2 | |||
d6a7b7e305 | |||
3d91f2f1e7 | |||
d76c295786 | |||
79422337ae | |||
b0e624ef75 | |||
9d78aabf35 | |||
a3930d7761 | |||
c958113c94 | |||
385c683fe3 | |||
1050337751 | |||
114bf7544a | |||
0199ee9877 | |||
6e02aeee53 | |||
6c3d71c4c9 | |||
78592b245f | |||
80d4422c90 | |||
32df55d636 | |||
eede86e278 | |||
1b855f953f | |||
59df400b0d | |||
4af244e3e2 | |||
ae91f8801f | |||
7f5786d47c | |||
ea12d5b951 | |||
d37468a6ab | |||
d0b3dc2ff8 | |||
85bbc10d06 | |||
2fca73aebd | |||
8b187940ee | |||
00369aa90b | |||
26a10020ac | |||
421463a642 | |||
8d9f248d2f | |||
ed72206a26 | |||
6b7460dd4c | |||
447af740be | |||
3ff6c32ac9 | |||
b752d70109 | |||
a6f83e2d37 | |||
016e223fb8 | |||
502601e684 | |||
29a4bb6803 | |||
cfbe7c83cb | |||
a6d9cb9201 | |||
32cdbd8c54 | |||
1a17b646e4 | |||
cdf79de36b | |||
2aa6be6496 | |||
25c391d244 | |||
a3c2be4e79 | |||
3413e10134 | |||
fa91348428 | |||
d40d3eb96e | |||
16e019be26 | |||
2e77f67683 | |||
9824dc5a44 | |||
1c20e03e0c | |||
98f334c883 | |||
8ac8a780e1 | |||
25e5700084 | |||
28d60a652b | |||
778be03472 | |||
fff8b5c29e | |||
a70d0bd601 | |||
8fc14ac793 | |||
13add8f60b | |||
2c1605c855 | |||
3524676fcc | |||
a577d57263 | |||
58440bb347 | |||
f3808c4251 | |||
95c08e3424 | |||
ce762b3cfa | |||
15bcf4a374 | |||
634aaa0b6a | |||
69fc090f55 | |||
f42041ccb6 | |||
a8787bd315 | |||
b5e77aeef8 | |||
f379685fdd | |||
32ff286691 | |||
38ab682978 | |||
8efe115698 | |||
38f72101eb | |||
f6d03b060c | |||
f450c00ff1 | |||
751f960b82 | |||
9558ded5c4 | |||
8066756605 | |||
ac2507e0ae | |||
205d4ccc41 | |||
7565818d0e | |||
fc093eca3e | |||
61b8f21037 | |||
d988ce8c99 | |||
727d82f268 | |||
c3c89c320b | |||
0b5bb877fb |
@ -3,6 +3,10 @@
|
||||
|
||||
#include "compiled.inc"
|
||||
|
||||
#ifdef _CPostprocess
|
||||
uniform vec4 PPComp17;
|
||||
#endif
|
||||
|
||||
uniform sampler2D tex;
|
||||
uniform vec2 dir;
|
||||
uniform vec2 screenSize;
|
||||
@ -45,6 +49,12 @@ 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(volumAirColor * res, 1.0);
|
||||
fragColor = vec4(AirColor * res, 1.0);
|
||||
}
|
||||
|
@ -19,6 +19,11 @@
|
||||
{
|
||||
"name": "screenSize",
|
||||
"link": "_screenSize"
|
||||
},
|
||||
{
|
||||
"name": "PPComp17",
|
||||
"link": "_PPComp17",
|
||||
"ifdef": ["_CPostprocess"]
|
||||
}
|
||||
],
|
||||
"texture_params": [],
|
||||
|
@ -5,7 +5,7 @@
|
||||
uniform sampler2D tex;
|
||||
|
||||
#ifdef _CPostprocess
|
||||
uniform vec3 PPComp13;
|
||||
uniform vec4 PPComp13;
|
||||
#endif
|
||||
|
||||
in vec2 texCoord;
|
||||
@ -43,13 +43,17 @@ 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 (compoChromaticType == 1) {
|
||||
if (CAType == 1) {
|
||||
float reci_num_iter_f = 1.0 / float(num_iter);
|
||||
|
||||
vec2 resolution = vec2(1,1);
|
||||
@ -64,7 +68,7 @@ void main() {
|
||||
sumcol += w * texture(tex, barrelDistortion(uv, 0.6 * max_distort * t));
|
||||
}
|
||||
|
||||
fragColor = sumcol / sumw;
|
||||
if (on == 1) fragColor = sumcol / sumw; else fragColor = texture(tex, texCoord);
|
||||
}
|
||||
|
||||
// Simple
|
||||
@ -73,6 +77,7 @@ 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;
|
||||
fragColor = vec4(col.x, col.y, col.z, fragColor.w);
|
||||
if (on == 1) fragColor = vec4(col.x, col.y, col.z, fragColor.w);
|
||||
else fragColor = texture(tex, texCoord);
|
||||
}
|
||||
}
|
||||
|
@ -62,8 +62,11 @@ 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
|
||||
@ -106,6 +109,16 @@ 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
|
||||
@ -118,8 +131,8 @@ out vec4 fragColor;
|
||||
// }
|
||||
vec3 applyFog(vec3 rgb, float distance) {
|
||||
// float fogAmount = 1.0 - exp(-distance * compoFogAmountA);
|
||||
float fogAmount = 1.0 - exp(-distance * (compoFogAmountA / 100));
|
||||
return mix(rgb, compoFogColor, fogAmount);
|
||||
float fogAmount = 1.0 - exp(-distance * (FogAmountA / 100));
|
||||
return mix(rgb, FogColor, fogAmount);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -131,7 +144,7 @@ float ConvertEV100ToExposure(float EV100) {
|
||||
return 1/0.8 * exp2(-EV100);
|
||||
}
|
||||
float ComputeEV(float avgLuminance) {
|
||||
const float sqAperture = PPComp1[0].x * PPComp1.x;
|
||||
const float sqAperture = PPComp1.x * PPComp1.x;
|
||||
const float shutterTime = 1.0 / PPComp1.y;
|
||||
const float ISO = PPComp1.z;
|
||||
const float EC = PPComp2.x;
|
||||
@ -349,16 +362,22 @@ void main() {
|
||||
|
||||
#ifdef _CSharpen
|
||||
#ifdef _CPostprocess
|
||||
float strengthSharpen = PPComp14.y;
|
||||
float strengthSharpen = PPComp14.y;
|
||||
vec3 SharpenColor = vec3(PPComp16.x, PPComp16.y, PPComp16.z);
|
||||
float SharpenSize = PPComp16.w;
|
||||
#else
|
||||
float strengthSharpen = compoSharpenStrength;
|
||||
vec3 SharpenColor = compoSharpenColor;
|
||||
float SharpenSize = compoSharpenSize;
|
||||
#endif
|
||||
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 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 colavg = (col1 + col2 + col3 + col4) * 0.25;
|
||||
fragColor.rgb += (fragColor.rgb - colavg) * strengthSharpen;
|
||||
|
||||
float edgeMagnitude = length(fragColor.rgb - colavg);
|
||||
fragColor.rgb = mix(fragColor.rgb, SharpenColor, min(edgeMagnitude * strengthSharpen * 2.0, 1.0));
|
||||
#endif
|
||||
|
||||
#ifdef _CFog
|
||||
@ -407,7 +426,11 @@ void main() {
|
||||
#endif
|
||||
|
||||
#ifdef _CExposure
|
||||
fragColor.rgb += fragColor.rgb * compoExposureStrength;
|
||||
#ifdef _CPostprocess
|
||||
fragColor.rgb+=fragColor.rgb*PPComp8.x;
|
||||
#else
|
||||
fragColor.rgb+= fragColor.rgb*compoExposureStrength;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _CPostprocess
|
||||
@ -415,8 +438,13 @@ 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, autoExposureStrength * 2.0);
|
||||
fragColor.rgb *= pow(expo, AEStrength * 2.0);
|
||||
#endif
|
||||
|
||||
// Clamp color to get rid of INF values that don't work for the tone mapping below
|
||||
@ -480,9 +508,7 @@ 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
|
||||
|
@ -235,6 +235,16 @@
|
||||
"name": "PPComp15",
|
||||
"link": "_PPComp15",
|
||||
"ifdef": ["_CPostprocess"]
|
||||
},
|
||||
{
|
||||
"name": "PPComp16",
|
||||
"link": "_PPComp16",
|
||||
"ifdef": ["_CPostprocess"]
|
||||
},
|
||||
{
|
||||
"name": "PPComp18",
|
||||
"link": "_PPComp18",
|
||||
"ifdef": ["_CPostprocess"]
|
||||
}
|
||||
],
|
||||
"texture_params": [],
|
||||
|
@ -2,13 +2,22 @@
|
||||
|
||||
#include "compiled.inc"
|
||||
|
||||
#ifdef _CPostprocess
|
||||
uniform vec3 PPComp8;
|
||||
#endif
|
||||
|
||||
uniform sampler2D tex;
|
||||
|
||||
in vec2 texCoord;
|
||||
out vec4 fragColor;
|
||||
|
||||
void main() {
|
||||
fragColor.a = 0.01 * autoExposureSpeed;
|
||||
#ifdef _CPostprocess
|
||||
fragColor.a = 0.01 * PPComp8.z;
|
||||
#else
|
||||
fragColor.a = 0.01 * autoExposureSpeed;
|
||||
#endif
|
||||
|
||||
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 +
|
||||
|
@ -8,7 +8,13 @@
|
||||
"blend_source": "source_alpha",
|
||||
"blend_destination": "inverse_source_alpha",
|
||||
"blend_operation": "add",
|
||||
"links": [],
|
||||
"links": [
|
||||
{
|
||||
"name": "PPComp8",
|
||||
"link": "_PPComp8",
|
||||
"ifdef": ["_CPostprocess"]
|
||||
}
|
||||
],
|
||||
"texture_params": [],
|
||||
"vertex_shader": "../include/pass.vert.glsl",
|
||||
"fragment_shader": "histogram_pass.frag.glsl"
|
||||
|
@ -11,6 +11,8 @@ 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;
|
||||
|
@ -11,6 +11,11 @@
|
||||
#include "std/light_common.glsl"
|
||||
#endif
|
||||
|
||||
#ifdef _CPostprocess
|
||||
uniform vec3 PPComp11;
|
||||
uniform vec4 PPComp17;
|
||||
#endif
|
||||
|
||||
uniform sampler2D gbufferD;
|
||||
uniform sampler2D snoise;
|
||||
|
||||
@ -87,7 +92,13 @@ out float fragColor;
|
||||
const float tScat = 0.08;
|
||||
const float tAbs = 0.0;
|
||||
const float tExt = tScat + tAbs;
|
||||
const float stepLen = 1.0 / volumSteps;
|
||||
#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 lighting = 0.4;
|
||||
|
||||
void rayStep(inout vec3 curPos, inout float curOpticalDepth, inout float scatteredLightAmount, float stepLenWorld, vec3 viewVecNorm) {
|
||||
@ -162,5 +173,5 @@ void main() {
|
||||
rayStep(curPos, curOpticalDepth, scatteredLightAmount, stepLenWorld, viewVecNorm);
|
||||
}
|
||||
|
||||
fragColor = scatteredLightAmount * volumAirTurbidity;
|
||||
fragColor = scatteredLightAmount * AirTurbidity;
|
||||
}
|
||||
|
@ -140,6 +140,16 @@
|
||||
"link": "_biasLightWorldViewProjectionMatrixSpot3",
|
||||
"ifndef": ["_ShadowMapAtlas"],
|
||||
"ifdef": ["_Spot", "_ShadowMap"]
|
||||
},
|
||||
{
|
||||
"name": "PPComp11",
|
||||
"link": "_PPComp11",
|
||||
"ifdef": ["_CPostprocess"]
|
||||
},
|
||||
{
|
||||
"name": "PPComp17",
|
||||
"link": "_PPComp17",
|
||||
"ifdef": ["_CPostprocess"]
|
||||
}
|
||||
],
|
||||
"texture_params": [],
|
||||
|
@ -12,6 +12,7 @@ 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;
|
||||
@ -23,6 +24,8 @@ 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;
|
||||
@ -34,13 +37,14 @@ class App {
|
||||
function new(done: Void->Void) {
|
||||
done();
|
||||
kha.System.notifyOnFrames(render);
|
||||
kha.Scheduler.addTimeTask(update, 0, iron.system.Time.delta);
|
||||
kha.Scheduler.addTimeTask(update, 0, iron.system.Time.step);
|
||||
}
|
||||
|
||||
public static function reset() {
|
||||
traitInits = [];
|
||||
traitUpdates = [];
|
||||
traitLateUpdates = [];
|
||||
traitFixedUpdates = [];
|
||||
traitRenders = [];
|
||||
traitRenders2D = [];
|
||||
if (onResets != null) for (f in onResets) f();
|
||||
@ -48,6 +52,8 @@ class App {
|
||||
|
||||
static function update() {
|
||||
if (Scene.active == null || !Scene.active.ready) return;
|
||||
|
||||
iron.system.Time.update();
|
||||
if (pauseUpdates) return;
|
||||
|
||||
#if lnx_debug
|
||||
@ -56,6 +62,14 @@ 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) {
|
||||
@ -106,7 +120,7 @@ class App {
|
||||
var frame = frames[0];
|
||||
framebuffer = frame;
|
||||
|
||||
iron.system.Time.update();
|
||||
iron.system.Time.render();
|
||||
|
||||
if (Scene.active == null || !Scene.active.ready) {
|
||||
render2D(frame);
|
||||
@ -172,6 +186,14 @@ 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);
|
||||
}
|
||||
|
@ -775,6 +775,7 @@ 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
|
||||
|
@ -16,6 +16,7 @@ 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;
|
||||
|
||||
@ -87,6 +88,23 @@ 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.
|
||||
**/
|
||||
|
@ -392,6 +392,8 @@ 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;
|
||||
|
50
leenkx/Sources/iron/format/bmp/Data.hx
Normal file
50
leenkx/Sources/iron/format/bmp/Data.hx
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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
|
||||
}
|
122
leenkx/Sources/iron/format/bmp/Reader.hx
Normal file
122
leenkx/Sources/iron/format/bmp/Reader.hx
Normal file
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* 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
|
||||
}
|
||||
}
|
||||
}
|
256
leenkx/Sources/iron/format/bmp/Tools.hx
Normal file
256
leenkx/Sources/iron/format/bmp/Tools.hx
Normal file
@ -0,0 +1,256 @@
|
||||
/*
|
||||
* 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
|
||||
}
|
||||
}
|
||||
}
|
74
leenkx/Sources/iron/format/bmp/Writer.hx
Normal file
74
leenkx/Sources/iron/format/bmp/Writer.hx
Normal file
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
@ -159,9 +159,17 @@ class Animation {
|
||||
if(markerEvents.get(sampler) != null){
|
||||
for (i in 0...anim.marker_frames.length) {
|
||||
if (frameIndex == anim.marker_frames[i]) {
|
||||
var marketAct = markerEvents.get(sampler);
|
||||
var ar = marketAct.get(anim.marker_names[i]);
|
||||
var markerAct = markerEvents.get(sampler);
|
||||
var ar = markerAct.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;
|
||||
|
@ -21,6 +21,7 @@ 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 screenSize = 0.0;
|
||||
@ -255,11 +256,11 @@ class MeshObject extends Object {
|
||||
particleSystems[i].update(particleChildren[i], this);
|
||||
}
|
||||
}
|
||||
if (particleSystems != null && particleSystems.length > 0 && !raw.render_emitter) return;
|
||||
if (particleSystems != null && particleSystems.length > 0 && !render_emitter) return;
|
||||
if (particleSystems == null && cullMaterial(context)) return;
|
||||
#else
|
||||
if (cullMaterial(context)) return;
|
||||
#end
|
||||
|
||||
if (cullMaterial(context)) return;
|
||||
|
||||
// Get lod
|
||||
var mats = materials;
|
||||
var lod = this;
|
||||
|
@ -172,6 +172,10 @@ 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;
|
||||
|
@ -2,6 +2,7 @@ package iron.object;
|
||||
|
||||
#if lnx_particles
|
||||
|
||||
import kha.FastFloat;
|
||||
import kha.graphics4.Usage;
|
||||
import kha.arrays.Float32Array;
|
||||
import iron.data.Data;
|
||||
@ -16,10 +17,12 @@ 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;
|
||||
@ -46,9 +49,13 @@ 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;
|
||||
|
||||
@ -65,33 +72,61 @@ class ParticleSystem {
|
||||
gy = 0;
|
||||
gz = -9.81 * r.weight_gravity;
|
||||
}
|
||||
alignx = r.object_align_factor[0] / 2;
|
||||
aligny = r.object_align_factor[1] / 2;
|
||||
alignz = r.object_align_factor[2] / 2;
|
||||
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;
|
||||
lifetime = r.lifetime / frameRate;
|
||||
animtime = (r.frame_end - r.frame_start) / frameRate;
|
||||
animtime = r.loop ? looptime : looptime + lifetime;
|
||||
spawnRate = ((r.frame_end - r.frame_start) / r.count) / frameRate;
|
||||
|
||||
for (i in 0...r.count) {
|
||||
var particle = new Particle(i);
|
||||
particle.sr = 1 - Math.random() * r.size_random;
|
||||
particles.push(particle);
|
||||
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() {
|
||||
lifetime = 0;
|
||||
speed = 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);
|
||||
@ -115,17 +150,21 @@ class ParticleSystem {
|
||||
}
|
||||
|
||||
// Animate
|
||||
time += Time.delta * speed;
|
||||
time += Time.renderDelta * speed; // realDelta to renderDelta
|
||||
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 = r.loop ? animtime : -animtime;
|
||||
m._00 = animtime;
|
||||
m._01 = hair ? 1 / particles.length : spawnRate;
|
||||
m._02 = hair ? 1 : lifetime;
|
||||
m._03 = particles.length;
|
||||
@ -133,9 +172,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 * r.mass;
|
||||
m._21 = hair ? 0 : gy * r.mass;
|
||||
m._22 = hair ? 0 : gz * r.mass;
|
||||
m._20 = hair ? 0 : gx;
|
||||
m._21 = hair ? 0 : gy;
|
||||
m._22 = hair ? 0 : gz;
|
||||
m._23 = hair ? 0 : r.lifetime_random;
|
||||
m._30 = tilesx;
|
||||
m._31 = tilesy;
|
||||
@ -144,13 +183,25 @@ 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
|
||||
}
|
||||
|
||||
function setupGeomGpu(object: MeshObject, owner: MeshObject) {
|
||||
var instancedData = new Float32Array(particles.length * 6);
|
||||
var instancedData = new Float32Array(particles.length * 3);
|
||||
var i = 0;
|
||||
|
||||
var normFactor = 1 / 32767; // pa.values are not normalized
|
||||
@ -169,10 +220,6 @@ class ParticleSystem {
|
||||
instancedData.set(i, pa.values[j * pa.size ] * normFactor * scaleFactor.x); i++;
|
||||
instancedData.set(i, pa.values[j * pa.size + 1] * normFactor * scaleFactor.y); i++;
|
||||
instancedData.set(i, pa.values[j * pa.size + 2] * normFactor * scaleFactor.z); i++;
|
||||
|
||||
instancedData.set(i, p.sr); i++;
|
||||
instancedData.set(i, p.sr); i++;
|
||||
instancedData.set(i, p.sr); i++;
|
||||
}
|
||||
|
||||
case 1: // Face
|
||||
@ -196,10 +243,6 @@ class ParticleSystem {
|
||||
instancedData.set(i, pos.x * normFactor * scaleFactor.x); i++;
|
||||
instancedData.set(i, pos.y * normFactor * scaleFactor.y); i++;
|
||||
instancedData.set(i, pos.z * normFactor * scaleFactor.z); i++;
|
||||
|
||||
instancedData.set(i, p.sr); i++;
|
||||
instancedData.set(i, p.sr); i++;
|
||||
instancedData.set(i, p.sr); i++;
|
||||
}
|
||||
|
||||
case 2: // Volume
|
||||
@ -210,13 +253,9 @@ class ParticleSystem {
|
||||
instancedData.set(i, (Math.random() * 2.0 - 1.0) * scaleFactorVolume.x); i++;
|
||||
instancedData.set(i, (Math.random() * 2.0 - 1.0) * scaleFactorVolume.y); i++;
|
||||
instancedData.set(i, (Math.random() * 2.0 - 1.0) * scaleFactorVolume.z); i++;
|
||||
|
||||
instancedData.set(i, p.sr); i++;
|
||||
instancedData.set(i, p.sr); i++;
|
||||
instancedData.set(i, p.sr); i++;
|
||||
}
|
||||
}
|
||||
object.data.geom.setupInstanced(instancedData, 3, Usage.StaticUsage);
|
||||
object.data.geom.setupInstanced(instancedData, 1, Usage.StaticUsage);
|
||||
}
|
||||
|
||||
function fhash(n: Int): Float {
|
||||
@ -255,10 +294,11 @@ class ParticleSystem {
|
||||
|
||||
class Particle {
|
||||
public var i: Int;
|
||||
public var px = 0.0;
|
||||
public var py = 0.0;
|
||||
public var pz = 0.0;
|
||||
public var sr = 1.0; // Size random
|
||||
|
||||
public var x = 0.0;
|
||||
public var y = 0.0;
|
||||
public var z = 0.0;
|
||||
|
||||
public var cameraDistance: Float;
|
||||
|
||||
public function new(i: Int) {
|
||||
|
@ -80,7 +80,7 @@ class Tilesheet {
|
||||
function update() {
|
||||
if (!ready || paused || action.start >= action.end) return;
|
||||
|
||||
time += Time.realDelta;
|
||||
time += Time.renderDelta;
|
||||
|
||||
var frameTime = 1 / raw.framerate;
|
||||
var framesToAdvance = 0;
|
||||
|
@ -1109,6 +1109,26 @@ 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) {
|
||||
|
@ -1,37 +1,58 @@
|
||||
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;
|
||||
}
|
||||
|
||||
public static var scale = 1.0;
|
||||
public static var delta(get, never): Float;
|
||||
static function get_delta(): Float {
|
||||
if (frequency == null) initFrequency();
|
||||
return (1 / frequency) * scale;
|
||||
|
||||
static var _fixedStep: Null<Float>;
|
||||
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 last = 0.0;
|
||||
public static var realDelta = 0.0;
|
||||
static var lastTime = 0.0;
|
||||
static var _delta = 0.0;
|
||||
public static var delta(get, never): Float;
|
||||
static function get_delta(): Float {
|
||||
return _delta;
|
||||
}
|
||||
|
||||
static var lastRenderTime = 0.0;
|
||||
static var _renderDelta = 0.0;
|
||||
public static var renderDelta(get, never): Float;
|
||||
static function get_renderDelta(): Float {
|
||||
return _renderDelta;
|
||||
}
|
||||
|
||||
public static inline function time(): Float {
|
||||
return kha.Scheduler.time();
|
||||
}
|
||||
|
||||
public static inline function realTime(): Float {
|
||||
return kha.Scheduler.realTime();
|
||||
}
|
||||
|
||||
static var frequency: Null<Int> = null;
|
||||
|
||||
static function initFrequency() {
|
||||
frequency = kha.Display.primary != null ? kha.Display.primary.frequency : 60;
|
||||
public static function update() {
|
||||
_delta = realTime() - lastTime;
|
||||
lastTime = realTime();
|
||||
}
|
||||
|
||||
public static function update() {
|
||||
realDelta = realTime() - last;
|
||||
last = realTime();
|
||||
public static function render() {
|
||||
_renderDelta = realTime() - lastRenderTime;
|
||||
lastRenderTime = realTime();
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ 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);
|
||||
@ -47,6 +48,7 @@ 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
|
||||
|
99
leenkx/Sources/leenkx/logicnode/AddParticleToObjectNode.hx
Normal file
99
leenkx/Sources/leenkx/logicnode/AddParticleToObjectNode.hx
Normal file
@ -0,0 +1,99 @@
|
||||
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);
|
||||
}
|
||||
}
|
16
leenkx/Sources/leenkx/logicnode/AutoExposureGetNode.hx
Normal file
16
leenkx/Sources/leenkx/logicnode/AutoExposureGetNode.hx
Normal file
@ -0,0 +1,16 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
15
leenkx/Sources/leenkx/logicnode/AutoExposureSetNode.hx
Normal file
15
leenkx/Sources/leenkx/logicnode/AutoExposureSetNode.hx
Normal file
@ -0,0 +1,15 @@
|
||||
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);
|
||||
}
|
||||
}
|
@ -1,26 +1,49 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
class CameraSetNode extends LogicNode {
|
||||
|
||||
|
||||
public var property0: String;
|
||||
|
||||
public function new(tree:LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from:Int) {
|
||||
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
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ 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;
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ 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);
|
||||
}
|
||||
|
@ -2,6 +2,9 @@ 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;
|
||||
|
||||
@ -27,11 +30,19 @@ 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());
|
||||
rt = kha.Image.createRenderTarget(iron.App.w(), iron.App.h(),
|
||||
kha.graphics4.TextureFormat.RGBA32,
|
||||
kha.graphics4.DepthStencilFormat.NoDepthAndStencil);
|
||||
|
||||
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);
|
||||
|
||||
@ -48,8 +59,20 @@ 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;
|
||||
}
|
||||
|
@ -99,8 +99,6 @@ 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());
|
||||
}
|
||||
}
|
||||
|
59
leenkx/Sources/leenkx/logicnode/DrawSubImageNode.hx
Normal file
59
leenkx/Sources/leenkx/logicnode/DrawSubImageNode.hx
Normal file
@ -0,0 +1,59 @@
|
||||
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);
|
||||
}
|
||||
}
|
@ -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.realDelta);
|
||||
var fps = Math.round(1 / iron.system.Time.renderDelta);
|
||||
if ((fps == Math.POSITIVE_INFINITY) || (fps == Math.NEGATIVE_INFINITY) || (Math.isNaN(fps))) {
|
||||
return 0;
|
||||
}
|
||||
|
72
leenkx/Sources/leenkx/logicnode/GetParticleDataNode.hx
Normal file
72
leenkx/Sources/leenkx/logicnode/GetParticleDataNode.hx
Normal file
@ -0,0 +1,72 @@
|
||||
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;
|
||||
}
|
||||
}
|
38
leenkx/Sources/leenkx/logicnode/GetParticleNode.hx
Normal file
38
leenkx/Sources/leenkx/logicnode/GetParticleNode.hx
Normal file
@ -0,0 +1,38 @@
|
||||
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;
|
||||
}
|
||||
}
|
@ -1,26 +1,12 @@
|
||||
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 {
|
||||
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;
|
||||
}
|
||||
return iron.Scene.active.raw.world_ref;
|
||||
}
|
||||
}
|
||||
}
|
26
leenkx/Sources/leenkx/logicnode/GetWorldOrientationNode.hx
Normal file
26
leenkx/Sources/leenkx/logicnode/GetWorldOrientationNode.hx
Normal file
@ -0,0 +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 {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
@ -18,7 +18,6 @@ class ProbabilisticOutputNode extends LogicNode {
|
||||
}
|
||||
|
||||
if (sum > 1){
|
||||
trace(sum);
|
||||
for (p in 0...probs.length)
|
||||
probs[p] /= sum;
|
||||
}
|
||||
|
@ -0,0 +1,64 @@
|
||||
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);
|
||||
}
|
||||
}
|
16
leenkx/Sources/leenkx/logicnode/ResolutionGetNode.hx
Normal file
16
leenkx/Sources/leenkx/logicnode/ResolutionGetNode.hx
Normal file
@ -0,0 +1,16 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
33
leenkx/Sources/leenkx/logicnode/ResolutionSetNode.hx
Normal file
33
leenkx/Sources/leenkx/logicnode/ResolutionSetNode.hx
Normal file
@ -0,0 +1,33 @@
|
||||
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);
|
||||
}
|
||||
}
|
@ -20,6 +20,8 @@ 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":
|
||||
|
@ -0,0 +1,55 @@
|
||||
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);
|
||||
}
|
||||
}
|
81
leenkx/Sources/leenkx/logicnode/SetParticleDataNode.hx
Normal file
81
leenkx/Sources/leenkx/logicnode/SetParticleDataNode.hx
Normal file
@ -0,0 +1,81 @@
|
||||
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':
|
||||
psys.r.factor_random = inputs[3].get();
|
||||
case 'Weight Gravity':
|
||||
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);
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
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);
|
||||
}
|
||||
}
|
@ -11,13 +11,16 @@ class SetParticleSpeedNode extends LogicNode {
|
||||
override function run(from: Int) {
|
||||
#if lnx_particles
|
||||
var object: Object = inputs[1].get();
|
||||
var speed: Float = inputs[2].get();
|
||||
var slot: Int = inputs[2].get();
|
||||
var speed: Float = inputs[3].get();
|
||||
|
||||
if (object == null) return;
|
||||
|
||||
var mo = cast(object, iron.object.MeshObject);
|
||||
var psys = mo.particleSystems.length > 0 ? mo.particleSystems[0] : null;
|
||||
if (psys == null) mo.particleOwner.particleSystems[0];
|
||||
var psys = mo.particleSystems != null ? mo.particleSystems[slot] :
|
||||
mo.particleOwner != null && mo.particleOwner.particleSystems != null ? mo.particleOwner.particleSystems[slot] : null;
|
||||
|
||||
if (psys == null) return;
|
||||
|
||||
psys.speed = speed;
|
||||
|
||||
|
40
leenkx/Sources/leenkx/logicnode/SetWorldNode.hx
Normal file
40
leenkx/Sources/leenkx/logicnode/SetWorldNode.hx
Normal file
@ -0,0 +1,40 @@
|
||||
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);
|
||||
}
|
||||
}
|
17
leenkx/Sources/leenkx/logicnode/SharpenGetNode.hx
Normal file
17
leenkx/Sources/leenkx/logicnode/SharpenGetNode.hx
Normal file
@ -0,0 +1,17 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
18
leenkx/Sources/leenkx/logicnode/SharpenSetNode.hx
Normal file
18
leenkx/Sources/leenkx/logicnode/SharpenSetNode.hx
Normal file
@ -0,0 +1,18 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
class SharpenSetNode extends LogicNode {
|
||||
|
||||
public function new(tree:LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from:Int) {
|
||||
leenkx.renderpath.Postprocess.sharpen_uniforms[0][0] = inputs[1].get().x;
|
||||
leenkx.renderpath.Postprocess.sharpen_uniforms[0][1] = inputs[1].get().y;
|
||||
leenkx.renderpath.Postprocess.sharpen_uniforms[0][2] = inputs[1].get().z;
|
||||
leenkx.renderpath.Postprocess.sharpen_uniforms[1][0] = inputs[2].get();
|
||||
leenkx.renderpath.Postprocess.camera_uniforms[12] = inputs[3].get();
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
17
leenkx/Sources/leenkx/logicnode/VolumetricFogGetNode.hx
Normal file
17
leenkx/Sources/leenkx/logicnode/VolumetricFogGetNode.hx
Normal file
@ -0,0 +1,17 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
class VolumetricFogGetNode extends LogicNode {
|
||||
|
||||
public function new(tree:LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function get(from:Int):Dynamic {
|
||||
return switch (from) {
|
||||
case 0: leenkx.renderpath.Postprocess.volumetric_fog_uniforms[0];
|
||||
case 1: leenkx.renderpath.Postprocess.volumetric_fog_uniforms[1][0];
|
||||
case 2: leenkx.renderpath.Postprocess.volumetric_fog_uniforms[2][0];
|
||||
default: 0.0;
|
||||
}
|
||||
}
|
||||
}
|
18
leenkx/Sources/leenkx/logicnode/VolumetricFogSetNode.hx
Normal file
18
leenkx/Sources/leenkx/logicnode/VolumetricFogSetNode.hx
Normal file
@ -0,0 +1,18 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
class VolumetricFogSetNode extends LogicNode {
|
||||
|
||||
public function new(tree:LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from:Int) {
|
||||
leenkx.renderpath.Postprocess.volumetric_fog_uniforms[0][0] = inputs[1].get().x;
|
||||
leenkx.renderpath.Postprocess.volumetric_fog_uniforms[0][1] = inputs[1].get().y;
|
||||
leenkx.renderpath.Postprocess.volumetric_fog_uniforms[0][2] = inputs[1].get().z;
|
||||
leenkx.renderpath.Postprocess.volumetric_fog_uniforms[1][0] = inputs[2].get();
|
||||
leenkx.renderpath.Postprocess.volumetric_fog_uniforms[2][0] = inputs[3].get();
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
17
leenkx/Sources/leenkx/logicnode/VolumetricLightGetNode.hx
Normal file
17
leenkx/Sources/leenkx/logicnode/VolumetricLightGetNode.hx
Normal file
@ -0,0 +1,17 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
class VolumetricLightGetNode extends LogicNode {
|
||||
|
||||
public function new(tree:LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function get(from:Int):Dynamic {
|
||||
return switch (from) {
|
||||
case 0: leenkx.renderpath.Postprocess.volumetric_light_uniforms[0];
|
||||
case 1: leenkx.renderpath.Postprocess.volumetric_light_uniforms[1][0];
|
||||
case 2: leenkx.renderpath.Postprocess.volumetric_light_uniforms[2][0];
|
||||
default: 0.0;
|
||||
}
|
||||
}
|
||||
}
|
18
leenkx/Sources/leenkx/logicnode/VolumetricLightSetNode.hx
Normal file
18
leenkx/Sources/leenkx/logicnode/VolumetricLightSetNode.hx
Normal file
@ -0,0 +1,18 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
class VolumetricLightSetNode extends LogicNode {
|
||||
|
||||
public function new(tree:LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from:Int) {
|
||||
leenkx.renderpath.Postprocess.volumetric_light_uniforms[0][0] = inputs[1].get().x;
|
||||
leenkx.renderpath.Postprocess.volumetric_light_uniforms[0][1] = inputs[1].get().y;
|
||||
leenkx.renderpath.Postprocess.volumetric_light_uniforms[0][2] = inputs[1].get().z;
|
||||
leenkx.renderpath.Postprocess.volumetric_light_uniforms[1][0] = inputs[2].get();
|
||||
leenkx.renderpath.Postprocess.volumetric_light_uniforms[2][0] = inputs[3].get();
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
105
leenkx/Sources/leenkx/logicnode/WriteImageNode.hx
Normal file
105
leenkx/Sources/leenkx/logicnode/WriteImageNode.hx
Normal file
@ -0,0 +1,105 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
import iron.object.CameraObject;
|
||||
|
||||
class WriteImageNode extends LogicNode {
|
||||
|
||||
var file: String;
|
||||
var camera: CameraObject;
|
||||
var renderTarget: kha.Image;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
// Relative or absolute path to file
|
||||
file = inputs[1].get();
|
||||
|
||||
assert(Error, iron.App.w() % inputs[3].get() == 0 && iron.App.h() % inputs[4].get() == 0, "Aspect ratio must match display resolution ratio");
|
||||
|
||||
camera = inputs[2].get();
|
||||
renderTarget = kha.Image.createRenderTarget(inputs[3].get(), inputs[4].get(),
|
||||
kha.graphics4.TextureFormat.RGBA32,
|
||||
kha.graphics4.DepthStencilFormat.NoDepthAndStencil);
|
||||
|
||||
tree.notifyOnRender(render);
|
||||
|
||||
}
|
||||
|
||||
function render(g: kha.graphics4.Graphics) {
|
||||
|
||||
var ready = false;
|
||||
final sceneCam = iron.Scene.active.camera;
|
||||
final oldRT = camera.renderTarget;
|
||||
|
||||
iron.Scene.active.camera = camera;
|
||||
camera.renderTarget = renderTarget;
|
||||
|
||||
camera.renderFrame(g);
|
||||
|
||||
var tex = camera.renderTarget;
|
||||
|
||||
camera.renderTarget = oldRT;
|
||||
iron.Scene.active.camera = sceneCam;
|
||||
|
||||
var pixels = tex.getPixels();
|
||||
|
||||
for (i in 0...pixels.length){
|
||||
if (pixels.get(i) != 0){ ready = true; break; }
|
||||
}
|
||||
|
||||
//wait for getPixels ready
|
||||
if (ready) {
|
||||
|
||||
var tx = inputs[5].get();
|
||||
var ty = inputs[6].get();
|
||||
var tw = inputs[7].get();
|
||||
var th = inputs[8].get();
|
||||
|
||||
var bo = new haxe.io.BytesOutput();
|
||||
var rgb = haxe.io.Bytes.alloc(tw * th * 4);
|
||||
for (j in ty...ty + th) {
|
||||
for (i in tx...tx + tw) {
|
||||
var k = j * tex.width + i;
|
||||
var m = (j - ty) * tw + i - tx;
|
||||
|
||||
#if kha_krom
|
||||
var l = k;
|
||||
#elseif kha_html5
|
||||
var l = (tex.height - j) * tex.width + i;
|
||||
#end
|
||||
|
||||
//ARGB 0xff
|
||||
rgb.set(m * 4 + 0, pixels.get(l * 4 + 3));
|
||||
rgb.set(m * 4 + 1, pixels.get(l * 4 + 0));
|
||||
rgb.set(m * 4 + 2, pixels.get(l * 4 + 1));
|
||||
rgb.set(m * 4 + 3, pixels.get(l * 4 + 2));
|
||||
}
|
||||
}
|
||||
|
||||
var imgwriter = new iron.format.bmp.Writer(bo);
|
||||
imgwriter.write(iron.format.bmp.Tools.buildFromARGB(tw, th, rgb));
|
||||
|
||||
#if kha_krom
|
||||
Krom.fileSaveBytes(Krom.getFilesLocation() + "/" + file, bo.getBytes().getData());
|
||||
|
||||
#elseif kha_html5
|
||||
var blob = new js.html.Blob([bo.getBytes().getData()], {type: "application"});
|
||||
var url = js.html.URL.createObjectURL(blob);
|
||||
var a = cast(js.Browser.document.createElement("a"), js.html.AnchorElement);
|
||||
a.href = url;
|
||||
a.download = file;
|
||||
a.click();
|
||||
js.html.URL.revokeObjectURL(url);
|
||||
#end
|
||||
|
||||
runOutput(0);
|
||||
|
||||
tree.removeRender(render);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -529,22 +529,29 @@ class Inc {
|
||||
public static function applyConfig() {
|
||||
#if lnx_config
|
||||
var config = leenkx.data.Config.raw;
|
||||
|
||||
#if rp_chromatic_aberration
|
||||
Postprocess.chromatic_aberration_uniforms[3] = config.rp_chromatic_aberration == true ? 1 : 0;
|
||||
#end
|
||||
|
||||
// Resize shadow map
|
||||
var l = path.light;
|
||||
if (l.data.raw.type == "sun" && l.data.raw.shadowmap_size != config.rp_shadowmap_cascade) {
|
||||
l.data.raw.shadowmap_size = config.rp_shadowmap_cascade;
|
||||
var rt = path.renderTargets.get("shadowMap");
|
||||
if (rt != null) {
|
||||
rt.unload();
|
||||
path.renderTargets.remove("shadowMap");
|
||||
if (l != null){
|
||||
if (l.data.raw.type == "sun" && l.data.raw.shadowmap_size != config.rp_shadowmap_cascade) {
|
||||
l.data.raw.shadowmap_size = config.rp_shadowmap_cascade;
|
||||
var rt = path.renderTargets.get("shadowMap");
|
||||
if (rt != null) {
|
||||
rt.unload();
|
||||
path.renderTargets.remove("shadowMap");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (l.data.raw.shadowmap_size != config.rp_shadowmap_cube) {
|
||||
l.data.raw.shadowmap_size = config.rp_shadowmap_cube;
|
||||
var rt = path.renderTargets.get("shadowMapCube");
|
||||
if (rt != null) {
|
||||
rt.unload();
|
||||
path.renderTargets.remove("shadowMapCube");
|
||||
else if (l.data.raw.shadowmap_size != config.rp_shadowmap_cube) {
|
||||
l.data.raw.shadowmap_size = config.rp_shadowmap_cube;
|
||||
var rt = path.renderTargets.get("shadowMapCube");
|
||||
if (rt != null) {
|
||||
rt.unload();
|
||||
path.renderTargets.remove("shadowMapCube");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (superSample != config.rp_supersample) {
|
||||
@ -778,7 +785,11 @@ class Inc {
|
||||
|
||||
public static inline function getDisplayp(): Null<Int> {
|
||||
#if rp_resolution_filter // Custom resolution set
|
||||
#if rp_pp
|
||||
return leenkx.renderpath.Postprocess.resolution_uniforms[0];
|
||||
#else
|
||||
return Main.resolutionSize;
|
||||
#end
|
||||
#else
|
||||
return null;
|
||||
#end
|
||||
|
@ -49,15 +49,20 @@ class Postprocess {
|
||||
0.01, //4: Fisheye Distortion
|
||||
1, //5: DoF AutoFocus §§ If true, it ignores the DoF Distance setting
|
||||
10.0, //6: DoF Distance
|
||||
160.0, //7: DoF Focal Length mm
|
||||
50.0, //7: DoF Focal Length mm
|
||||
128, //8: DoF F-Stop
|
||||
0, //9: Tonemapping Method
|
||||
2.0, //10: Distort
|
||||
2.0, //11: Film Grain
|
||||
0.25, //12: Sharpen
|
||||
0.25, //12: Sharpen Strength
|
||||
0.7 //13: Vignette
|
||||
];
|
||||
|
||||
public static var sharpen_uniforms = [
|
||||
[0.0, 0.0, 0.0], //0: Sharpen Color
|
||||
[2.5] //1: Sharpen Size
|
||||
];
|
||||
|
||||
public static var tonemapper_uniforms = [
|
||||
1.0, //0: Slope
|
||||
1.0, //1: Toe
|
||||
@ -102,7 +107,35 @@ class Postprocess {
|
||||
|
||||
public static var chromatic_aberration_uniforms = [
|
||||
2.0, //0: Strength
|
||||
32 //1: Samples
|
||||
32, //1: Samples
|
||||
0, //2: Type
|
||||
1 //3: On/Off
|
||||
];
|
||||
|
||||
public static var exposure_uniforms = [
|
||||
1 //0: Exposure
|
||||
];
|
||||
|
||||
public static var auto_exposure_uniforms = [
|
||||
1, //0: Auto Exposure Strength
|
||||
1 //1: Auto Exposure Speed
|
||||
];
|
||||
|
||||
public static var volumetric_light_uniforms = [
|
||||
[1.0, 1.0, 1.0], //0: Volumetric Light Air Color
|
||||
[1.0], //1: Volumetric Light Air Turbidity
|
||||
[20.0] //2: Volumetric Light Steps
|
||||
];
|
||||
|
||||
public static var volumetric_fog_uniforms = [
|
||||
[0.5, 0.6, 0.7], //0: Volumetric Fog Color
|
||||
[0.25], //1: Volumetric Fog Amount A
|
||||
[50.0] //2: Volumetric Fog Amount B
|
||||
];
|
||||
|
||||
public static var resolution_uniforms = [
|
||||
720, //0: Size
|
||||
0 //1: Filter
|
||||
];
|
||||
|
||||
public static function vec3Link(object: Object, mat: MaterialData, link: String): iron.math.Vec4 {
|
||||
@ -284,6 +317,11 @@ class Postprocess {
|
||||
v.x = lenstexture_uniforms[2]; //Lum min
|
||||
v.y = lenstexture_uniforms[3]; //Lum max
|
||||
v.z = lenstexture_uniforms[4]; //Expo
|
||||
case "_PPComp8":
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = exposure_uniforms[0]; //Exposure
|
||||
v.y = auto_exposure_uniforms[0]; //Auto Exposure Strength
|
||||
v.z = auto_exposure_uniforms[1]; //Auto Exposure Speed
|
||||
case "_PPComp9":
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = ssr_uniforms[0]; //Step
|
||||
@ -297,8 +335,8 @@ class Postprocess {
|
||||
case "_PPComp11":
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = bloom_uniforms[2]; // Bloom Strength
|
||||
v.y = 0; // Unused
|
||||
v.z = 0; // Unused
|
||||
v.y = volumetric_light_uniforms[2][0]; //Volumetric Light Steps
|
||||
v.z = volumetric_fog_uniforms[2][0]; //Volumetric Fog Amount B
|
||||
case "_PPComp12":
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = ssao_uniforms[0]; //SSAO Strength
|
||||
@ -308,7 +346,8 @@ class Postprocess {
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = chromatic_aberration_uniforms[0]; //CA Strength
|
||||
v.y = chromatic_aberration_uniforms[1]; //CA Samples
|
||||
v.z = 0;
|
||||
v.z = chromatic_aberration_uniforms[2]; //CA Type
|
||||
v.w = chromatic_aberration_uniforms[3]; //On/Off
|
||||
case "_PPComp14":
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = camera_uniforms[10]; //Distort
|
||||
@ -338,6 +377,24 @@ class Postprocess {
|
||||
v.y = letterbox_uniforms[0][1];
|
||||
v.z = letterbox_uniforms[0][2];
|
||||
v.w = letterbox_uniforms[1][0]; //Size
|
||||
case "_PPComp16":
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = sharpen_uniforms[0][0]; //Color
|
||||
v.y = sharpen_uniforms[0][1];
|
||||
v.z = sharpen_uniforms[0][2];
|
||||
v.w = sharpen_uniforms[1][0]; //Size
|
||||
case "_PPComp17":
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = volumetric_light_uniforms[0][0]; //Air Color
|
||||
v.y = volumetric_light_uniforms[0][1];
|
||||
v.z = volumetric_light_uniforms[0][2];
|
||||
v.w = volumetric_light_uniforms[1][0]; //Air Turbidity
|
||||
case "_PPComp18":
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = volumetric_fog_uniforms[0][0]; //Color
|
||||
v.y = volumetric_fog_uniforms[0][1];
|
||||
v.z = volumetric_fog_uniforms[0][2];
|
||||
v.w = volumetric_fog_uniforms[1][0]; //Amount A
|
||||
}
|
||||
|
||||
return v;
|
||||
|
@ -45,7 +45,7 @@ class DebugDrawHelper {
|
||||
|
||||
iron.App.notifyOnRender2D(onRender);
|
||||
if (debugDrawMode & DrawRayCast != 0) {
|
||||
iron.App.notifyOnUpdate(function () {
|
||||
iron.App.notifyOnFixedUpdate(function () {
|
||||
rayCasts.resize(0);
|
||||
});
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ class PhysicsWorld extends Trait {
|
||||
|
||||
|
||||
|
||||
public function new(timeScale = 1.0, maxSteps = 10, solverIterations = 10, debugDrawMode: DebugDrawMode = NoDebug) {
|
||||
public function new(timeScale = 1.0, maxSteps = 10, solverIterations = 10, fixedStep = 1 / 60, debugDrawMode: DebugDrawMode = NoDebug) {
|
||||
super();
|
||||
|
||||
if (nullvec) {
|
||||
@ -120,6 +120,7 @@ class PhysicsWorld extends Trait {
|
||||
this.timeScale = timeScale;
|
||||
this.maxSteps = maxSteps;
|
||||
this.solverIterations = solverIterations;
|
||||
Time.initFixedStep(fixedStep);
|
||||
|
||||
// First scene
|
||||
if (active == null) {
|
||||
@ -136,10 +137,10 @@ class PhysicsWorld extends Trait {
|
||||
conMap = new Map();
|
||||
active = this;
|
||||
|
||||
// Ensure physics are updated first in the lateUpdate list
|
||||
_lateUpdate = [lateUpdate];
|
||||
@:privateAccess iron.App.traitLateUpdates.insert(0, lateUpdate);
|
||||
|
||||
// Ensure physics are updated first in the fixedUpdate list
|
||||
_fixedUpdate = [fixedUpdate];
|
||||
@:privateAccess iron.App.traitFixedUpdates.insert(0, fixedUpdate);
|
||||
|
||||
setDebugDrawMode(debugDrawMode);
|
||||
|
||||
iron.Scene.active.notifyOnRemove(function() {
|
||||
@ -298,8 +299,8 @@ class PhysicsWorld extends Trait {
|
||||
return rb;
|
||||
}
|
||||
|
||||
function lateUpdate() {
|
||||
var t = Time.delta * timeScale;
|
||||
function fixedUpdate() {
|
||||
var t = Time.fixedStep * timeScale * Time.scale;
|
||||
if (t == 0.0) return; // Simulation paused
|
||||
|
||||
#if lnx_debug
|
||||
@ -308,13 +309,10 @@ class PhysicsWorld extends Trait {
|
||||
|
||||
if (preUpdates != null) for (f in preUpdates) f();
|
||||
|
||||
//Bullet physics fixed timescale
|
||||
var fixedTime = 1.0 / 60;
|
||||
|
||||
//This condition must be satisfied to not loose time
|
||||
var currMaxSteps = t < (fixedTime * maxSteps) ? maxSteps : 1;
|
||||
var currMaxSteps = t < (Time.fixedStep * maxSteps) ? maxSteps : 1;
|
||||
|
||||
world.stepSimulation(t, currMaxSteps, fixedTime);
|
||||
world.stepSimulation(t, currMaxSteps, Time.fixedStep);
|
||||
updateContacts();
|
||||
|
||||
for (rb in rbMap) @:privateAccess rb.physicsUpdate();
|
||||
@ -436,8 +434,8 @@ class PhysicsWorld extends Trait {
|
||||
from: from,
|
||||
to: to,
|
||||
hasHit: rc.hasHit(),
|
||||
hitPoint: hitPointWorld,
|
||||
hitNormal: hitNormalWorld
|
||||
hitPoint: hitPointWorld.clone(),
|
||||
hitNormal: hitNormalWorld.clone()
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -2,11 +2,13 @@ package leenkx.trait.physics.bullet;
|
||||
|
||||
#if lnx_bullet
|
||||
|
||||
import leenkx.math.Helper;
|
||||
import iron.data.MeshData;
|
||||
import iron.math.Vec4;
|
||||
import iron.math.Quat;
|
||||
import iron.object.Transform;
|
||||
import iron.object.MeshObject;
|
||||
import iron.data.MeshData;
|
||||
import iron.system.Time;
|
||||
|
||||
/**
|
||||
RigidBody is used to allow objects to interact with Physics in your game including collisions and gravity.
|
||||
@ -76,6 +78,14 @@ class RigidBody extends iron.Trait {
|
||||
static var triangleMeshCache = new Map<MeshData, bullet.Bt.TriangleMesh>();
|
||||
static var usersCache = new Map<MeshData, Int>();
|
||||
|
||||
// Interpolation
|
||||
var interpolate: Bool = false;
|
||||
var time: Float = 0.0;
|
||||
var currentPos: bullet.Bt.Vector3 = new bullet.Bt.Vector3(0, 0, 0);
|
||||
var prevPos: bullet.Bt.Vector3 = new bullet.Bt.Vector3(0, 0, 0);
|
||||
var currentRot: bullet.Bt.Quaternion = new bullet.Bt.Quaternion(0, 0, 0, 1);
|
||||
var prevRot: bullet.Bt.Quaternion = new bullet.Bt.Quaternion(0, 0, 0, 1);
|
||||
|
||||
public function new(shape = Shape.Box, mass = 1.0, friction = 0.5, restitution = 0.0, group = 1, mask = 1,
|
||||
params: RigidBodyParams = null, flags: RigidBodyFlags = null) {
|
||||
super();
|
||||
@ -85,7 +95,7 @@ class RigidBody extends iron.Trait {
|
||||
vec1 = new bullet.Bt.Vector3(0, 0, 0);
|
||||
vec2 = new bullet.Bt.Vector3(0, 0, 0);
|
||||
vec3 = new bullet.Bt.Vector3(0, 0, 0);
|
||||
quat1 = new bullet.Bt.Quaternion(0, 0, 0, 0);
|
||||
quat1 = new bullet.Bt.Quaternion(0, 0, 0, 1);
|
||||
trans1 = new bullet.Bt.Transform();
|
||||
trans2 = new bullet.Bt.Transform();
|
||||
}
|
||||
@ -117,6 +127,7 @@ class RigidBody extends iron.Trait {
|
||||
animated: false,
|
||||
trigger: false,
|
||||
ccd: false,
|
||||
interpolate: false,
|
||||
staticObj: false,
|
||||
useDeactivation: true
|
||||
};
|
||||
@ -131,6 +142,7 @@ class RigidBody extends iron.Trait {
|
||||
this.animated = flags.animated;
|
||||
this.trigger = flags.trigger;
|
||||
this.ccd = flags.ccd;
|
||||
this.interpolate = flags.interpolate;
|
||||
this.staticObj = flags.staticObj;
|
||||
this.useDeactivation = flags.useDeactivation;
|
||||
|
||||
@ -153,6 +165,7 @@ class RigidBody extends iron.Trait {
|
||||
if (!Std.isOfType(object, MeshObject)) return; // No mesh data
|
||||
|
||||
transform = object.transform;
|
||||
transform.buildMatrix();
|
||||
physics = leenkx.trait.physics.PhysicsWorld.active;
|
||||
|
||||
if (shape == Shape.Box) {
|
||||
@ -244,6 +257,9 @@ class RigidBody extends iron.Trait {
|
||||
quat1.setValue(quat.x, quat.y, quat.z, quat.w);
|
||||
trans1.setRotation(quat1);
|
||||
|
||||
currentPos.setValue(vec1.x(), vec1.y(), vec1.z());
|
||||
currentRot.setValue(quat.x, quat.y, quat.z, quat.w);
|
||||
|
||||
var centerOfMassOffset = trans2;
|
||||
centerOfMassOffset.setIdentity();
|
||||
motionState = new bullet.Bt.DefaultMotionState(trans1, centerOfMassOffset);
|
||||
@ -307,7 +323,8 @@ class RigidBody extends iron.Trait {
|
||||
|
||||
physics.addRigidBody(this);
|
||||
notifyOnRemove(removeFromWorld);
|
||||
|
||||
if (!animated) notifyOnUpdate(update);
|
||||
|
||||
if (onReady != null) onReady();
|
||||
|
||||
#if js
|
||||
@ -317,26 +334,71 @@ class RigidBody extends iron.Trait {
|
||||
#end
|
||||
}
|
||||
|
||||
|
||||
function update() {
|
||||
if (interpolate) {
|
||||
time += Time.delta;
|
||||
|
||||
while (time >= Time.fixedStep) {
|
||||
time -= Time.fixedStep;
|
||||
}
|
||||
|
||||
var t: Float = time / Time.fixedStep;
|
||||
t = Helper.clamp(t, 0, 1);
|
||||
|
||||
var tx: Float = prevPos.x() * (1.0 - t) + currentPos.x() * t;
|
||||
var ty: Float = prevPos.y() * (1.0 - t) + currentPos.y() * t;
|
||||
var tz: Float = prevPos.z() * (1.0 - t) + currentPos.z() * t;
|
||||
|
||||
var tRot: bullet.Bt.Quaternion = nlerp(prevRot, currentRot, t);
|
||||
|
||||
transform.loc.set(tx, ty, tz, 1.0);
|
||||
transform.rot.set(tRot.x(), tRot.y(), tRot.z(), tRot.w());
|
||||
} else {
|
||||
transform.loc.set(currentPos.x(), currentPos.y(), currentPos.z(), 1.0);
|
||||
transform.rot.set(currentRot.x(), currentRot.y(), currentRot.z(), currentRot.w());
|
||||
}
|
||||
|
||||
if (object.parent != null) {
|
||||
var ptransform = object.parent.transform;
|
||||
transform.loc.x -= ptransform.worldx();
|
||||
transform.loc.y -= ptransform.worldy();
|
||||
transform.loc.z -= ptransform.worldz();
|
||||
}
|
||||
|
||||
transform.buildMatrix();
|
||||
}
|
||||
|
||||
function nlerp(q1: bullet.Bt.Quaternion, q2: bullet.Bt.Quaternion, t: Float): bullet.Bt.Quaternion {
|
||||
var dot = q1.x() * q2.x() + q1.y() * q2.y() + q1.z() * q2.z() + q1.w() * q2.w();
|
||||
var _q2 = dot < 0 ? new bullet.Bt.Quaternion(-q2.x(), -q2.y(), -q2.z(), -q2.w()) : q2;
|
||||
|
||||
var x = q1.x() * (1.0 - t) + _q2.x() * t;
|
||||
var y = q1.y() * (1.0 - t) + _q2.y() * t;
|
||||
var z = q1.z() * (1.0 - t) + _q2.z() * t;
|
||||
var w = q1.w() * (1.0 - t) + _q2.w() * t;
|
||||
|
||||
var len = Math.sqrt(x * x + y * y + z * z + w * w);
|
||||
return new bullet.Bt.Quaternion(x / len, y / len, z / len, w / len);
|
||||
}
|
||||
|
||||
function physicsUpdate() {
|
||||
if (!ready) return;
|
||||
if (animated) {
|
||||
syncTransform();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (interpolate) {
|
||||
prevPos.setValue(currentPos.x(), currentPos.y(), currentPos.z());
|
||||
prevRot.setValue(currentRot.x(), currentRot.y(), currentRot.z(), currentRot.w());
|
||||
}
|
||||
var trans = body.getWorldTransform();
|
||||
var p = trans.getOrigin();
|
||||
var q = trans.getRotation();
|
||||
|
||||
transform.loc.set(p.x(), p.y(), p.z());
|
||||
transform.rot.set(q.x(), q.y(), q.z(), q.w());
|
||||
if (object.parent != null) {
|
||||
var ptransform = object.parent.transform;
|
||||
transform.loc.x -= ptransform.worldx();
|
||||
transform.loc.y -= ptransform.worldy();
|
||||
transform.loc.z -= ptransform.worldz();
|
||||
}
|
||||
transform.clearDelta();
|
||||
transform.buildMatrix();
|
||||
// transform.buildMatrix();
|
||||
currentPos.setValue(p.x(), p.y(), p.z());
|
||||
currentRot.setValue(q.x(), q.y(), q.z(), q.w());
|
||||
|
||||
|
||||
#if hl
|
||||
p.delete();
|
||||
@ -689,6 +751,7 @@ typedef RigidBodyFlags = {
|
||||
var animated: Bool;
|
||||
var trigger: Bool;
|
||||
var ccd: Bool;
|
||||
var interpolate: Bool;
|
||||
var staticObj: Bool;
|
||||
var useDeactivation: Bool;
|
||||
}
|
||||
|
@ -540,7 +540,7 @@ class LeenkxExporter:
|
||||
o['material_refs'].append(lnx.utils.asset_name(material))
|
||||
|
||||
def export_particle_system_ref(self, psys: bpy.types.ParticleSystem, out_object):
|
||||
if psys.settings.instance_object is None or psys.settings.render_type != 'OBJECT' or not psys.settings.instance_object.lnx_export:
|
||||
if psys.settings.instance_object is None or psys.settings.render_type != 'OBJECT' or not psys.settings.instance_object.lnx_export or not bpy.data.objects[out_object['name']].modifiers[psys.name].show_render:
|
||||
return
|
||||
|
||||
self.particle_system_array[psys.settings] = {"structName": psys.settings.name}
|
||||
@ -910,7 +910,8 @@ class LeenkxExporter:
|
||||
out_object['particle_refs'] = []
|
||||
out_object['render_emitter'] = bobject.show_instancer_for_render
|
||||
for i in range(num_psys):
|
||||
self.export_particle_system_ref(bobject.particle_systems[i], out_object)
|
||||
if bobject.modifiers[bobject.particle_systems[i].name].show_render:
|
||||
self.export_particle_system_ref(bobject.particle_systems[i], out_object)
|
||||
|
||||
aabb = bobject.data.lnx_aabb
|
||||
if aabb[0] == 0 and aabb[1] == 0 and aabb[2] == 0:
|
||||
@ -2280,6 +2281,15 @@ class LeenkxExporter:
|
||||
if len(self.particle_system_array) > 0:
|
||||
self.output['particle_datas'] = []
|
||||
for particleRef in self.particle_system_array.items():
|
||||
padd = False;
|
||||
for obj in self.output['objects']:
|
||||
if 'particle_refs' in obj:
|
||||
for pref in obj['particle_refs']:
|
||||
if pref['particle'] == particleRef[1]["structName"]:
|
||||
if bpy.data.objects[obj['name']].modifiers[pref['name']].show_render == True:
|
||||
padd = True;
|
||||
if not padd:
|
||||
continue;
|
||||
psettings = particleRef[0]
|
||||
|
||||
if psettings is None:
|
||||
@ -2297,6 +2307,8 @@ class LeenkxExporter:
|
||||
out_particlesys = {
|
||||
'name': particleRef[1]["structName"],
|
||||
'type': 0 if psettings.type == 'EMITTER' else 1, # HAIR
|
||||
'auto_start': psettings.lnx_auto_start,
|
||||
'is_unique': psettings.lnx_is_unique,
|
||||
'loop': psettings.lnx_loop,
|
||||
# Emission
|
||||
'count': int(psettings.count * psettings.lnx_count_mult),
|
||||
@ -2813,6 +2825,7 @@ class LeenkxExporter:
|
||||
body_flags['animated'] = rb.kinematic
|
||||
body_flags['trigger'] = bobject.lnx_rb_trigger
|
||||
body_flags['ccd'] = bobject.lnx_rb_ccd
|
||||
body_flags['interpolate'] = bobject.lnx_rb_interpolate
|
||||
body_flags['staticObj'] = is_static
|
||||
body_flags['useDeactivation'] = rb.use_deactivation
|
||||
x['parameters'].append(lnx.utils.get_haxe_json_string(body_params))
|
||||
@ -3037,7 +3050,7 @@ class LeenkxExporter:
|
||||
|
||||
rbw = self.scene.rigidbody_world
|
||||
if rbw is not None and rbw.enabled:
|
||||
out_trait['parameters'] = [str(rbw.time_scale), str(rbw.substeps_per_frame), str(rbw.solver_iterations)]
|
||||
out_trait['parameters'] = [str(rbw.time_scale), str(rbw.substeps_per_frame), str(rbw.solver_iterations), str(wrd.lnx_physics_fixed_step)]
|
||||
|
||||
if phys_pkg == 'bullet' or phys_pkg == 'oimo':
|
||||
debug_draw_mode = 1 if wrd.lnx_physics_dbg_draw_wireframe else 0
|
||||
|
@ -87,6 +87,7 @@ def on_operator_post(operator_id: str) -> None:
|
||||
target_obj.lnx_rb_trigger = source_obj.lnx_rb_trigger
|
||||
target_obj.lnx_rb_deactivation_time = source_obj.lnx_rb_deactivation_time
|
||||
target_obj.lnx_rb_ccd = source_obj.lnx_rb_ccd
|
||||
target_obj.lnx_rb_interpolate = source_obj.lnx_rb_interpolate
|
||||
target_obj.lnx_rb_collision_filter_mask = source_obj.lnx_rb_collision_filter_mask
|
||||
|
||||
elif operator_id == "NODE_OT_new_node_tree":
|
||||
|
@ -191,7 +191,7 @@ def apply_materials(load_atlas=0):
|
||||
|
||||
mainNode = outputNode.inputs[0].links[0].from_node.inputs[0].links[0].from_node
|
||||
|
||||
if (mainNode.type == "ShaderNodeMixRGB"):
|
||||
if (mainNode.type == "ShaderNodeMix"):
|
||||
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
|
||||
print("Mix RGB shader found")
|
||||
|
||||
@ -199,9 +199,11 @@ def apply_materials(load_atlas=0):
|
||||
|
||||
#Add all nodes first
|
||||
#Add lightmap multipliction texture
|
||||
mixNode = node_tree.nodes.new(type="ShaderNodeMixRGB")
|
||||
mixNode = node_tree.nodes.new(type="ShaderNodeMix")
|
||||
mixNode.name = "Lightmap_Multiplication"
|
||||
mixNode.location = -800, 300
|
||||
mixNode.data_type = 'RGBA'
|
||||
mixNode.inputs[0].default_value = 1
|
||||
if scene.TLM_EngineProperties.tlm_lighting_mode == "indirect" or scene.TLM_EngineProperties.tlm_lighting_mode == "indirectAO":
|
||||
mixNode.blend_type = 'MULTIPLY'
|
||||
else:
|
||||
@ -312,8 +314,8 @@ def apply_materials(load_atlas=0):
|
||||
else:
|
||||
mat.node_tree.links.new(lightmapNode.outputs[1], DecodeNode.inputs[1]) #Connect lightmap node to decodenode
|
||||
|
||||
mat.node_tree.links.new(DecodeNode.outputs[0], mixNode.inputs[1]) #Connect decode node to mixnode
|
||||
mat.node_tree.links.new(ExposureNode.outputs[0], mixNode.inputs[1]) #Connect exposure node to mixnode
|
||||
mat.node_tree.links.new(DecodeNode.outputs[0], mixNode.inputs[6]) #Connect decode node to mixnode
|
||||
mat.node_tree.links.new(ExposureNode.outputs[0], mixNode.inputs[6]) #Connect exposure node to mixnode
|
||||
|
||||
else:
|
||||
|
||||
@ -323,10 +325,10 @@ def apply_materials(load_atlas=0):
|
||||
else:
|
||||
mat.node_tree.links.new(lightmapNode.outputs[1], DecodeNode.inputs[1]) #Connect lightmap node to decodenode
|
||||
|
||||
mat.node_tree.links.new(DecodeNode.outputs[0], mixNode.inputs[1]) #Connect lightmap node to mixnode
|
||||
mat.node_tree.links.new(DecodeNode.outputs[0], mixNode.inputs[6]) #Connect lightmap node to mixnode
|
||||
|
||||
mat.node_tree.links.new(baseColorNode.outputs[0], mixNode.inputs[2]) #Connect basecolor to pbr node
|
||||
mat.node_tree.links.new(mixNode.outputs[0], mainNode.inputs[0]) #Connect mixnode to pbr node
|
||||
mat.node_tree.links.new(baseColorNode.outputs[0], mixNode.inputs[7]) #Connect basecolor to pbr node
|
||||
mat.node_tree.links.new(mixNode.outputs[2], mainNode.inputs[0]) #Connect mixnode to pbr node
|
||||
|
||||
if not scene.TLM_EngineProperties.tlm_target == "vertex":
|
||||
mat.node_tree.links.new(UVLightmap.outputs[0], lightmapNode.inputs[0]) #Connect uvnode to lightmapnode
|
||||
@ -338,11 +340,11 @@ def apply_materials(load_atlas=0):
|
||||
|
||||
if(scene.TLM_EngineProperties.tlm_exposure_multiplier > 0):
|
||||
mat.node_tree.links.new(lightmapNode.outputs[0], ExposureNode.inputs[0]) #Connect lightmap node to mixnode
|
||||
mat.node_tree.links.new(ExposureNode.outputs[0], mixNode.inputs[1]) #Connect lightmap node to mixnode
|
||||
mat.node_tree.links.new(ExposureNode.outputs[0], mixNode.inputs[6]) #Connect lightmap node to mixnode
|
||||
else:
|
||||
mat.node_tree.links.new(lightmapNode.outputs[0], mixNode.inputs[1]) #Connect lightmap node to mixnode
|
||||
mat.node_tree.links.new(baseColorNode.outputs[0], mixNode.inputs[2]) #Connect basecolor to pbr node
|
||||
mat.node_tree.links.new(mixNode.outputs[0], mainNode.inputs[0]) #Connect mixnode to pbr node
|
||||
mat.node_tree.links.new(lightmapNode.outputs[0], mixNode.inputs[6]) #Connect lightmap node to mixnode
|
||||
mat.node_tree.links.new(baseColorNode.outputs[0], mixNode.inputs[7]) #Connect basecolor to pbr node
|
||||
mat.node_tree.links.new(mixNode.outputs[0], mainNode.inputs[2]) #Connect mixnode to pbr node
|
||||
if not scene.TLM_EngineProperties.tlm_target == "vertex":
|
||||
mat.node_tree.links.new(UVLightmap.outputs[0], lightmapNode.inputs[0]) #Connect uvnode to lightmapnode
|
||||
|
||||
@ -491,8 +493,9 @@ def applyAOPass():
|
||||
AOMap.image = AOImage
|
||||
AOMap.location = -800, 0
|
||||
|
||||
AOMult = nodes.new(type="ShaderNodeMixRGB")
|
||||
AOMult = nodes.new(type="ShaderNodeMix")
|
||||
AOMult.name = "TLM_AOMult"
|
||||
AOMult.data_type = 'RGBA'
|
||||
AOMult.blend_type = 'MULTIPLY'
|
||||
AOMult.inputs[0].default_value = 1.0
|
||||
AOMult.location = -300, 300
|
||||
|
@ -518,7 +518,7 @@ def configure_meshes(self):
|
||||
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
|
||||
print("The material group is not supported!")
|
||||
|
||||
if (mainNode.type == "ShaderNodeMixRGB"):
|
||||
if (mainNode.type == "ShaderNodeMix"):
|
||||
if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
|
||||
print("Mix shader found")
|
||||
|
||||
@ -811,7 +811,7 @@ def set_settings():
|
||||
|
||||
print(bpy.app.version)
|
||||
|
||||
if bpy.app.version[0] == 3:
|
||||
if bpy.app.version[0] == 3 or byp.app.version[0] == 4:
|
||||
if cycles.device == "GPU":
|
||||
scene.cycles.tile_size = 256
|
||||
else:
|
||||
|
@ -28,7 +28,11 @@ class ViewportDraw:
|
||||
w = 400
|
||||
h = 200
|
||||
|
||||
self.shader = gpu.shader.from_builtin('2D_IMAGE')
|
||||
if bpy.app.version[0] == 3:
|
||||
self.shader = gpu.shader.from_builtin('2D_IMAGE')
|
||||
else:
|
||||
self.shader = gpu.shader.from_builtin('IMAGE')
|
||||
|
||||
self.batch = batch_for_shader(
|
||||
self.shader, 'TRI_FAN',
|
||||
{
|
||||
|
@ -34,7 +34,7 @@ class Shader_Node_Types:
|
||||
normal = "ShaderNodeNormalMap"
|
||||
ao = "ShaderNodeAmbientOcclusion"
|
||||
uv = "ShaderNodeUVMap"
|
||||
mix = "ShaderNodeMixRGB"
|
||||
mix = "ShaderNodeMix"
|
||||
|
||||
def select_object(self,obj):
|
||||
C = bpy.context
|
||||
|
@ -47,7 +47,8 @@ def init_categories():
|
||||
lnx_nodes.add_category('Navmesh', icon='UV_VERTEXSEL', section="motion")
|
||||
lnx_nodes.add_category('Transform', icon='TRANSFORM_ORIGINS', section="motion")
|
||||
lnx_nodes.add_category('Physics', icon='PHYSICS', section="motion")
|
||||
|
||||
lnx_nodes.add_category('Particle', icon='PARTICLE_DATA', section="motion")
|
||||
|
||||
lnx_nodes.add_category('Array', icon='MOD_ARRAY', section="values")
|
||||
lnx_nodes.add_category('Map', icon='SHORTDISPLAY', section="values")
|
||||
lnx_nodes.add_category('Database', icon='MESH_CYLINDER', section="values")
|
||||
|
@ -11,14 +11,15 @@ class DrawCameraTextureNode(LnxLogicTreeNode):
|
||||
@input Object: Object of which to choose the material in the `Material Slot` input.
|
||||
@input Material Slot: Index of the material slot of which the diffuse
|
||||
texture is replaced with the camera's render target.
|
||||
|
||||
@input Node: Node name of the Image Texture Node.
|
||||
|
||||
@output On Start: Activated after the `Start` input has been activated.
|
||||
@output On Stop: Activated after the `Stop` input has been activated.
|
||||
"""
|
||||
bl_idname = 'LNDrawCameraTextureNode'
|
||||
bl_label = 'Draw Camera to Texture'
|
||||
lnx_section = 'draw'
|
||||
lnx_version = 1
|
||||
lnx_version = 2
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'Start')
|
||||
@ -26,6 +27,13 @@ class DrawCameraTextureNode(LnxLogicTreeNode):
|
||||
self.add_input('LnxNodeSocketObject', 'Camera')
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxIntSocket', 'Material Slot')
|
||||
|
||||
self.add_input('LnxStringSocket', 'Node')
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'On Start')
|
||||
self.add_output('LnxNodeSocketAction', 'On Stop')
|
||||
|
||||
def get_replacement_node(self, node_tree: bpy.types.NodeTree):
|
||||
if self.lnx_version not in (0, 1):
|
||||
raise LookupError()
|
||||
|
||||
return NodeReplacement.Identity(self)
|
44
leenkx/blender/lnx/logicnode/draw/LN_draw_sub_image.py
Normal file
44
leenkx/blender/lnx/logicnode/draw/LN_draw_sub_image.py
Normal file
@ -0,0 +1,44 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
|
||||
class DrawSubImageNode(LnxLogicTreeNode):
|
||||
"""Draws an image.
|
||||
@input Draw: Activate to draw the image on this frame. The input must
|
||||
be (indirectly) called from an `On Render2D` node.
|
||||
@input Image: The filename of the image.
|
||||
@input Color: The color that the image's pixels are multiplied with.
|
||||
@input Left/Center/Right: Horizontal anchor point of the image.
|
||||
0 = Left, 1 = Center, 2 = Right
|
||||
@input Top/Middle/Bottom: Vertical anchor point of the image.
|
||||
0 = Top, 1 = Middle, 2 = Bottom
|
||||
@input X/Y: Position of the anchor point in pixels.
|
||||
@input Width/Height: Size of the sub image in pixels.
|
||||
@input sX/Y: Position of the sub anchor point in pixels.
|
||||
@input sWidth/Height: Size of the image in pixels.
|
||||
@input Angle: Rotation angle in radians. Image will be rotated cloclwiswe
|
||||
at the anchor point.
|
||||
@output Out: Activated after the image has been drawn.
|
||||
@see [`kha.graphics2.Graphics.drawImage()`](http://kha.tech/api/kha/graphics2/Graphics.html#drawImage).
|
||||
"""
|
||||
bl_idname = 'LNDrawSubImageNode'
|
||||
bl_label = 'Draw Sub Image'
|
||||
lnx_section = 'draw'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'Draw')
|
||||
self.add_input('LnxStringSocket', 'Image File')
|
||||
self.add_input('LnxColorSocket', 'Color', default_value=[1.0, 1.0, 1.0, 1.0])
|
||||
self.add_input('LnxIntSocket', '0/1/2 = Left/Center/Right', default_value=0)
|
||||
self.add_input('LnxIntSocket', '0/1/2 = Top/Middle/Bottom', default_value=0)
|
||||
self.add_input('LnxFloatSocket', 'X')
|
||||
self.add_input('LnxFloatSocket', 'Y')
|
||||
self.add_input('LnxFloatSocket', 'Width')
|
||||
self.add_input('LnxFloatSocket', 'Height')
|
||||
self.add_input('LnxFloatSocket', 'sX')
|
||||
self.add_input('LnxFloatSocket', 'sY')
|
||||
self.add_input('LnxFloatSocket', 'sWidth')
|
||||
self.add_input('LnxFloatSocket', 'sHeight')
|
||||
self.add_input('LnxFloatSocket', 'Angle')
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
@ -0,0 +1,23 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class SetMaterialTextureFilterNode(LnxLogicTreeNode):
|
||||
"""Sets texture filter interpolation."""
|
||||
bl_idname = 'LNSetMaterialTextureFilterNode'
|
||||
bl_label = 'Set Object Material Texture Filter'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxDynamicSocket', 'Material')
|
||||
self.add_input('LnxIntSocket', 'Slot')
|
||||
self.add_input('LnxStringSocket', 'Node')
|
||||
self.add_input('LnxIntSocket', 'Texture Filter')
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
layout.label(text='Tex Filter 0: Linear')
|
||||
layout.label(text='Tex Filter 1: Closest')
|
||||
layout.label(text='Tex Filter 2: Cubic')
|
||||
layout.label(text='Tex Filter 3: Smart')
|
@ -5,8 +5,6 @@ class WriteFileNode(LnxLogicTreeNode):
|
||||
"""Writes the given string content to the given file. If the file
|
||||
already exists, the existing content of the file is overwritten.
|
||||
|
||||
> **This node is currently only implemented on Krom**
|
||||
|
||||
@input File: the name of the file, relative to `Krom.getFilesLocation()`
|
||||
@input Content: the content to write to the file.
|
||||
|
||||
|
34
leenkx/blender/lnx/logicnode/native/LN_write_image.py
Normal file
34
leenkx/blender/lnx/logicnode/native/LN_write_image.py
Normal file
@ -0,0 +1,34 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
|
||||
class WriteImageNode(LnxLogicTreeNode):
|
||||
"""Writes the given image to the given file. If the image
|
||||
already exists, the existing content of the image is overwritten.
|
||||
Aspect ratio must match display resolution ratio.
|
||||
@input Image File: the name of the image, relative to `Krom.getFilesLocation()`
|
||||
@input Camera: the render target image of the camera to write to the image file.
|
||||
@input Width: width of the image file.
|
||||
@input Height: heigth of the image file.
|
||||
@input sX: sub position of first x pixel of the sub image (0 for start).
|
||||
@input sY: sub position of first y pixel of the sub image (0 for start).
|
||||
@input sWidth: width of the sub image.
|
||||
@input sHeight: height of the sub image.
|
||||
@seeNode Read File
|
||||
"""
|
||||
bl_idname = 'LNWriteImageNode'
|
||||
bl_label = 'Write Image'
|
||||
lnx_section = 'file'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxStringSocket', 'Image File')
|
||||
self.add_input('LnxNodeSocketObject', 'Camera')
|
||||
self.add_input('LnxIntSocket', 'Width')
|
||||
self.add_input('LnxIntSocket', 'Height')
|
||||
self.add_input('LnxIntSocket', 'sX')
|
||||
self.add_input('LnxIntSocket', 'sY')
|
||||
self.add_input('LnxIntSocket', 'sWidth')
|
||||
self.add_input('LnxIntSocket', 'sHeight')
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
@ -5,8 +5,6 @@ class WriteJsonNode(LnxLogicTreeNode):
|
||||
"""Writes the given content to the given JSON file. If the file
|
||||
already exists, the existing content of the file is overwritten.
|
||||
|
||||
> **This node is currently only implemented on Krom**
|
||||
|
||||
@input File: the name of the file, relative to `Krom.getFilesLocation()`,
|
||||
including the file extension.
|
||||
@input Dynamic: the content to write to the file. Can be any type that can
|
||||
|
@ -0,0 +1,41 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class AddParticleToObjectNode(LnxLogicTreeNode):
|
||||
"""Sets the speed of the given particle source."""
|
||||
bl_idname = 'LNAddParticleToObjectNode'
|
||||
bl_label = 'Add Particle To Object'
|
||||
lnx_version = 1
|
||||
|
||||
def remove_extra_inputs(self, context):
|
||||
while len(self.inputs) > 1:
|
||||
self.inputs.remove(self.inputs[-1])
|
||||
if self.property0 == 'Scene':
|
||||
self.add_input('LnxStringSocket', 'Scene From Name')
|
||||
self.add_input('LnxStringSocket', 'Object From Name')
|
||||
else:
|
||||
self.add_input('LnxNodeSocketObject', 'Object From')
|
||||
self.add_input('LnxIntSocket', 'Slot')
|
||||
self.add_input('LnxNodeSocketObject', 'Object To')
|
||||
self.add_input('LnxBoolSocket', 'Render Emitter', default_value = True)
|
||||
|
||||
|
||||
property0: HaxeEnumProperty(
|
||||
'property0',
|
||||
items = [('Scene Active', 'Scene Active', 'Scene Active'),
|
||||
('Scene', 'Scene', 'Scene')],
|
||||
name='', default='Scene Active', update=remove_extra_inputs)
|
||||
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxNodeSocketObject', 'Object From')
|
||||
self.add_input('LnxIntSocket', 'Slot')
|
||||
self.add_input('LnxNodeSocketObject', 'Object To')
|
||||
self.add_input('LnxBoolSocket', 'Render Emitter', default_value = True)
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
layout.prop(self, 'property0')
|
||||
|
||||
|
14
leenkx/blender/lnx/logicnode/particle/LN_get_particle.py
Normal file
14
leenkx/blender/lnx/logicnode/particle/LN_get_particle.py
Normal file
@ -0,0 +1,14 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class GetParticleNode(LnxLogicTreeNode):
|
||||
"""Returns the Particle Systems of an object."""
|
||||
bl_idname = 'LNGetParticleNode'
|
||||
bl_label = 'Get Particle'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.inputs.new('LnxNodeSocketObject', 'Object')
|
||||
|
||||
self.outputs.new('LnxNodeSocketArray', 'Names')
|
||||
self.outputs.new('LnxIntSocket', 'Length')
|
||||
self.outputs.new('LnxBoolSocket', 'Render Emitter')
|
@ -0,0 +1,34 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class GetParticleDataNode(LnxLogicTreeNode):
|
||||
"""Returns the data of the given Particle System."""
|
||||
bl_idname = 'LNGetParticleDataNode'
|
||||
bl_label = 'Get Particle Data'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.inputs.new('LnxNodeSocketObject', 'Object')
|
||||
self.inputs.new('LnxIntSocket', 'Slot')
|
||||
|
||||
self.outputs.new('LnxStringSocket', 'Name')
|
||||
self.outputs.new('LnxFloatSocket', 'Particle Size')
|
||||
self.outputs.new('LnxIntSocket', 'Frame Start')
|
||||
self.outputs.new('LnxIntSocket', 'Frame End')
|
||||
self.outputs.new('LnxIntSocket', 'Lifetime')
|
||||
self.outputs.new('LnxFloatSocket', 'Lifetime Random')
|
||||
self.outputs.new('LnxIntSocket', 'Emit From')
|
||||
self.outputs.new('LnxBoolSocket', 'Auto Start')
|
||||
self.outputs.new('LnxBoolSocket', 'Is Unique')
|
||||
self.outputs.new('LnxBoolSocket', 'Loop')
|
||||
|
||||
self.outputs.new('LnxVectorSocket', 'Velocity')
|
||||
self.outputs.new('LnxFloatSocket', 'Velocity Random')
|
||||
self.outputs.new('LnxVectorSocket', 'Gravity')
|
||||
self.outputs.new('LnxFloatSocket', 'Weight Gravity')
|
||||
|
||||
self.outputs.new('LnxFloatSocket', 'Speed')
|
||||
|
||||
self.outputs.new('LnxFloatSocket', 'Time')
|
||||
self.outputs.new('LnxFloatSocket', 'Lap')
|
||||
self.outputs.new('LnxFloatSocket', 'Lap Time')
|
||||
self.outputs.new('LnxIntSocket', 'Count')
|
@ -0,0 +1,33 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class RemoveParticleFromObjectNode(LnxLogicTreeNode):
|
||||
"""Remove Particle From Object."""
|
||||
bl_idname = 'LNRemoveParticleFromObjectNode'
|
||||
bl_label = 'Remove Particle From Object'
|
||||
lnx_version = 1
|
||||
|
||||
def remove_extra_inputs(self, context):
|
||||
while len(self.inputs) > 2:
|
||||
self.inputs.remove(self.inputs[-1])
|
||||
if self.property0 == 'Slot':
|
||||
self.add_input('LnxIntSocket', 'Slot')
|
||||
if self.property0 == 'Name':
|
||||
self.add_input('LnxStringSocket', 'Name')
|
||||
|
||||
property0: HaxeEnumProperty(
|
||||
'property0',
|
||||
items = [('Slot', 'Slot', 'Slot'),
|
||||
('Name', 'Name', 'Name'),
|
||||
('All', 'All', 'All')],
|
||||
name='', default='Slot', update=remove_extra_inputs)
|
||||
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxIntSocket', 'Slot')
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
layout.prop(self, 'property0')
|
@ -0,0 +1,67 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class SetParticleDataNode(LnxLogicTreeNode):
|
||||
"""Sets the parameters of the given particle system."""
|
||||
bl_idname = 'LNSetParticleDataNode'
|
||||
bl_label = 'Set Particle Data'
|
||||
lnx_version = 1
|
||||
|
||||
def remove_extra_inputs(self, context):
|
||||
while len(self.inputs) > 3:
|
||||
self.inputs.remove(self.inputs[-1])
|
||||
if self.property0 == 'Particle Size':
|
||||
self.add_input('LnxFloatSocket', 'Particle Size')
|
||||
if self.property0 == 'Frame End':
|
||||
self.add_input('LnxIntSocket', 'Frame End')
|
||||
if self.property0 == 'Frame Start':
|
||||
self.add_input('LnxIntSocket', 'Frame Start')
|
||||
if self.property0 == 'Lifetime':
|
||||
self.add_input('LnxIntSocket', 'Lifetime')
|
||||
if self.property0 == 'Lifetime Random':
|
||||
self.add_input('LnxFloatSocket', 'Lifetime Random')
|
||||
if self.property0 == 'Emit From':
|
||||
self.add_input('LnxIntSocket', 'Emit From')
|
||||
if self.property0 == 'Auto Start':
|
||||
self.add_input('LnxBoolSocket', 'Auto Start')
|
||||
if self.property0 == 'Is Unique':
|
||||
self.add_input('LnxBoolSocket', 'Is Unique')
|
||||
if self.property0 == 'Loop':
|
||||
self.add_input('LnxBoolSocket', 'Loop')
|
||||
if self.property0 == 'Velocity':
|
||||
self.add_input('LnxVectorSocket', 'Velocity')
|
||||
if self.property0 == 'Velocity Random':
|
||||
self.add_input('LnxFloatSocket', 'Velocity Random')
|
||||
if self.property0 == 'Weight Gravity':
|
||||
self.add_input('LnxFloatSocket', 'Weight Gravity')
|
||||
if self.property0 == 'Speed':
|
||||
self.add_input('LnxFloatSocket', 'Speed')
|
||||
|
||||
|
||||
property0: HaxeEnumProperty(
|
||||
'property0',
|
||||
items = [('Particle Size', 'Particle Size', 'for the system'),
|
||||
('Frame Start', 'Frame Start', 'for the system'),
|
||||
('Frame End', 'Frame End', 'for the system'),
|
||||
('Lifetime', 'Lifetime', 'for the instance'),
|
||||
('Lifetime Random', 'Lifetime Random', 'for the system'),
|
||||
('Emit From', 'Emit From', 'for the system (Vertices:0 Faces:1 Volume: 2)'),
|
||||
('Auto Start', 'Auto Start', 'for the system'),
|
||||
('Is Unique', 'Is Unique', 'for the system'),
|
||||
('Loop', 'Loop', 'for the system'),
|
||||
('Velocity', 'Velocity', 'for the instance'),
|
||||
('Velocity Random', 'Velocity Random', 'for the system'),
|
||||
('Weight Gravity', 'Weight Gravity', 'for the instance'),
|
||||
('Speed', 'Speed', 'for the instance')],
|
||||
name='', default='Speed', update=remove_extra_inputs)
|
||||
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxIntSocket', 'Slot')
|
||||
self.add_input('LnxFloatSocket', 'Speed', default_value=1.0)
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
layout.prop(self, 'property0')
|
@ -1,14 +1,22 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class SetParticleSpeedNode(LnxLogicTreeNode):
|
||||
"""Sets the speed of the given particle source."""
|
||||
bl_idname = 'LNSetParticleSpeedNode'
|
||||
bl_label = 'Set Particle Speed'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxFloatSocket', 'Speed', default_value=1.0)
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class SetParticleSpeedNode(LnxLogicTreeNode):
|
||||
"""Sets the speed of the given particle source."""
|
||||
bl_idname = 'LNSetParticleSpeedNode'
|
||||
bl_label = 'Set Particle Speed'
|
||||
lnx_version = 2
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxIntSocket', 'Slot')
|
||||
self.add_input('LnxFloatSocket', 'Speed', default_value=1.0)
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
|
||||
|
||||
def get_replacement_node(self, node_tree: bpy.types.NodeTree):
|
||||
if self.lnx_version not in (0, 1):
|
||||
raise LookupError()
|
||||
|
||||
return NodeReplacement.Identity(self)
|
3
leenkx/blender/lnx/logicnode/particle/__init__.py
Normal file
3
leenkx/blender/lnx/logicnode/particle/__init__.py
Normal file
@ -0,0 +1,3 @@
|
||||
from lnx.logicnode.lnx_nodes import add_node_section
|
||||
|
||||
add_node_section(name='default', category='Particle')
|
@ -0,0 +1,11 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class AutoExposureGetNode(LnxLogicTreeNode):
|
||||
"""Returns the auto exposure post-processing settings."""
|
||||
bl_idname = 'LNAutoExposureGetNode'
|
||||
bl_label = 'Get Auto Exposure Settings'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_output('LnxFloatSocket', 'Strength')
|
||||
self.add_output('LnxFloatSocket', 'Speed')
|
@ -1,11 +1,20 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class ChromaticAberrationGetNode(LnxLogicTreeNode):
|
||||
"""Returns the chromatic aberration post-processing settings."""
|
||||
"""Returns the chromatic aberration post-processing settings.
|
||||
Type: Simple 0 Spectral 1.
|
||||
"""
|
||||
bl_idname = 'LNChromaticAberrationGetNode'
|
||||
bl_label = 'Get CA Settings'
|
||||
lnx_version = 1
|
||||
lnx_version = 2
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_output('LnxFloatSocket', 'Strength')
|
||||
self.add_output('LnxFloatSocket', 'Samples')
|
||||
self.add_output('LnxIntSocket', 'Type')
|
||||
|
||||
def get_replacement_node(self, node_tree: bpy.types.NodeTree):
|
||||
if self.lnx_version not in (0, 1):
|
||||
raise LookupError()
|
||||
|
||||
return NodeReplacement.Identity(self)
|
@ -16,11 +16,12 @@ class CameraGetNode(LnxLogicTreeNode):
|
||||
self.add_output('LnxFloatSocket', 'DOF Distance')#6
|
||||
self.add_output('LnxFloatSocket', 'DOF Length')#7
|
||||
self.add_output('LnxFloatSocket', 'DOF F-Stop')#8
|
||||
self.add_output('LnxBoolSocket', 'Tonemapping')#9
|
||||
self.add_output('LnxIntSocket', 'Tonemapping')#9
|
||||
self.add_output('LnxFloatSocket', 'Distort')#10
|
||||
self.add_output('LnxFloatSocket', 'Film Grain')#11
|
||||
self.add_output('LnxFloatSocket', 'Sharpen')#12
|
||||
self.add_output('LnxFloatSocket', 'Vignette')#13
|
||||
self.add_output('LnxFloatSocket', 'Exposure')#14
|
||||
|
||||
def get_replacement_node(self, node_tree: bpy.types.NodeTree):
|
||||
if self.lnx_version not in (0, 3):
|
||||
|
@ -0,0 +1,12 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class ResolutionGetNode(LnxLogicTreeNode):
|
||||
"""Returns the resolution parameters.
|
||||
"""
|
||||
bl_idname = 'LNResolutionGetNode'
|
||||
bl_label = 'Get Resolution Settings'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_output('LnxIntSocket', 'Size')
|
||||
self.add_output('LnxIntSocket', 'Filter')
|
@ -0,0 +1,12 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class SharpenGetNode(LnxLogicTreeNode):
|
||||
"""Returns the sharpen post-processing settings."""
|
||||
bl_idname = 'LNSharpenGetNode'
|
||||
bl_label = 'Get Sharpen Settings'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_output('LnxColorSocket', 'Color')
|
||||
self.add_output('LnxFloatSocket', 'Size')
|
||||
self.add_output('LnxFloatSocket', 'Strength')
|
@ -0,0 +1,12 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class VolumetricFogGetNode(LnxLogicTreeNode):
|
||||
"""Returns the volumetric fog post-processing settings."""
|
||||
bl_idname = 'LNVolumetricFogGetNode'
|
||||
bl_label = 'Get Volumetric Fog Settings'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_output('LnxColorSocket', 'Color')
|
||||
self.add_output('LnxFloatSocket', 'Amount A')
|
||||
self.add_output('LnxFloatSocket', 'Amount B')
|
@ -0,0 +1,12 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class VolumetricLightGetNode(LnxLogicTreeNode):
|
||||
"""Returns the volumetric light post-processing settings."""
|
||||
bl_idname = 'LNVolumetricLightGetNode'
|
||||
bl_label = 'Get Volumetric Light Settings'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_output('LnxColorSocket', 'Air Color')
|
||||
self.add_output('LnxFloatSocket', 'Air Turbidity')
|
||||
self.add_output('LnxIntSocket', 'Steps')
|
@ -0,0 +1,14 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class AutoExposureSetNode(LnxLogicTreeNode):
|
||||
"""Set the sharpen post-processing settings."""
|
||||
bl_idname = 'LNAutoExposureSetNode'
|
||||
bl_label = 'Set Auto Exposure Settings'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxFloatSocket', 'Strength', default_value=1)
|
||||
self.add_input('LnxFloatSocket', 'Speed', default_value=1)
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
@ -1,14 +1,27 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class ChromaticAberrationSetNode(LnxLogicTreeNode):
|
||||
"""Set the chromatic aberration post-processing settings."""
|
||||
"""Set the chromatic aberration post-processing settings.
|
||||
Type: Simple 0 Spectral 1.
|
||||
"""
|
||||
bl_idname = 'LNChromaticAberrationSetNode'
|
||||
bl_label = 'Set CA Settings'
|
||||
lnx_version = 1
|
||||
lnx_version = 2
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxFloatSocket', 'Strength', default_value=2.0)
|
||||
self.add_input('LnxIntSocket', 'Samples', default_value=32)
|
||||
self.add_input('LnxIntSocket', 'Type', default_value=0)
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
layout.label(text="Type 0: Simple")
|
||||
layout.label(text="Type 1: Spectral")
|
||||
|
||||
def get_replacement_node(self, node_tree: bpy.types.NodeTree):
|
||||
if self.lnx_version not in (0, 1):
|
||||
raise LookupError()
|
||||
|
||||
return NodeReplacement.Identity(self)
|
@ -4,27 +4,81 @@ class CameraSetNode(LnxLogicTreeNode):
|
||||
"""Set the post-processing effects of a camera."""
|
||||
bl_idname = 'LNCameraSetNode'
|
||||
bl_label = 'Set Camera Post Process'
|
||||
lnx_version = 4
|
||||
lnx_version = 6
|
||||
|
||||
|
||||
def remove_extra_inputs(self, context):
|
||||
while len(self.inputs) > 1:
|
||||
self.inputs.remove(self.inputs[-1])
|
||||
if self.property0 == 'F-stop':
|
||||
self.add_input('LnxFloatSocket', 'F-stop', default_value=1.0)#0
|
||||
if self.property0 == 'Shutter Time':
|
||||
self.add_input('LnxFloatSocket', 'Shutter Time', default_value=2.8333)#1
|
||||
if self.property0 == 'ISO':
|
||||
self.add_input('LnxFloatSocket', 'ISO', default_value=100.0)#2
|
||||
if self.property0 == 'Exposure Compensation':
|
||||
self.add_input('LnxFloatSocket', 'Exposure Compensation', default_value=0.0)#3
|
||||
if self.property0 == 'Fisheye Distortion':
|
||||
self.add_input('LnxFloatSocket', 'Fisheye Distortion', default_value=0.01)#4
|
||||
if self.property0 == 'Auto Focus':
|
||||
self.add_input('LnxBoolSocket', 'Auto Focus', default_value=True)#5
|
||||
if self.property0 == 'DoF Distance':
|
||||
self.add_input('LnxFloatSocket', 'DoF Distance', default_value=10.0)#6
|
||||
if self.property0 == 'DoF Length':
|
||||
self.add_input('LnxFloatSocket', 'DoF Length', default_value=160.0)#7
|
||||
if self.property0 == 'DoF F-Stop':
|
||||
self.add_input('LnxFloatSocket', 'DoF F-Stop', default_value=128.0)#8
|
||||
if self.property0 == 'Tonemapping':
|
||||
self.add_input('LnxIntSocket', 'Tonemapping', default_value=5)#9
|
||||
if self.property0 == 'Distort':
|
||||
self.add_input('LnxFloatSocket', 'Distort', default_value=2.0)#10
|
||||
if self.property0 == 'Film Grain':
|
||||
self.add_input('LnxFloatSocket', 'Film Grain', default_value=2.0)#11
|
||||
if self.property0 == 'Sharpen':
|
||||
self.add_input('LnxFloatSocket', 'Sharpen', default_value=0.25)#12
|
||||
if self.property0 == 'Vignette':
|
||||
self.add_input('LnxFloatSocket', 'Vignette', default_value=0.7)#13
|
||||
if self.property0 == 'Exposure':
|
||||
self.add_input('LnxFloatSocket', 'Exposure', default_value=1)#14
|
||||
|
||||
|
||||
property0: HaxeEnumProperty(
|
||||
'property0',
|
||||
items = [('F-stop', 'F-stop', 'F-stop'),
|
||||
('Shutter Time', 'Shutter Time', 'Shutter Time'),
|
||||
('ISO', 'ISO', 'ISO'),
|
||||
('Exposure Compensation', 'Exposure Compensation', 'Exposure Compensation'),
|
||||
('Fisheye Distortion', 'Fisheye Distortion', 'Fisheye Distortion'),
|
||||
('Auto Focus', 'Auto Focus', 'Auto Focus'),
|
||||
('DoF Distance', 'DoF Distance', 'DoF Distance'),
|
||||
('DoF Length', 'DoF Length', 'DoF Length'),
|
||||
('DoF F-Stop', 'DoF F-Stop', 'DoF F-Stop'),
|
||||
('Tonemapping', 'Tonemapping', 'Tonemapping'),
|
||||
('Distort', 'Distort', 'Distort'),
|
||||
('Film Grain', 'Film Grain', 'Film Grain'),
|
||||
('Sharpen', 'Sharpen', 'Sharpen'),
|
||||
('Vignette', 'Vignette', 'Vignette'),
|
||||
('Exposure', 'Exposure', 'Exposure')],
|
||||
name='', default='F-stop', update=remove_extra_inputs)
|
||||
|
||||
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxFloatSocket', 'F-stop', default_value=1.0)#0
|
||||
self.add_input('LnxFloatSocket', 'Shutter Time', default_value=2.8333)#1
|
||||
self.add_input('LnxFloatSocket', 'ISO', default_value=100.0)#2
|
||||
self.add_input('LnxFloatSocket', 'Exposure Compensation', default_value=0.0)#3
|
||||
self.add_input('LnxFloatSocket', 'Fisheye Distortion', default_value=0.01)#4
|
||||
self.add_input('LnxBoolSocket', 'Auto Focus', default_value=True)#5
|
||||
self.add_input('LnxFloatSocket', 'DoF Distance', default_value=10.0)#6
|
||||
self.add_input('LnxFloatSocket', 'DoF Length', default_value=160.0)#7
|
||||
self.add_input('LnxFloatSocket', 'DoF F-Stop', default_value=128.0)#8
|
||||
self.add_input('LnxBoolSocket', 'Tonemapping', default_value=False)#9
|
||||
self.add_input('LnxFloatSocket', 'Distort', default_value=2.0)#10
|
||||
self.add_input('LnxFloatSocket', 'Film Grain', default_value=2.0)#11
|
||||
self.add_input('LnxFloatSocket', 'Sharpen', default_value=0.25)#12
|
||||
self.add_input('LnxFloatSocket', 'Vignette', default_value=0.7)#13
|
||||
self.add_input('LnxFloatSocket', 'F-stop', default_value=1.0)
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
if self.property0 == 'Tonemapping':
|
||||
layout.label(text="0: Filmic")
|
||||
layout.label(text="1: Filmic2")
|
||||
layout.label(text="2: Reinhard")
|
||||
layout.label(text="3: Uncharted2")
|
||||
layout.label(text="5: Agx")
|
||||
layout.label(text="6: None")
|
||||
layout.prop(self, 'property0')
|
||||
|
||||
def get_replacement_node(self, node_tree: bpy.types.NodeTree):
|
||||
if self.lnx_version not in range(0, 4):
|
||||
raise LookupError()
|
||||
|
@ -0,0 +1,20 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class ResolutionSetNode(LnxLogicTreeNode):
|
||||
"""Set the resolution post-processing settings.
|
||||
Filter 0: Lineal 1: Closest
|
||||
"""
|
||||
bl_idname = 'LNResolutionSetNode'
|
||||
bl_label = 'Set Resolution Settings'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxIntSocket', 'Size', default_value=720)
|
||||
self.add_input('LnxIntSocket', 'Filter', default_value=0)
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
layout.label(text="Type 0: Lineal")
|
||||
layout.label(text="Type 1: Closest")
|
@ -0,0 +1,15 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class SharpenSetNode(LnxLogicTreeNode):
|
||||
"""Set the sharpen post-processing settings."""
|
||||
bl_idname = 'LNSharpenSetNode'
|
||||
bl_label = 'Set Sharpen Settings'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxColorSocket', 'Color', default_value=[0.0, 0.0, 0.0, 1.0])
|
||||
self.add_input('LnxFloatSocket', 'Size', default_value=2.5)
|
||||
self.add_input('LnxFloatSocket', 'Strength', default_value=0.25)
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
@ -0,0 +1,15 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class VolumetricFogSetNode(LnxLogicTreeNode):
|
||||
"""Set the volumetric fog post-processing settings."""
|
||||
bl_idname = 'LNVolumetricFogSetNode'
|
||||
bl_label = 'Set Volumetric Fog Settings'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxColorSocket', 'Color', default_value=[0.5, 0.6, 0.7, 1.0])
|
||||
self.add_input('LnxFloatSocket', 'Amount A', default_value=0.25)
|
||||
self.add_input('LnxFloatSocket', 'Amount B', default_value=0.50)
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
@ -0,0 +1,15 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class VolumetricLightSetNode(LnxLogicTreeNode):
|
||||
"""Set the volumetric light post-processing settings."""
|
||||
bl_idname = 'LNVolumetricLightSetNode'
|
||||
bl_label = 'Set Volumetric Light Settings'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxColorSocket', 'Air Color', default_value=[1.0, 1.0, 1.0, 1.0])
|
||||
self.add_input('LnxFloatSocket', 'Air Turbidity', default_value=1)
|
||||
self.add_input('LnxIntSocket', 'Steps', default_value=20)
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
@ -4,12 +4,13 @@ class RpConfigNode(LnxLogicTreeNode):
|
||||
"""Sets the post process quality."""
|
||||
bl_idname = 'LNRpConfigNode'
|
||||
bl_label = 'Set Post Process Quality'
|
||||
lnx_version = 1
|
||||
lnx_version = 2
|
||||
property0: HaxeEnumProperty(
|
||||
'property0',
|
||||
items = [('SSGI', 'SSGI', 'SSGI'),
|
||||
('SSR', 'SSR', 'SSR'),
|
||||
('Bloom', 'Bloom', 'Bloom'),
|
||||
('CA', 'CA', 'CA'),
|
||||
('GI', 'GI', 'GI'),
|
||||
('Motion Blur', 'Motion Blur', 'Motion Blur')
|
||||
],
|
||||
@ -23,3 +24,10 @@ class RpConfigNode(LnxLogicTreeNode):
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
layout.prop(self, 'property0')
|
||||
|
||||
|
||||
def get_replacement_node(self, node_tree: bpy.types.NodeTree):
|
||||
if self.lnx_version not in (0, 1):
|
||||
raise LookupError()
|
||||
|
||||
return NodeReplacement.Identity(self)
|
@ -1,8 +1,8 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class GetWorldNode(LnxLogicTreeNode):
|
||||
class GetWorldOrientationNode(LnxLogicTreeNode):
|
||||
"""Returns the world orientation of the given object."""
|
||||
bl_idname = 'LNGetWorldNode'
|
||||
bl_idname = 'LNGetWorldOrientationNode'
|
||||
bl_label = 'Get World Orientation'
|
||||
lnx_section = 'rotation'
|
||||
lnx_version = 1
|
||||
|
10
leenkx/blender/lnx/logicnode/world/LN_get_world.py
Normal file
10
leenkx/blender/lnx/logicnode/world/LN_get_world.py
Normal file
@ -0,0 +1,10 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class GetWorldNode(LnxLogicTreeNode):
|
||||
"""Gets the World of the active scene."""
|
||||
bl_idname = 'LNGetWorldNode'
|
||||
bl_label = 'Get World'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_output('LnxStringSocket', 'World')
|
13
leenkx/blender/lnx/logicnode/world/LN_set_world.py
Normal file
13
leenkx/blender/lnx/logicnode/world/LN_set_world.py
Normal file
@ -0,0 +1,13 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class SetWorldNode(LnxLogicTreeNode):
|
||||
"""Sets the World of the active scene."""
|
||||
bl_idname = 'LNSetWorldNode'
|
||||
bl_label = 'Set World'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxStringSocket', 'World')
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user