forked from LeenkxTeam/LNXSDK
Compare commits
251 Commits
Author | SHA1 | Date | |
---|---|---|---|
e594518e57 | |||
a41be0f436 | |||
1306033b36 | |||
eee0011cdd | |||
315ac0bd16 | |||
700d236bf1 | |||
f228eab8d3 | |||
863d884b76 | |||
34e0f5a282 | |||
45e2e52008 | |||
fb2d2a1a7c | |||
f88c04abea | |||
6fdd4b3f70 | |||
a389c27d75 | |||
1909c3da9f | |||
5824bd91aa | |||
43fe559eef | |||
12c09545ce | |||
0e60951ec9 | |||
ccb8b358d3 | |||
1a8586777b | |||
3721c774a1 | |||
a58fba408d | |||
268fba6cd5 | |||
4ab14ce6c8 | |||
9023e8d1da | |||
b58c7a9632 | |||
99b70622f5 | |||
647b73b746 | |||
935c30ec08 | |||
0b0d597f89 | |||
d5878afb30 | |||
96b55a1a56 | |||
91b3072305 | |||
1d0b338d92 | |||
8e83c0d0d0 | |||
927baec4df | |||
f5c9e70d1a | |||
0423a735fc | |||
bd413917fc | |||
852377f60d | |||
e17e9a8e35 | |||
4055c979a1 | |||
06b003ecdb | |||
fd7f215bb2 | |||
6a1df9ec46 | |||
deccac3c46 | |||
432b0210b2 | |||
14cf5cebed | |||
2307e1504f | |||
1ebfecb644 | |||
175b575b23 | |||
63943a9cbf | |||
224d9be76f | |||
62d3c8757b | |||
3785f93573 | |||
ffb276745f | |||
d1c9258da5 | |||
3e0cd2be35 | |||
1fd1973470 | |||
a01c72ef76 | |||
4b01a562c9 | |||
6972d9abc4 | |||
63c6b9d98b | |||
313d24bbc8 | |||
6d2812306d | |||
e84d6ada84 | |||
5057f2b946 | |||
2715fe3398 | |||
7cb8b8a2d2 | |||
cd606009e0 | |||
965162b101 | |||
c61a57bfb3 | |||
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 |
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
*.hdr binary
|
||||||
|
blender/lnx/props.py ident
|
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
*.DS_Store
|
@ -3,6 +3,10 @@
|
|||||||
|
|
||||||
#include "compiled.inc"
|
#include "compiled.inc"
|
||||||
|
|
||||||
|
#ifdef _CPostprocess
|
||||||
|
uniform vec4 PPComp17;
|
||||||
|
#endif
|
||||||
|
|
||||||
uniform sampler2D tex;
|
uniform sampler2D tex;
|
||||||
uniform vec2 dir;
|
uniform vec2 dir;
|
||||||
uniform vec2 screenSize;
|
uniform vec2 screenSize;
|
||||||
@ -45,6 +49,12 @@ void main() {
|
|||||||
res += factor * col;
|
res += factor * col;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _CPostprocess
|
||||||
|
vec3 AirColor = vec3(PPComp17.x, PPComp17.y, PPComp17.z);
|
||||||
|
#else
|
||||||
|
vec3 AirColor = volumAirColor;
|
||||||
|
#endif
|
||||||
|
|
||||||
res /= sumfactor;
|
res /= sumfactor;
|
||||||
fragColor = vec4(volumAirColor * res, 1.0);
|
fragColor = vec4(AirColor * res, 1.0);
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,11 @@
|
|||||||
{
|
{
|
||||||
"name": "screenSize",
|
"name": "screenSize",
|
||||||
"link": "_screenSize"
|
"link": "_screenSize"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PPComp17",
|
||||||
|
"link": "_PPComp17",
|
||||||
|
"ifdef": ["_CPostprocess"]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"texture_params": [],
|
"texture_params": [],
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
uniform sampler2D tex;
|
uniform sampler2D tex;
|
||||||
|
|
||||||
#ifdef _CPostprocess
|
#ifdef _CPostprocess
|
||||||
uniform vec3 PPComp13;
|
uniform vec4 PPComp13;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
in vec2 texCoord;
|
in vec2 texCoord;
|
||||||
@ -43,13 +43,17 @@ void main() {
|
|||||||
#ifdef _CPostprocess
|
#ifdef _CPostprocess
|
||||||
float max_distort = PPComp13.x;
|
float max_distort = PPComp13.x;
|
||||||
int num_iter = int(PPComp13.y);
|
int num_iter = int(PPComp13.y);
|
||||||
|
int CAType = int(PPComp13.z);
|
||||||
|
int on = int(PPComp13.w);
|
||||||
#else
|
#else
|
||||||
float max_distort = compoChromaticStrength;
|
float max_distort = compoChromaticStrength;
|
||||||
int num_iter = compoChromaticSamples;
|
int num_iter = compoChromaticSamples;
|
||||||
|
int CAType = compoChromaticType;
|
||||||
|
int on = 1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Spectral
|
// Spectral
|
||||||
if (compoChromaticType == 1) {
|
if (CAType == 1) {
|
||||||
float reci_num_iter_f = 1.0 / float(num_iter);
|
float reci_num_iter_f = 1.0 / float(num_iter);
|
||||||
|
|
||||||
vec2 resolution = vec2(1,1);
|
vec2 resolution = vec2(1,1);
|
||||||
@ -64,7 +68,7 @@ void main() {
|
|||||||
sumcol += w * texture(tex, barrelDistortion(uv, 0.6 * max_distort * t));
|
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
|
// Simple
|
||||||
@ -73,6 +77,7 @@ void main() {
|
|||||||
col.x = texture(tex, texCoord + ((vec2(0.0, 1.0) * max_distort) / vec2(1000.0))).x;
|
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.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;
|
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 PPComp6;
|
||||||
uniform vec3 PPComp7;
|
uniform vec3 PPComp7;
|
||||||
uniform vec3 PPComp8;
|
uniform vec3 PPComp8;
|
||||||
|
uniform vec3 PPComp11;
|
||||||
uniform vec3 PPComp14;
|
uniform vec3 PPComp14;
|
||||||
uniform vec4 PPComp15;
|
uniform vec4 PPComp15;
|
||||||
|
uniform vec4 PPComp16;
|
||||||
|
uniform vec4 PPComp18;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// #ifdef _CPos
|
// #ifdef _CPos
|
||||||
@ -106,6 +109,16 @@ in vec2 texCoord;
|
|||||||
out vec4 fragColor;
|
out vec4 fragColor;
|
||||||
|
|
||||||
#ifdef _CFog
|
#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 vec3 compoFogColor = vec3(0.5, 0.6, 0.7);
|
||||||
// const float compoFogAmountA = 1.0; // b = 0.01
|
// const float compoFogAmountA = 1.0; // b = 0.01
|
||||||
// const float compoFogAmountB = 1.0; // c = 0.1
|
// const float compoFogAmountB = 1.0; // c = 0.1
|
||||||
@ -118,8 +131,8 @@ out vec4 fragColor;
|
|||||||
// }
|
// }
|
||||||
vec3 applyFog(vec3 rgb, float distance) {
|
vec3 applyFog(vec3 rgb, float distance) {
|
||||||
// float fogAmount = 1.0 - exp(-distance * compoFogAmountA);
|
// float fogAmount = 1.0 - exp(-distance * compoFogAmountA);
|
||||||
float fogAmount = 1.0 - exp(-distance * (compoFogAmountA / 100));
|
float fogAmount = 1.0 - exp(-distance * (FogAmountA / 100));
|
||||||
return mix(rgb, compoFogColor, fogAmount);
|
return mix(rgb, FogColor, fogAmount);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -131,7 +144,7 @@ float ConvertEV100ToExposure(float EV100) {
|
|||||||
return 1/0.8 * exp2(-EV100);
|
return 1/0.8 * exp2(-EV100);
|
||||||
}
|
}
|
||||||
float ComputeEV(float avgLuminance) {
|
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 shutterTime = 1.0 / PPComp1.y;
|
||||||
const float ISO = PPComp1.z;
|
const float ISO = PPComp1.z;
|
||||||
const float EC = PPComp2.x;
|
const float EC = PPComp2.x;
|
||||||
@ -350,15 +363,21 @@ void main() {
|
|||||||
#ifdef _CSharpen
|
#ifdef _CSharpen
|
||||||
#ifdef _CPostprocess
|
#ifdef _CPostprocess
|
||||||
float strengthSharpen = PPComp14.y;
|
float strengthSharpen = PPComp14.y;
|
||||||
|
vec3 SharpenColor = vec3(PPComp16.x, PPComp16.y, PPComp16.z);
|
||||||
|
float SharpenSize = PPComp16.w;
|
||||||
#else
|
#else
|
||||||
float strengthSharpen = compoSharpenStrength;
|
float strengthSharpen = compoSharpenStrength;
|
||||||
|
vec3 SharpenColor = compoSharpenColor;
|
||||||
|
float SharpenSize = compoSharpenSize;
|
||||||
#endif
|
#endif
|
||||||
vec3 col1 = 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) * 1.5, 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) * 1.5, 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) * 1.5, 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;
|
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
|
#endif
|
||||||
|
|
||||||
#ifdef _CFog
|
#ifdef _CFog
|
||||||
@ -407,7 +426,11 @@ void main() {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _CExposure
|
#ifdef _CExposure
|
||||||
fragColor.rgb += fragColor.rgb * compoExposureStrength;
|
#ifdef _CPostprocess
|
||||||
|
fragColor.rgb+=fragColor.rgb*PPComp8.x;
|
||||||
|
#else
|
||||||
|
fragColor.rgb+= fragColor.rgb*compoExposureStrength;
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _CPostprocess
|
#ifdef _CPostprocess
|
||||||
@ -415,8 +438,13 @@ void main() {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _AutoExposure
|
#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);
|
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
|
#endif
|
||||||
|
|
||||||
// Clamp color to get rid of INF values that don't work for the tone mapping below
|
// 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
|
fragColor.rgb = pow(fragColor.rgb, vec3(1.0 / 2.2)); // To gamma
|
||||||
} else if (PPComp4.x == 10){
|
} else if (PPComp4.x == 10){
|
||||||
fragColor.rgb = tonemapAgXFull(fragColor.rgb);
|
fragColor.rgb = tonemapAgXFull(fragColor.rgb);
|
||||||
} else {
|
} //else { fragColor.rgb = vec3(0,1,0); //ERROR}
|
||||||
fragColor.rgb = vec3(0,1,0); //ERROR
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
@ -235,6 +235,16 @@
|
|||||||
"name": "PPComp15",
|
"name": "PPComp15",
|
||||||
"link": "_PPComp15",
|
"link": "_PPComp15",
|
||||||
"ifdef": ["_CPostprocess"]
|
"ifdef": ["_CPostprocess"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PPComp16",
|
||||||
|
"link": "_PPComp16",
|
||||||
|
"ifdef": ["_CPostprocess"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PPComp18",
|
||||||
|
"link": "_PPComp18",
|
||||||
|
"ifdef": ["_CPostprocess"]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"texture_params": [],
|
"texture_params": [],
|
||||||
|
@ -20,7 +20,7 @@ uniform sampler2D gbuffer0;
|
|||||||
uniform sampler2D gbuffer1;
|
uniform sampler2D gbuffer1;
|
||||||
|
|
||||||
#ifdef _gbuffer2
|
#ifdef _gbuffer2
|
||||||
//!uniform sampler2D gbuffer2;
|
uniform sampler2D gbuffer2;
|
||||||
#endif
|
#endif
|
||||||
#ifdef _EmissionShaded
|
#ifdef _EmissionShaded
|
||||||
uniform sampler2D gbufferEmission;
|
uniform sampler2D gbufferEmission;
|
||||||
@ -286,7 +286,7 @@ void main() {
|
|||||||
|
|
||||||
#ifdef _VoxelGI
|
#ifdef _VoxelGI
|
||||||
vec4 indirect_diffuse = textureLod(voxels_diffuse, texCoord, 0.0);
|
vec4 indirect_diffuse = textureLod(voxels_diffuse, texCoord, 0.0);
|
||||||
fragColor.rgb = (indirect_diffuse.rgb + envl.rgb * (1.0 - indirect_diffuse.a)) * albedo * voxelgiDiff;
|
fragColor.rgb = (indirect_diffuse.rgb * albedo + envl.rgb * (1.0 - indirect_diffuse.a)) * voxelgiDiff;
|
||||||
if(roughness < 1.0 && occspec.y > 0.0)
|
if(roughness < 1.0 && occspec.y > 0.0)
|
||||||
fragColor.rgb += textureLod(voxels_specular, texCoord, 0.0).rgb * occspec.y * voxelgiRefl;
|
fragColor.rgb += textureLod(voxels_specular, texCoord, 0.0).rgb * occspec.y * voxelgiRefl;
|
||||||
#endif
|
#endif
|
||||||
@ -380,7 +380,7 @@ void main() {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _VoxelShadow
|
#ifdef _VoxelShadow
|
||||||
svisibility *= (1.0 - traceShadow(p, n, voxels, voxelsSDF, sunDir, clipmaps, gl_FragCoord.xy, g2.rg).r) * voxelgiShad;
|
svisibility *= (1.0 - traceShadow(p, n, voxels, voxelsSDF, sunDir, clipmaps, gl_FragCoord.xy).r) * voxelgiShad;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _SSRS
|
#ifdef _SSRS
|
||||||
|
@ -2,13 +2,22 @@
|
|||||||
|
|
||||||
#include "compiled.inc"
|
#include "compiled.inc"
|
||||||
|
|
||||||
|
#ifdef _CPostprocess
|
||||||
|
uniform vec3 PPComp8;
|
||||||
|
#endif
|
||||||
|
|
||||||
uniform sampler2D tex;
|
uniform sampler2D tex;
|
||||||
|
|
||||||
in vec2 texCoord;
|
in vec2 texCoord;
|
||||||
out vec4 fragColor;
|
out vec4 fragColor;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
#ifdef _CPostprocess
|
||||||
|
fragColor.a = 0.01 * PPComp8.z;
|
||||||
|
#else
|
||||||
fragColor.a = 0.01 * autoExposureSpeed;
|
fragColor.a = 0.01 * autoExposureSpeed;
|
||||||
|
#endif
|
||||||
|
|
||||||
fragColor.rgb = textureLod(tex, vec2(0.5, 0.5), 0.0).rgb +
|
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.2, 0.2), 0.0).rgb +
|
||||||
textureLod(tex, vec2(0.8, 0.2), 0.0).rgb +
|
textureLod(tex, vec2(0.8, 0.2), 0.0).rgb +
|
||||||
|
@ -8,7 +8,13 @@
|
|||||||
"blend_source": "source_alpha",
|
"blend_source": "source_alpha",
|
||||||
"blend_destination": "inverse_source_alpha",
|
"blend_destination": "inverse_source_alpha",
|
||||||
"blend_operation": "add",
|
"blend_operation": "add",
|
||||||
"links": [],
|
"links": [
|
||||||
|
{
|
||||||
|
"name": "PPComp8",
|
||||||
|
"link": "_PPComp8",
|
||||||
|
"ifdef": ["_CPostprocess"]
|
||||||
|
}
|
||||||
|
],
|
||||||
"texture_params": [],
|
"texture_params": [],
|
||||||
"vertex_shader": "../include/pass.vert.glsl",
|
"vertex_shader": "../include/pass.vert.glsl",
|
||||||
"fragment_shader": "histogram_pass.frag.glsl"
|
"fragment_shader": "histogram_pass.frag.glsl"
|
||||||
|
@ -92,7 +92,7 @@ void main() {
|
|||||||
|
|
||||||
vec3 viewNormal = V3 * n;
|
vec3 viewNormal = V3 * n;
|
||||||
vec3 viewPos = getPosView(viewRay, d, cameraProj);
|
vec3 viewPos = getPosView(viewRay, d, cameraProj);
|
||||||
vec3 reflected = reflect(normalize(viewPos), viewNormal);
|
vec3 reflected = reflect(viewPos, viewNormal);
|
||||||
hitCoord = viewPos;
|
hitCoord = viewPos;
|
||||||
|
|
||||||
#ifdef _CPostprocess
|
#ifdef _CPostprocess
|
||||||
|
@ -62,12 +62,9 @@ vec4 rayCast(vec3 dir) {
|
|||||||
for (int i = 0; i < maxSteps; i++) {
|
for (int i = 0; i < maxSteps; i++) {
|
||||||
hitCoord += dir;
|
hitCoord += dir;
|
||||||
ddepth = getDeltaDepth(hitCoord);
|
ddepth = getDeltaDepth(hitCoord);
|
||||||
if (ddepth > 0.0)
|
if (ddepth > 0.0) return binarySearch(dir);
|
||||||
return binarySearch(dir);
|
|
||||||
}
|
}
|
||||||
// No hit — fallback to projecting the ray to UV space
|
return vec4(texCoord, 0.0, 1.0);
|
||||||
vec2 fallbackUV = getProjectedCoord(hitCoord);
|
|
||||||
return vec4(fallbackUV, 0.0, 0.5); // We set .w lower to indicate fallback
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
@ -77,7 +74,7 @@ void main() {
|
|||||||
float ior = gr.x;
|
float ior = gr.x;
|
||||||
float opac = gr.y;
|
float opac = gr.y;
|
||||||
float d = textureLod(gbufferD, texCoord, 0.0).r * 2.0 - 1.0;
|
float d = textureLod(gbufferD, texCoord, 0.0).r * 2.0 - 1.0;
|
||||||
if (d == 0.0 || opac == 1.0 || ior == 1.0) {
|
if (d == 0.0 || d == 1.0 || opac == 1.0 || ior == 1.0) {
|
||||||
fragColor.rgb = textureLod(tex1, texCoord, 0.0).rgb;
|
fragColor.rgb = textureLod(tex1, texCoord, 0.0).rgb;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -166,7 +166,7 @@ vec4 traceDiffuse(const vec3 origin, const vec3 normal, const sampler3D voxels,
|
|||||||
}
|
}
|
||||||
|
|
||||||
vec4 traceSpecular(const vec3 origin, const vec3 normal, const sampler3D voxels, const sampler3D voxelsSDF, const vec3 viewDir, const float roughness, const float clipmaps[voxelgiClipmapCount * 10], const vec2 pixel, const vec2 velocity) {
|
vec4 traceSpecular(const vec3 origin, const vec3 normal, const sampler3D voxels, const sampler3D voxelsSDF, const vec3 viewDir, const float roughness, const float clipmaps[voxelgiClipmapCount * 10], const vec2 pixel, const vec2 velocity) {
|
||||||
vec3 specularDir = reflect(normalize(-viewDir), normal);
|
vec3 specularDir = reflect(-viewDir, normal);
|
||||||
vec3 P = origin + specularDir * ((BayerMatrix8[int(pixel.x + velocity.x) % 8][int(pixel.y + velocity.y) % 8] - 0.5)) * voxelgiStep;
|
vec3 P = origin + specularDir * ((BayerMatrix8[int(pixel.x + velocity.x) % 8][int(pixel.y + velocity.y) % 8] - 0.5)) * voxelgiStep;
|
||||||
vec4 amount = traceCone(voxels, voxelsSDF, P, normal, specularDir, 0, true, roughness, voxelgiStep, clipmaps);
|
vec4 amount = traceCone(voxels, voxelsSDF, P, normal, specularDir, 0, true, roughness, voxelgiStep, clipmaps);
|
||||||
|
|
||||||
@ -176,9 +176,9 @@ vec4 traceSpecular(const vec3 origin, const vec3 normal, const sampler3D voxels,
|
|||||||
return amount * voxelgiOcc;
|
return amount * voxelgiOcc;
|
||||||
}
|
}
|
||||||
|
|
||||||
vec4 traceRefraction(const vec3 origin, const vec3 normal, sampler3D voxels, sampler3D voxelsSDF, const vec3 viewDir, const float ior, const float roughness, const float clipmaps[voxelgiClipmapCount * 10], const vec2 pixel, const vec2 velocity, const float opacity) {
|
vec4 traceRefraction(const vec3 origin, const vec3 normal, sampler3D voxels, sampler3D voxelsSDF, const vec3 viewDir, const float ior, const float roughness, const float clipmaps[voxelgiClipmapCount * 10], const vec2 pixel, const vec2 velocity) {
|
||||||
const float transmittance = 1.0 - opacity;
|
const float transmittance = 1.0;
|
||||||
vec3 refractionDir = refract(normalize(-viewDir), normal, 1.0 / ior);
|
vec3 refractionDir = refract(-viewDir, normal, 1.0 / ior);
|
||||||
vec3 P = origin + refractionDir * (BayerMatrix8[int(pixel.x + velocity.x) % 8][int(pixel.y + velocity.y) % 8] - 0.5) * voxelgiStep;
|
vec3 P = origin + refractionDir * (BayerMatrix8[int(pixel.x + velocity.x) % 8][int(pixel.y + velocity.y) % 8] - 0.5) * voxelgiStep;
|
||||||
vec4 amount = transmittance * traceCone(voxels, voxelsSDF, P, normal, refractionDir, 0, true, roughness, voxelgiStep, clipmaps);
|
vec4 amount = transmittance * traceCone(voxels, voxelsSDF, P, normal, refractionDir, 0, true, roughness, voxelgiStep, clipmaps);
|
||||||
|
|
||||||
@ -328,8 +328,8 @@ float traceConeShadow(const sampler3D voxels, const sampler3D voxelsSDF, const v
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
float traceShadow(const vec3 origin, const vec3 normal, const sampler3D voxels, const sampler3D voxelsSDF, const vec3 dir, const float clipmaps[voxelgiClipmapCount * 10], const vec2 pixel, const vec2 velocity) {
|
float traceShadow(const vec3 origin, const vec3 normal, const sampler3D voxels, const sampler3D voxelsSDF, const vec3 dir, const float clipmaps[voxelgiClipmapCount * 10], const vec2 pixel) {
|
||||||
vec3 P = origin + dir * (BayerMatrix8[int(pixel.x + velocity.x) % 8][int(pixel.y + velocity.y) % 8] - 0.5) * voxelgiStep;
|
vec3 P = origin + dir * (BayerMatrix8[int(pixel.x) % 8][int(pixel.y) % 8] - 0.5) * voxelgiStep;
|
||||||
float amount = traceConeShadow(voxels, voxelsSDF, P, normal, dir, DIFFUSE_CONE_APERTURE, voxelgiStep, clipmaps);
|
float amount = traceConeShadow(voxels, voxelsSDF, P, normal, dir, DIFFUSE_CONE_APERTURE, voxelgiStep, clipmaps);
|
||||||
amount = clamp(amount, 0.0, 1.0);
|
amount = clamp(amount, 0.0, 1.0);
|
||||||
return amount * voxelgiOcc;
|
return amount * voxelgiOcc;
|
||||||
|
@ -9,9 +9,7 @@
|
|||||||
#endif
|
#endif
|
||||||
#ifdef _VoxelShadow
|
#ifdef _VoxelShadow
|
||||||
#include "std/conetrace.glsl"
|
#include "std/conetrace.glsl"
|
||||||
#endif
|
//!uniform sampler2D voxels_shadows;
|
||||||
#ifdef _gbuffer2
|
|
||||||
uniform sampler2D gbuffer2;
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef _LTC
|
#ifdef _LTC
|
||||||
#include "std/ltc.glsl"
|
#include "std/ltc.glsl"
|
||||||
@ -148,8 +146,7 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _VoxelShadow
|
#ifdef _VoxelShadow
|
||||||
vec4 g2 = textureLod(gbuffer2, gl_FragCoord.xy, 0.0);
|
direct *= (1.0 - traceShadow(p, n, voxels, voxelsSDF, l, clipmaps, gl_FragCoord.xy).r) * voxelgiShad;
|
||||||
direct *= (1.0 - traceShadow(p, n, voxels, voxelsSDF, l, clipmaps, gl_FragCoord.xy, g2.rg).r) * voxelgiShad;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _LTC
|
#ifdef _LTC
|
||||||
|
@ -87,6 +87,40 @@ float lpToDepth(vec3 lp, const vec2 lightProj) {
|
|||||||
return zcomp * 0.5 + 0.5;
|
return zcomp * 0.5 + 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef _ShadowMapAtlas
|
||||||
|
vec3 PCFCube(samplerCubeShadow shadowMapCube, samplerCube shadowMapCubeTransparent, vec3 lp, vec3 ml, float bias, vec2 lightProj, vec3 n, const bool transparent) {
|
||||||
|
const float s = shadowmapCubePcfSize;
|
||||||
|
float compare = lpToDepth(lp, lightProj) - bias * 1.5;
|
||||||
|
ml = ml + n * bias * 20;
|
||||||
|
#ifdef _InvY
|
||||||
|
ml.y = -ml.y;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
float shadowFactor = 0.0;
|
||||||
|
shadowFactor = texture(shadowMapCube, vec4(ml, compare));
|
||||||
|
shadowFactor += texture(shadowMapCube, vec4(ml + vec3(s, s, s), compare));
|
||||||
|
shadowFactor += texture(shadowMapCube, vec4(ml + vec3(-s, s, s), compare));
|
||||||
|
shadowFactor += texture(shadowMapCube, vec4(ml + vec3(s, -s, s), compare));
|
||||||
|
shadowFactor += texture(shadowMapCube, vec4(ml + vec3(s, s, -s), compare));
|
||||||
|
shadowFactor += texture(shadowMapCube, vec4(ml + vec3(-s, -s, s), compare));
|
||||||
|
shadowFactor += texture(shadowMapCube, vec4(ml + vec3(s, -s, -s), compare));
|
||||||
|
shadowFactor += texture(shadowMapCube, vec4(ml + vec3(-s, s, -s), compare));
|
||||||
|
shadowFactor += texture(shadowMapCube, vec4(ml + vec3(-s, -s, -s), compare));
|
||||||
|
shadowFactor /= 9.0;
|
||||||
|
|
||||||
|
vec3 result = vec3(shadowFactor);
|
||||||
|
|
||||||
|
if (transparent == false) {
|
||||||
|
vec4 shadowmap_transparent = texture(shadowMapCubeTransparent, ml);
|
||||||
|
if (shadowmap_transparent.a < compare)
|
||||||
|
result *= shadowmap_transparent.rgb;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _ShadowMapAtlas
|
||||||
vec3 PCFCube(samplerCubeShadow shadowMapCube, samplerCube shadowMapCubeTransparent, const vec3 lp, vec3 ml, const float bias, const vec2 lightProj, const vec3 n, const bool transparent) {
|
vec3 PCFCube(samplerCubeShadow shadowMapCube, samplerCube shadowMapCubeTransparent, const vec3 lp, vec3 ml, const float bias, const vec2 lightProj, const vec3 n, const bool transparent) {
|
||||||
const float s = shadowmapCubePcfSize; // TODO: incorrect...
|
const float s = shadowmapCubePcfSize; // TODO: incorrect...
|
||||||
float compare = lpToDepth(lp, lightProj) - bias * 1.5;
|
float compare = lpToDepth(lp, lightProj) - bias * 1.5;
|
||||||
@ -115,7 +149,7 @@ vec3 PCFCube(samplerCubeShadow shadowMapCube, samplerCube shadowMapCubeTranspare
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _ShadowMapAtlas
|
|
||||||
// transform "out-of-bounds" coordinates to the correct face/coordinate system
|
// transform "out-of-bounds" coordinates to the correct face/coordinate system
|
||||||
// https://www.khronos.org/opengl/wiki/File:CubeMapAxes.png
|
// https://www.khronos.org/opengl/wiki/File:CubeMapAxes.png
|
||||||
vec2 transformOffsetedUV(const int faceIndex, out int newFaceIndex, vec2 uv) {
|
vec2 transformOffsetedUV(const int faceIndex, out int newFaceIndex, vec2 uv) {
|
||||||
|
@ -11,6 +11,8 @@ vec3 uncharted2Tonemap(const vec3 x) {
|
|||||||
vec3 tonemapUncharted2(const vec3 color) {
|
vec3 tonemapUncharted2(const vec3 color) {
|
||||||
const float W = 11.2;
|
const float W = 11.2;
|
||||||
const float exposureBias = 2.0;
|
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 curr = uncharted2Tonemap(exposureBias * color);
|
||||||
vec3 whiteScale = 1.0 / uncharted2Tonemap(vec3(W));
|
vec3 whiteScale = 1.0 / uncharted2Tonemap(vec3(W));
|
||||||
return curr * whiteScale;
|
return curr * whiteScale;
|
||||||
|
@ -11,6 +11,11 @@
|
|||||||
#include "std/light_common.glsl"
|
#include "std/light_common.glsl"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef _CPostprocess
|
||||||
|
uniform vec3 PPComp11;
|
||||||
|
uniform vec4 PPComp17;
|
||||||
|
#endif
|
||||||
|
|
||||||
uniform sampler2D gbufferD;
|
uniform sampler2D gbufferD;
|
||||||
uniform sampler2D snoise;
|
uniform sampler2D snoise;
|
||||||
|
|
||||||
@ -87,7 +92,13 @@ out float fragColor;
|
|||||||
const float tScat = 0.08;
|
const float tScat = 0.08;
|
||||||
const float tAbs = 0.0;
|
const float tAbs = 0.0;
|
||||||
const float tExt = tScat + tAbs;
|
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;
|
const float lighting = 0.4;
|
||||||
|
|
||||||
void rayStep(inout vec3 curPos, inout float curOpticalDepth, inout float scatteredLightAmount, float stepLenWorld, vec3 viewVecNorm) {
|
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);
|
rayStep(curPos, curOpticalDepth, scatteredLightAmount, stepLenWorld, viewVecNorm);
|
||||||
}
|
}
|
||||||
|
|
||||||
fragColor = scatteredLightAmount * volumAirTurbidity;
|
fragColor = scatteredLightAmount * AirTurbidity;
|
||||||
}
|
}
|
||||||
|
@ -140,6 +140,16 @@
|
|||||||
"link": "_biasLightWorldViewProjectionMatrixSpot3",
|
"link": "_biasLightWorldViewProjectionMatrixSpot3",
|
||||||
"ifndef": ["_ShadowMapAtlas"],
|
"ifndef": ["_ShadowMapAtlas"],
|
||||||
"ifdef": ["_Spot", "_ShadowMap"]
|
"ifdef": ["_Spot", "_ShadowMap"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PPComp11",
|
||||||
|
"link": "_PPComp11",
|
||||||
|
"ifdef": ["_CPostprocess"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PPComp17",
|
||||||
|
"link": "_PPComp17",
|
||||||
|
"ifdef": ["_CPostprocess"]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"texture_params": [],
|
"texture_params": [],
|
||||||
|
@ -33,7 +33,6 @@ uniform layout(r32ui) uimage3D voxelsLight;
|
|||||||
|
|
||||||
#ifdef _ShadowMap
|
#ifdef _ShadowMap
|
||||||
uniform sampler2DShadow shadowMap;
|
uniform sampler2DShadow shadowMap;
|
||||||
uniform sampler2D shadowMapTransparent;
|
|
||||||
uniform sampler2DShadow shadowMapSpot;
|
uniform sampler2DShadow shadowMapSpot;
|
||||||
#ifdef _ShadowMapAtlas
|
#ifdef _ShadowMapAtlas
|
||||||
uniform sampler2DShadow shadowMapPoint;
|
uniform sampler2DShadow shadowMapPoint;
|
||||||
@ -87,22 +86,27 @@ float lpToDepth(vec3 lp, const vec2 lightProj) {
|
|||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
int res = voxelgiResolution.x;
|
int res = voxelgiResolution.x;
|
||||||
for (int i = 0; i < 6; i++) {
|
|
||||||
ivec3 dst = ivec3(gl_GlobalInvocationID.xyz);
|
ivec3 dst = ivec3(gl_GlobalInvocationID.xyz);
|
||||||
|
dst.y += clipmapLevel * res;
|
||||||
|
|
||||||
vec3 P = (gl_GlobalInvocationID.xyz + 0.5) / voxelgiResolution;
|
vec3 P = (gl_GlobalInvocationID.xyz + 0.5) / voxelgiResolution;
|
||||||
P = P * 2.0 - 1.0;
|
P = P * 2.0 - 1.0;
|
||||||
|
P *= clipmaps[int(clipmapLevel * 10)];
|
||||||
|
P *= voxelgiResolution;
|
||||||
|
P += vec3(clipmaps[int(clipmapLevel * 10 + 4)], clipmaps[int(clipmapLevel * 10 + 5)], clipmaps[int(clipmapLevel * 10 + 6)]);
|
||||||
|
|
||||||
float visibility;
|
vec3 visibility;
|
||||||
vec3 lp = lightPos - P;
|
vec3 lp = lightPos - P;
|
||||||
vec3 l;
|
vec3 l;
|
||||||
if (lightType == 0) { l = lightDir; visibility = 1.0; }
|
if (lightType == 0) { l = lightDir; visibility = vec3(1.0); }
|
||||||
else { l = normalize(lp); visibility = attenuate(distance(P, lightPos)); }
|
else { l = normalize(lp); visibility = vec3(attenuate(distance(P, lightPos))); }
|
||||||
|
|
||||||
#ifdef _ShadowMap
|
#ifdef _ShadowMap
|
||||||
if (lightShadow == 1) {
|
if (lightShadow == 1) {
|
||||||
vec4 lightPosition = LVP * vec4(P, 1.0);
|
vec4 lightPosition = LVP * vec4(P, 1.0);
|
||||||
vec3 lPos = lightPosition.xyz / lightPosition.w;
|
vec3 lPos = lightPosition.xyz / lightPosition.w;
|
||||||
visibility = texture(shadowMap, vec3(lPos.xy, lPos.z - shadowsBias)).r;
|
visibility = texture(shadowMap, vec3(lPos.xy, lPos.z - shadowsBias)).rrr;
|
||||||
}
|
}
|
||||||
else if (lightShadow == 2) {
|
else if (lightShadow == 2) {
|
||||||
vec4 lightPosition = LVP * vec4(P, 1.0);
|
vec4 lightPosition = LVP * vec4(P, 1.0);
|
||||||
@ -124,14 +128,11 @@ void main() {
|
|||||||
visibility *= texture(shadowMapPoint, vec4(-l, lpToDepth(lp, lightProj) - shadowsBias)).r;
|
visibility *= texture(shadowMapPoint, vec4(-l, lpToDepth(lp, lightProj) - shadowsBias)).r;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
vec3 uvw_light = (P - vec3(clipmaps[int(clipmapLevel * 10 + 4)], clipmaps[int(clipmapLevel * 10 + 5)], clipmaps[int(clipmapLevel * 10 + 6)])) / (float(clipmaps[int(clipmapLevel * 10)]) * voxelgiResolution);
|
|
||||||
uvw_light = (uvw_light * 0.5 + 0.5);
|
|
||||||
if (any(notEqual(uvw_light, clamp(uvw_light, 0.0, 1.0)))) return;
|
|
||||||
vec3 writecoords_light = floor(uvw_light * voxelgiResolution);
|
|
||||||
|
|
||||||
imageAtomicMax(voxelsLight, ivec3(writecoords_light), uint(visibility * lightColor.r * 255));
|
vec3 light = visibility * lightColor;
|
||||||
imageAtomicMax(voxelsLight, ivec3(writecoords_light) + ivec3(0, 0, voxelgiResolution.x), uint(visibility * lightColor.g * 255));
|
|
||||||
imageAtomicMax(voxelsLight, ivec3(writecoords_light) + ivec3(0, 0, voxelgiResolution.x * 2), uint(visibility * lightColor.b * 255));
|
imageAtomicAdd(voxelsLight, dst + ivec3(0, 0, 0), uint(light.r * 255));
|
||||||
}
|
imageAtomicAdd(voxelsLight, dst + ivec3(0, 0, voxelgiResolution.x), uint(light.g * 255));
|
||||||
|
imageAtomicAdd(voxelsLight, dst + ivec3(0, 0, voxelgiResolution.x * 2), uint(light.b * 255));
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ layout (local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
|
|||||||
uniform sampler3D voxels;
|
uniform sampler3D voxels;
|
||||||
uniform sampler2D gbufferD;
|
uniform sampler2D gbufferD;
|
||||||
uniform sampler2D gbuffer0;
|
uniform sampler2D gbuffer0;
|
||||||
uniform layout(r16) image2D voxels_ao;
|
uniform layout(r8) image2D voxels_ao;
|
||||||
|
|
||||||
uniform float clipmaps[voxelgiClipmapCount * 10];
|
uniform float clipmaps[voxelgiClipmapCount * 10];
|
||||||
uniform mat4 InvVP;
|
uniform mat4 InvVP;
|
||||||
|
@ -33,7 +33,7 @@ layout (local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
|
|||||||
uniform sampler3D voxels;
|
uniform sampler3D voxels;
|
||||||
uniform sampler2D gbufferD;
|
uniform sampler2D gbufferD;
|
||||||
uniform sampler2D gbuffer0;
|
uniform sampler2D gbuffer0;
|
||||||
uniform layout(rgba16) image2D voxels_diffuse;
|
uniform layout(rgba8) image2D voxels_diffuse;
|
||||||
|
|
||||||
uniform float clipmaps[voxelgiClipmapCount * 10];
|
uniform float clipmaps[voxelgiClipmapCount * 10];
|
||||||
uniform mat4 InvVP;
|
uniform mat4 InvVP;
|
||||||
@ -46,7 +46,7 @@ void main() {
|
|||||||
const vec2 pixel = gl_GlobalInvocationID.xy;
|
const vec2 pixel = gl_GlobalInvocationID.xy;
|
||||||
vec2 uv = (pixel + 0.5) / postprocess_resolution;
|
vec2 uv = (pixel + 0.5) / postprocess_resolution;
|
||||||
#ifdef _InvY
|
#ifdef _InvY
|
||||||
uv.y = 1.0 - uv.y;
|
uv.y = 1.0 - uv.y
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
float depth = textureLod(gbufferD, uv, 0.0).r * 2.0 - 1.0;
|
float depth = textureLod(gbufferD, uv, 0.0).r * 2.0 - 1.0;
|
||||||
|
@ -34,7 +34,7 @@ uniform sampler2D gbufferD;
|
|||||||
uniform sampler2D gbuffer0;
|
uniform sampler2D gbuffer0;
|
||||||
uniform sampler3D voxels;
|
uniform sampler3D voxels;
|
||||||
uniform sampler3D voxelsSDF;
|
uniform sampler3D voxelsSDF;
|
||||||
uniform layout(rgba16) image2D voxels_specular;
|
uniform layout(rgba8) image2D voxels_specular;
|
||||||
|
|
||||||
uniform float clipmaps[voxelgiClipmapCount * 10];
|
uniform float clipmaps[voxelgiClipmapCount * 10];
|
||||||
uniform mat4 InvVP;
|
uniform mat4 InvVP;
|
||||||
@ -71,7 +71,7 @@ void main() {
|
|||||||
|
|
||||||
vec2 velocity = -textureLod(sveloc, uv, 0.0).rg;
|
vec2 velocity = -textureLod(sveloc, uv, 0.0).rg;
|
||||||
|
|
||||||
vec3 color = traceSpecular(P, n, voxels, voxelsSDF, normalize(eye - P), g0.z * g0.z, clipmaps, pixel, velocity).rgb;
|
vec3 color = traceSpecular(P, n, voxels, voxelsSDF, normalize(eye - P), g0.z, clipmaps, pixel, velocity).rgb;
|
||||||
|
|
||||||
imageStore(voxels_specular, ivec2(pixel), vec4(color, 1.0));
|
imageStore(voxels_specular, ivec2(pixel), vec4(color, 1.0));
|
||||||
}
|
}
|
||||||
|
@ -23,8 +23,8 @@ THE SOFTWARE.
|
|||||||
|
|
||||||
#include "compiled.inc"
|
#include "compiled.inc"
|
||||||
|
|
||||||
uniform layout(r8) image3D input_sdf;
|
uniform layout(r16) image3D input_sdf;
|
||||||
uniform layout(r8) image3D output_sdf;
|
uniform layout(r16) image3D output_sdf;
|
||||||
|
|
||||||
uniform float jump_size;
|
uniform float jump_size;
|
||||||
uniform int clipmapLevel;
|
uniform int clipmapLevel;
|
||||||
|
@ -46,15 +46,15 @@ uniform layout(r32ui) uimage3D voxels;
|
|||||||
uniform layout(r32ui) uimage3D voxelsLight;
|
uniform layout(r32ui) uimage3D voxelsLight;
|
||||||
uniform layout(rgba8) image3D voxelsB;
|
uniform layout(rgba8) image3D voxelsB;
|
||||||
uniform layout(rgba8) image3D voxelsOut;
|
uniform layout(rgba8) image3D voxelsOut;
|
||||||
uniform layout(r8) image3D SDF;
|
uniform layout(r16) image3D SDF;
|
||||||
#else
|
#else
|
||||||
#ifdef _VoxelAOvar
|
#ifdef _VoxelAOvar
|
||||||
#ifdef _VoxelShadow
|
#ifdef _VoxelShadow
|
||||||
uniform layout(r8) image3D SDF;
|
uniform layout(r16) image3D SDF;
|
||||||
#endif
|
#endif
|
||||||
uniform layout(r32ui) uimage3D voxels;
|
uniform layout(r32ui) uimage3D voxels;
|
||||||
uniform layout(r8) image3D voxelsB;
|
uniform layout(r16) image3D voxelsB;
|
||||||
uniform layout(r8) image3D voxelsOut;
|
uniform layout(r16) image3D voxelsOut;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -80,6 +80,7 @@ void main() {
|
|||||||
light.r = float(imageLoad(voxelsLight, src)) / 255;
|
light.r = float(imageLoad(voxelsLight, src)) / 255;
|
||||||
light.g = float(imageLoad(voxelsLight, src + ivec3(0, 0, voxelgiResolution.x))) / 255;
|
light.g = float(imageLoad(voxelsLight, src + ivec3(0, 0, voxelgiResolution.x))) / 255;
|
||||||
light.b = float(imageLoad(voxelsLight, src + ivec3(0, 0, voxelgiResolution.x * 2))) / 255;
|
light.b = float(imageLoad(voxelsLight, src + ivec3(0, 0, voxelgiResolution.x * 2))) / 255;
|
||||||
|
light /= 3;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (int i = 0; i < 6 + DIFFUSE_CONE_COUNT; i++)
|
for (int i = 0; i < 6 + DIFFUSE_CONE_COUNT; i++)
|
||||||
@ -124,7 +125,7 @@ void main() {
|
|||||||
envl.g = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 10))) / 255;
|
envl.g = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 10))) / 255;
|
||||||
envl.b = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 11))) / 255;
|
envl.b = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 11))) / 255;
|
||||||
envl /= 3;
|
envl /= 3;
|
||||||
|
envl *= 100;
|
||||||
|
|
||||||
//clipmap to world
|
//clipmap to world
|
||||||
vec3 wposition = (gl_GlobalInvocationID.xyz + 0.5) / voxelgiResolution.x;
|
vec3 wposition = (gl_GlobalInvocationID.xyz + 0.5) / voxelgiResolution.x;
|
||||||
@ -136,7 +137,7 @@ void main() {
|
|||||||
radiance = basecol;
|
radiance = basecol;
|
||||||
vec4 trace = traceDiffuse(wposition, wnormal, voxelsSampler, clipmaps);
|
vec4 trace = traceDiffuse(wposition, wnormal, voxelsSampler, clipmaps);
|
||||||
vec3 indirect = trace.rgb + envl.rgb * (1.0 - trace.a);
|
vec3 indirect = trace.rgb + envl.rgb * (1.0 - trace.a);
|
||||||
radiance.rgb *= light / PI + indirect;
|
radiance.rgb *= light + indirect;
|
||||||
radiance.rgb += emission.rgb;
|
radiance.rgb += emission.rgb;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
@ -75,17 +75,16 @@ vec4 binarySearch(vec3 dir) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
vec4 rayCast(vec3 dir) {
|
vec4 rayCast(vec3 dir) {
|
||||||
float ddepth;
|
#ifdef _CPostprocess
|
||||||
dir *= ss_refractionRayStep;
|
dir *= PPComp9.x;
|
||||||
|
#else
|
||||||
|
dir *= ssrRayStep;
|
||||||
|
#endif
|
||||||
for (int i = 0; i < maxSteps; i++) {
|
for (int i = 0; i < maxSteps; i++) {
|
||||||
hitCoord += dir;
|
hitCoord += dir;
|
||||||
ddepth = getDeltaDepth(hitCoord);
|
if (getDeltaDepth(hitCoord) > 0.0) return binarySearch(dir);
|
||||||
if (ddepth > 0.0)
|
|
||||||
return binarySearch(dir);
|
|
||||||
}
|
}
|
||||||
// No hit — fallback to projecting the ray to UV space
|
return vec4(0.0);
|
||||||
vec2 fallbackUV = getProjectedCoord(hitCoord);
|
|
||||||
return vec4(fallbackUV, 0.0, 0.5); // We set .w lower to indicate fallback
|
|
||||||
}
|
}
|
||||||
#endif //SSR
|
#endif //SSR
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ class App {
|
|||||||
static var traitInits: Array<Void->Void> = [];
|
static var traitInits: Array<Void->Void> = [];
|
||||||
static var traitUpdates: Array<Void->Void> = [];
|
static var traitUpdates: Array<Void->Void> = [];
|
||||||
static var traitLateUpdates: 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 traitRenders: Array<kha.graphics4.Graphics->Void> = [];
|
||||||
static var traitRenders2D: Array<kha.graphics2.Graphics->Void> = [];
|
static var traitRenders2D: Array<kha.graphics2.Graphics->Void> = [];
|
||||||
public static var framebuffer: kha.Framebuffer;
|
public static var framebuffer: kha.Framebuffer;
|
||||||
@ -23,6 +24,8 @@ class App {
|
|||||||
public static var renderPathTime: Float;
|
public static var renderPathTime: Float;
|
||||||
public static var endFrameCallbacks: Array<Void->Void> = [];
|
public static var endFrameCallbacks: Array<Void->Void> = [];
|
||||||
#end
|
#end
|
||||||
|
static var last = 0.0;
|
||||||
|
static var time = 0.0;
|
||||||
static var lastw = -1;
|
static var lastw = -1;
|
||||||
static var lasth = -1;
|
static var lasth = -1;
|
||||||
public static var onResize: Void->Void = null;
|
public static var onResize: Void->Void = null;
|
||||||
@ -34,13 +37,14 @@ class App {
|
|||||||
function new(done: Void->Void) {
|
function new(done: Void->Void) {
|
||||||
done();
|
done();
|
||||||
kha.System.notifyOnFrames(render);
|
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() {
|
public static function reset() {
|
||||||
traitInits = [];
|
traitInits = [];
|
||||||
traitUpdates = [];
|
traitUpdates = [];
|
||||||
traitLateUpdates = [];
|
traitLateUpdates = [];
|
||||||
|
traitFixedUpdates = [];
|
||||||
traitRenders = [];
|
traitRenders = [];
|
||||||
traitRenders2D = [];
|
traitRenders2D = [];
|
||||||
if (onResets != null) for (f in onResets) f();
|
if (onResets != null) for (f in onResets) f();
|
||||||
@ -48,6 +52,8 @@ class App {
|
|||||||
|
|
||||||
static function update() {
|
static function update() {
|
||||||
if (Scene.active == null || !Scene.active.ready) return;
|
if (Scene.active == null || !Scene.active.ready) return;
|
||||||
|
|
||||||
|
iron.system.Time.update();
|
||||||
if (pauseUpdates) return;
|
if (pauseUpdates) return;
|
||||||
|
|
||||||
#if lnx_debug
|
#if lnx_debug
|
||||||
@ -56,6 +62,14 @@ class App {
|
|||||||
|
|
||||||
Scene.active.updateFrame();
|
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 i = 0;
|
||||||
var l = traitUpdates.length;
|
var l = traitUpdates.length;
|
||||||
while (i < l) {
|
while (i < l) {
|
||||||
@ -106,7 +120,7 @@ class App {
|
|||||||
var frame = frames[0];
|
var frame = frames[0];
|
||||||
framebuffer = frame;
|
framebuffer = frame;
|
||||||
|
|
||||||
iron.system.Time.update();
|
iron.system.Time.render();
|
||||||
|
|
||||||
if (Scene.active == null || !Scene.active.ready) {
|
if (Scene.active == null || !Scene.active.ready) {
|
||||||
render2D(frame);
|
render2D(frame);
|
||||||
@ -172,6 +186,14 @@ class App {
|
|||||||
traitLateUpdates.remove(f);
|
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) {
|
public static function notifyOnRender(f: kha.graphics4.Graphics->Void) {
|
||||||
traitRenders.push(f);
|
traitRenders.push(f);
|
||||||
}
|
}
|
||||||
|
@ -518,12 +518,44 @@ class RenderPath {
|
|||||||
return Reflect.field(kha.Shaders, handle + "_comp");
|
return Reflect.field(kha.Shaders, handle + "_comp");
|
||||||
}
|
}
|
||||||
|
|
||||||
#if (kha_krom && lnx_vr)
|
#if lnx_vr
|
||||||
public function drawStereo(drawMeshes: Int->Void) {
|
public function drawStereo(drawMeshes: Void->Void) {
|
||||||
for (eye in 0...2) {
|
var vr = kha.vr.VrInterface.instance;
|
||||||
Krom.vrBeginRender(eye);
|
var appw = iron.App.w();
|
||||||
drawMeshes(eye);
|
var apph = iron.App.h();
|
||||||
Krom.vrEndRender(eye);
|
var halfw = Std.int(appw / 2);
|
||||||
|
var g = currentG;
|
||||||
|
|
||||||
|
if (vr != null && vr.IsPresenting()) {
|
||||||
|
// Left eye
|
||||||
|
Scene.active.camera.V.setFrom(Scene.active.camera.leftV);
|
||||||
|
Scene.active.camera.P.self = vr.GetProjectionMatrix(0);
|
||||||
|
g.viewport(0, 0, halfw, apph);
|
||||||
|
drawMeshes();
|
||||||
|
|
||||||
|
// Right eye
|
||||||
|
begin(g, additionalTargets);
|
||||||
|
Scene.active.camera.V.setFrom(Scene.active.camera.rightV);
|
||||||
|
Scene.active.camera.P.self = vr.GetProjectionMatrix(1);
|
||||||
|
g.viewport(halfw, 0, halfw, apph);
|
||||||
|
drawMeshes();
|
||||||
|
}
|
||||||
|
else { // Simulate
|
||||||
|
Scene.active.camera.buildProjection(halfw / apph);
|
||||||
|
|
||||||
|
// Left eye
|
||||||
|
g.viewport(0, 0, halfw, apph);
|
||||||
|
drawMeshes();
|
||||||
|
|
||||||
|
// Right eye
|
||||||
|
begin(g, additionalTargets);
|
||||||
|
Scene.active.camera.transform.move(Scene.active.camera.right(), 0.032);
|
||||||
|
Scene.active.camera.buildMatrix();
|
||||||
|
g.viewport(halfw, 0, halfw, apph);
|
||||||
|
drawMeshes();
|
||||||
|
|
||||||
|
Scene.active.camera.transform.move(Scene.active.camera.right(), -0.032);
|
||||||
|
Scene.active.camera.buildMatrix();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#end
|
#end
|
||||||
|
@ -775,6 +775,7 @@ class Scene {
|
|||||||
// Attach particle systems
|
// Attach particle systems
|
||||||
#if lnx_particles
|
#if lnx_particles
|
||||||
if (o.particle_refs != null) {
|
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);
|
for (ref in o.particle_refs) cast(object, MeshObject).setupParticleSystem(sceneName, ref);
|
||||||
}
|
}
|
||||||
#end
|
#end
|
||||||
@ -782,6 +783,11 @@ class Scene {
|
|||||||
if (o.tilesheet_ref != null) {
|
if (o.tilesheet_ref != null) {
|
||||||
cast(object, MeshObject).setupTilesheet(sceneName, o.tilesheet_ref, o.tilesheet_action_ref);
|
cast(object, MeshObject).setupTilesheet(sceneName, o.tilesheet_ref, o.tilesheet_action_ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (o.camera_list != null){
|
||||||
|
cast(object, MeshObject).cameraList = o.camera_list;
|
||||||
|
}
|
||||||
|
|
||||||
returnObject(object, o, done);
|
returnObject(object, o, done);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ class Trait {
|
|||||||
var _remove: Array<Void->Void> = null;
|
var _remove: Array<Void->Void> = null;
|
||||||
var _update: Array<Void->Void> = null;
|
var _update: Array<Void->Void> = null;
|
||||||
var _lateUpdate: 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 _render: Array<kha.graphics4.Graphics->Void> = null;
|
||||||
var _render2D: Array<kha.graphics2.Graphics->Void> = null;
|
var _render2D: Array<kha.graphics2.Graphics->Void> = null;
|
||||||
|
|
||||||
@ -87,6 +88,23 @@ class Trait {
|
|||||||
App.removeLateUpdate(f);
|
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.
|
Add render handler.
|
||||||
**/
|
**/
|
||||||
|
@ -392,6 +392,8 @@ typedef TParticleData = {
|
|||||||
#end
|
#end
|
||||||
public var name: String;
|
public var name: String;
|
||||||
public var type: Int; // 0 - Emitter, Hair
|
public var type: Int; // 0 - Emitter, Hair
|
||||||
|
public var auto_start: Bool;
|
||||||
|
public var is_unique: Bool;
|
||||||
public var loop: Bool;
|
public var loop: Bool;
|
||||||
public var count: Int;
|
public var count: Int;
|
||||||
public var frame_start: FastFloat;
|
public var frame_start: FastFloat;
|
||||||
@ -439,6 +441,7 @@ typedef TObj = {
|
|||||||
@:optional public var traits: Array<TTrait>;
|
@:optional public var traits: Array<TTrait>;
|
||||||
@:optional public var properties: Array<TProperty>;
|
@:optional public var properties: Array<TProperty>;
|
||||||
@:optional public var vertex_groups: Array<TVertex_groups>;
|
@:optional public var vertex_groups: Array<TVertex_groups>;
|
||||||
|
@:optional public var camera_list: Array<String>;
|
||||||
@:optional public var constraints: Array<TConstraint>;
|
@:optional public var constraints: Array<TConstraint>;
|
||||||
@:optional public var dimensions: Float32Array; // Geometry objects
|
@:optional public var dimensions: Float32Array; // Geometry objects
|
||||||
@:optional public var object_actions: Array<String>;
|
@:optional public var object_actions: Array<String>;
|
||||||
|
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){
|
if(markerEvents.get(sampler) != null){
|
||||||
for (i in 0...anim.marker_frames.length) {
|
for (i in 0...anim.marker_frames.length) {
|
||||||
if (frameIndex == anim.marker_frames[i]) {
|
if (frameIndex == anim.marker_frames[i]) {
|
||||||
var marketAct = markerEvents.get(sampler);
|
var markerAct = markerEvents.get(sampler);
|
||||||
var ar = marketAct.get(anim.marker_names[i]);
|
var ar = markerAct.get(anim.marker_names[i]);
|
||||||
if (ar != null) for (f in ar) f();
|
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;
|
lastFrameIndex = frameIndex;
|
||||||
|
@ -31,11 +31,21 @@ class CameraObject extends Object {
|
|||||||
static var vcenter = new Vec4();
|
static var vcenter = new Vec4();
|
||||||
static var vup = new Vec4();
|
static var vup = new Vec4();
|
||||||
|
|
||||||
|
#if lnx_vr
|
||||||
|
var helpMat = Mat4.identity();
|
||||||
|
public var leftV = Mat4.identity();
|
||||||
|
public var rightV = Mat4.identity();
|
||||||
|
#end
|
||||||
|
|
||||||
public function new(data: CameraData) {
|
public function new(data: CameraData) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.data = data;
|
this.data = data;
|
||||||
|
|
||||||
|
#if lnx_vr
|
||||||
|
iron.system.VR.initButton();
|
||||||
|
#end
|
||||||
|
|
||||||
buildProjection();
|
buildProjection();
|
||||||
|
|
||||||
V = Mat4.identity();
|
V = Mat4.identity();
|
||||||
@ -117,6 +127,26 @@ class CameraObject extends Object {
|
|||||||
V.getInverse(transform.world);
|
V.getInverse(transform.world);
|
||||||
VP.multmats(P, V);
|
VP.multmats(P, V);
|
||||||
|
|
||||||
|
|
||||||
|
#if lnx_vr
|
||||||
|
var vr = kha.vr.VrInterface.instance;
|
||||||
|
if (vr != null && vr.IsPresenting()) {
|
||||||
|
leftV.setFrom(V);
|
||||||
|
helpMat.self = vr.GetViewMatrix(0);
|
||||||
|
leftV.multmat(helpMat);
|
||||||
|
|
||||||
|
rightV.setFrom(V);
|
||||||
|
helpMat.self = vr.GetViewMatrix(1);
|
||||||
|
rightV.multmat(helpMat);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
leftV.setFrom(V);
|
||||||
|
}
|
||||||
|
VP.multmats(P, leftV);
|
||||||
|
#else
|
||||||
|
VP.multmats(P, V);
|
||||||
|
#end
|
||||||
|
|
||||||
if (data.raw.frustum_culling) {
|
if (data.raw.frustum_culling) {
|
||||||
buildViewFrustum(VP, frustumPlanes);
|
buildViewFrustum(VP, frustumPlanes);
|
||||||
}
|
}
|
||||||
|
@ -155,7 +155,12 @@ class LightObject extends Object {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function setCascade(camera: CameraObject, cascade: Int) {
|
public function setCascade(camera: CameraObject, cascade: Int) {
|
||||||
|
|
||||||
|
#if lnx_vr
|
||||||
|
m.setFrom(camera.leftV);
|
||||||
|
#else
|
||||||
m.setFrom(camera.V);
|
m.setFrom(camera.V);
|
||||||
|
#end
|
||||||
|
|
||||||
#if lnx_csm
|
#if lnx_csm
|
||||||
if (camSlicedP == null) {
|
if (camSlicedP == null) {
|
||||||
|
@ -21,8 +21,10 @@ class MeshObject extends Object {
|
|||||||
public var particleChildren: Array<MeshObject> = null;
|
public var particleChildren: Array<MeshObject> = null;
|
||||||
public var particleOwner: MeshObject = null; // Particle object
|
public var particleOwner: MeshObject = null; // Particle object
|
||||||
public var particleIndex = -1;
|
public var particleIndex = -1;
|
||||||
|
public var render_emitter = true;
|
||||||
#end
|
#end
|
||||||
public var cameraDistance: Float;
|
public var cameraDistance: Float;
|
||||||
|
public var cameraList: Array<String> = null;
|
||||||
public var screenSize = 0.0;
|
public var screenSize = 0.0;
|
||||||
public var frustumCulling = true;
|
public var frustumCulling = true;
|
||||||
public var activeTilesheet: Tilesheet = null;
|
public var activeTilesheet: Tilesheet = null;
|
||||||
@ -234,6 +236,8 @@ class MeshObject extends Object {
|
|||||||
if (cullMesh(context, Scene.active.camera, RenderPath.active.light)) return;
|
if (cullMesh(context, Scene.active.camera, RenderPath.active.light)) return;
|
||||||
var meshContext = raw != null ? context == "mesh" : false;
|
var meshContext = raw != null ? context == "mesh" : false;
|
||||||
|
|
||||||
|
if (cameraList != null && cameraList.indexOf(Scene.active.camera.name) < 0) return;
|
||||||
|
|
||||||
#if lnx_particles
|
#if lnx_particles
|
||||||
if (raw != null && raw.is_particle && particleOwner == null) return; // Instancing not yet set-up by particle system owner
|
if (raw != null && raw.is_particle && particleOwner == null) return; // Instancing not yet set-up by particle system owner
|
||||||
if (particleSystems != null && meshContext) {
|
if (particleSystems != null && meshContext) {
|
||||||
@ -244,6 +248,7 @@ class MeshObject extends Object {
|
|||||||
Scene.active.spawnObject(psys.data.raw.instance_object, null, function(o: Object) {
|
Scene.active.spawnObject(psys.data.raw.instance_object, null, function(o: Object) {
|
||||||
if (o != null) {
|
if (o != null) {
|
||||||
var c: MeshObject = cast o;
|
var c: MeshObject = cast o;
|
||||||
|
c.cameraList = this.cameraList;
|
||||||
particleChildren.push(c);
|
particleChildren.push(c);
|
||||||
c.particleOwner = this;
|
c.particleOwner = this;
|
||||||
c.particleIndex = particleChildren.length - 1;
|
c.particleIndex = particleChildren.length - 1;
|
||||||
@ -255,11 +260,11 @@ class MeshObject extends Object {
|
|||||||
particleSystems[i].update(particleChildren[i], this);
|
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;
|
||||||
#end
|
if (particleSystems == null && cullMaterial(context)) return;
|
||||||
|
#else
|
||||||
if (cullMaterial(context)) return;
|
if (cullMaterial(context)) return;
|
||||||
|
#end
|
||||||
// Get lod
|
// Get lod
|
||||||
var mats = materials;
|
var mats = materials;
|
||||||
var lod = this;
|
var lod = this;
|
||||||
|
@ -172,6 +172,10 @@ class Object {
|
|||||||
for (f in t._init) App.removeInit(f);
|
for (f in t._init) App.removeInit(f);
|
||||||
t._init = null;
|
t._init = null;
|
||||||
}
|
}
|
||||||
|
if (t._fixedUpdate != null) {
|
||||||
|
for (f in t._fixedUpdate) App.removeFixedUpdate(f);
|
||||||
|
t._fixedUpdate = null;
|
||||||
|
}
|
||||||
if (t._update != null) {
|
if (t._update != null) {
|
||||||
for (f in t._update) App.removeUpdate(f);
|
for (f in t._update) App.removeUpdate(f);
|
||||||
t._update = null;
|
t._update = null;
|
||||||
|
@ -2,6 +2,7 @@ package iron.object;
|
|||||||
|
|
||||||
#if lnx_particles
|
#if lnx_particles
|
||||||
|
|
||||||
|
import kha.FastFloat;
|
||||||
import kha.graphics4.Usage;
|
import kha.graphics4.Usage;
|
||||||
import kha.arrays.Float32Array;
|
import kha.arrays.Float32Array;
|
||||||
import iron.data.Data;
|
import iron.data.Data;
|
||||||
@ -16,10 +17,12 @@ import iron.math.Vec4;
|
|||||||
class ParticleSystem {
|
class ParticleSystem {
|
||||||
public var data: ParticleData;
|
public var data: ParticleData;
|
||||||
public var speed = 1.0;
|
public var speed = 1.0;
|
||||||
|
var currentSpeed = 0.0;
|
||||||
var particles: Array<Particle>;
|
var particles: Array<Particle>;
|
||||||
var ready: Bool;
|
var ready: Bool;
|
||||||
var frameRate = 24;
|
var frameRate = 24;
|
||||||
var lifetime = 0.0;
|
var lifetime = 0.0;
|
||||||
|
var looptime = 0.0;
|
||||||
var animtime = 0.0;
|
var animtime = 0.0;
|
||||||
var time = 0.0;
|
var time = 0.0;
|
||||||
var spawnRate = 0.0;
|
var spawnRate = 0.0;
|
||||||
@ -47,8 +50,12 @@ class ParticleSystem {
|
|||||||
var ownerRot = new Quat();
|
var ownerRot = new Quat();
|
||||||
var ownerScl = new Vec4();
|
var ownerScl = new Vec4();
|
||||||
|
|
||||||
|
var random = 0.0;
|
||||||
|
|
||||||
public function new(sceneName: String, pref: TParticleReference) {
|
public function new(sceneName: String, pref: TParticleReference) {
|
||||||
seed = pref.seed;
|
seed = pref.seed;
|
||||||
|
currentSpeed = speed;
|
||||||
|
speed = 0;
|
||||||
particles = [];
|
particles = [];
|
||||||
ready = false;
|
ready = false;
|
||||||
|
|
||||||
@ -65,33 +72,61 @@ class ParticleSystem {
|
|||||||
gy = 0;
|
gy = 0;
|
||||||
gz = -9.81 * r.weight_gravity;
|
gz = -9.81 * r.weight_gravity;
|
||||||
}
|
}
|
||||||
alignx = r.object_align_factor[0] / 2;
|
alignx = r.object_align_factor[0];
|
||||||
aligny = r.object_align_factor[1] / 2;
|
aligny = r.object_align_factor[1];
|
||||||
alignz = r.object_align_factor[2] / 2;
|
alignz = r.object_align_factor[2];
|
||||||
|
looptime = (r.frame_end - r.frame_start) / frameRate;
|
||||||
lifetime = r.lifetime / 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;
|
spawnRate = ((r.frame_end - r.frame_start) / r.count) / frameRate;
|
||||||
|
|
||||||
for (i in 0...r.count) {
|
for (i in 0...r.count) {
|
||||||
var particle = new Particle(i);
|
particles.push(new Particle(i));
|
||||||
particle.sr = 1 - Math.random() * r.size_random;
|
|
||||||
particles.push(particle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ready = true;
|
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() {
|
public function pause() {
|
||||||
lifetime = 0;
|
speed = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function resume() {
|
public function resume() {
|
||||||
lifetime = r.lifetime / frameRate;
|
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) {
|
public function update(object: MeshObject, owner: MeshObject) {
|
||||||
if (!ready || object == null || speed == 0.0) return;
|
if (!ready || object == null || speed == 0.0) return;
|
||||||
|
if (iron.App.pauseUpdates) return;
|
||||||
|
|
||||||
|
var prevLap = lap;
|
||||||
|
|
||||||
// Copy owner world transform but discard scale
|
// Copy owner world transform but discard scale
|
||||||
owner.transform.world.decompose(ownerLoc, ownerRot, ownerScl);
|
owner.transform.world.decompose(ownerLoc, ownerRot, ownerScl);
|
||||||
@ -115,17 +150,21 @@ class ParticleSystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Animate
|
// Animate
|
||||||
time += Time.delta * speed;
|
time += Time.renderDelta * speed; // realDelta to renderDelta
|
||||||
lap = Std.int(time / animtime);
|
lap = Std.int(time / animtime);
|
||||||
lapTime = time - lap * animtime;
|
lapTime = time - lap * animtime;
|
||||||
count = Std.int(lapTime / spawnRate);
|
count = Std.int(lapTime / spawnRate);
|
||||||
|
|
||||||
|
if (lap > prevLap && !r.loop) {
|
||||||
|
end();
|
||||||
|
}
|
||||||
|
|
||||||
updateGpu(object, owner);
|
updateGpu(object, owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getData(): Mat4 {
|
public function getData(): Mat4 {
|
||||||
var hair = r.type == 1;
|
var hair = r.type == 1;
|
||||||
m._00 = r.loop ? animtime : -animtime;
|
m._00 = animtime;
|
||||||
m._01 = hair ? 1 / particles.length : spawnRate;
|
m._01 = hair ? 1 / particles.length : spawnRate;
|
||||||
m._02 = hair ? 1 : lifetime;
|
m._02 = hair ? 1 : lifetime;
|
||||||
m._03 = particles.length;
|
m._03 = particles.length;
|
||||||
@ -133,9 +172,9 @@ class ParticleSystem {
|
|||||||
m._11 = hair ? 0 : aligny;
|
m._11 = hair ? 0 : aligny;
|
||||||
m._12 = hair ? 0 : alignz;
|
m._12 = hair ? 0 : alignz;
|
||||||
m._13 = hair ? 0 : r.factor_random;
|
m._13 = hair ? 0 : r.factor_random;
|
||||||
m._20 = hair ? 0 : gx * r.mass;
|
m._20 = hair ? 0 : gx;
|
||||||
m._21 = hair ? 0 : gy * r.mass;
|
m._21 = hair ? 0 : gy;
|
||||||
m._22 = hair ? 0 : gz * r.mass;
|
m._22 = hair ? 0 : gz;
|
||||||
m._23 = hair ? 0 : r.lifetime_random;
|
m._23 = hair ? 0 : r.lifetime_random;
|
||||||
m._30 = tilesx;
|
m._30 = tilesx;
|
||||||
m._31 = tilesy;
|
m._31 = tilesy;
|
||||||
@ -144,13 +183,25 @@ class ParticleSystem {
|
|||||||
return m;
|
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) {
|
function updateGpu(object: MeshObject, owner: MeshObject) {
|
||||||
if (!object.data.geom.instanced) setupGeomGpu(object, owner);
|
if (!object.data.geom.instanced) setupGeomGpu(object, owner);
|
||||||
// GPU particles transform is attached to owner object
|
// GPU particles transform is attached to owner object
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupGeomGpu(object: MeshObject, owner: MeshObject) {
|
function setupGeomGpu(object: MeshObject, owner: MeshObject) {
|
||||||
var instancedData = new Float32Array(particles.length * 6);
|
var instancedData = new Float32Array(particles.length * 3);
|
||||||
var i = 0;
|
var i = 0;
|
||||||
|
|
||||||
var normFactor = 1 / 32767; // pa.values are not normalized
|
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 ] * normFactor * scaleFactor.x); i++;
|
||||||
instancedData.set(i, pa.values[j * pa.size + 1] * normFactor * scaleFactor.y); i++;
|
instancedData.set(i, pa.values[j * pa.size + 1] * normFactor * scaleFactor.y); i++;
|
||||||
instancedData.set(i, pa.values[j * pa.size + 2] * normFactor * scaleFactor.z); i++;
|
instancedData.set(i, pa.values[j * pa.size + 2] * normFactor * scaleFactor.z); i++;
|
||||||
|
|
||||||
instancedData.set(i, p.sr); i++;
|
|
||||||
instancedData.set(i, p.sr); i++;
|
|
||||||
instancedData.set(i, p.sr); i++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case 1: // Face
|
case 1: // Face
|
||||||
@ -196,10 +243,6 @@ class ParticleSystem {
|
|||||||
instancedData.set(i, pos.x * normFactor * scaleFactor.x); i++;
|
instancedData.set(i, pos.x * normFactor * scaleFactor.x); i++;
|
||||||
instancedData.set(i, pos.y * normFactor * scaleFactor.y); i++;
|
instancedData.set(i, pos.y * normFactor * scaleFactor.y); i++;
|
||||||
instancedData.set(i, pos.z * normFactor * scaleFactor.z); i++;
|
instancedData.set(i, pos.z * normFactor * scaleFactor.z); i++;
|
||||||
|
|
||||||
instancedData.set(i, p.sr); i++;
|
|
||||||
instancedData.set(i, p.sr); i++;
|
|
||||||
instancedData.set(i, p.sr); i++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case 2: // Volume
|
case 2: // Volume
|
||||||
@ -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.x); i++;
|
||||||
instancedData.set(i, (Math.random() * 2.0 - 1.0) * scaleFactorVolume.y); i++;
|
instancedData.set(i, (Math.random() * 2.0 - 1.0) * scaleFactorVolume.y); i++;
|
||||||
instancedData.set(i, (Math.random() * 2.0 - 1.0) * scaleFactorVolume.z); i++;
|
instancedData.set(i, (Math.random() * 2.0 - 1.0) * scaleFactorVolume.z); i++;
|
||||||
|
|
||||||
instancedData.set(i, p.sr); i++;
|
|
||||||
instancedData.set(i, p.sr); i++;
|
|
||||||
instancedData.set(i, p.sr); i++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
object.data.geom.setupInstanced(instancedData, 3, Usage.StaticUsage);
|
object.data.geom.setupInstanced(instancedData, 1, Usage.StaticUsage);
|
||||||
}
|
}
|
||||||
|
|
||||||
function fhash(n: Int): Float {
|
function fhash(n: Int): Float {
|
||||||
@ -255,10 +294,11 @@ class ParticleSystem {
|
|||||||
|
|
||||||
class Particle {
|
class Particle {
|
||||||
public var i: Int;
|
public var i: Int;
|
||||||
public var px = 0.0;
|
|
||||||
public var py = 0.0;
|
public var x = 0.0;
|
||||||
public var pz = 0.0;
|
public var y = 0.0;
|
||||||
public var sr = 1.0; // Size random
|
public var z = 0.0;
|
||||||
|
|
||||||
public var cameraDistance: Float;
|
public var cameraDistance: Float;
|
||||||
|
|
||||||
public function new(i: Int) {
|
public function new(i: Int) {
|
||||||
|
@ -80,7 +80,7 @@ class Tilesheet {
|
|||||||
function update() {
|
function update() {
|
||||||
if (!ready || paused || action.start >= action.end) return;
|
if (!ready || paused || action.start >= action.end) return;
|
||||||
|
|
||||||
time += Time.realDelta;
|
time += Time.renderDelta;
|
||||||
|
|
||||||
var frameTime = 1 / raw.framerate;
|
var frameTime = 1 / raw.framerate;
|
||||||
var framesToAdvance = 0;
|
var framesToAdvance = 0;
|
||||||
|
@ -1109,6 +1109,26 @@ class Uniforms {
|
|||||||
case "_texUnpack": {
|
case "_texUnpack": {
|
||||||
f = texUnpack != null ? texUnpack : 1.0;
|
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) {
|
if (f == null && externalFloatLinks != null) {
|
||||||
|
@ -1,6 +1,12 @@
|
|||||||
package iron.system;
|
package iron.system;
|
||||||
|
|
||||||
class Time {
|
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;
|
public static var step(get, never): Float;
|
||||||
static function get_step(): Float {
|
static function get_step(): Float {
|
||||||
@ -8,30 +14,45 @@ class Time {
|
|||||||
return 1 / frequency;
|
return 1 / frequency;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static var scale = 1.0;
|
static var _fixedStep: Null<Float>;
|
||||||
public static var delta(get, never): Float;
|
public static var fixedStep(get, never): Float;
|
||||||
static function get_delta(): Float {
|
static function get_fixedStep(): Float {
|
||||||
if (frequency == null) initFrequency();
|
return _fixedStep;
|
||||||
return (1 / frequency) * scale;
|
}
|
||||||
|
|
||||||
|
public static function initFixedStep(value: Float = 1 / 60) {
|
||||||
|
_fixedStep = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
static var last = 0.0;
|
|
||||||
public static var realDelta = 0.0;
|
|
||||||
public static inline function time(): Float {
|
public static inline function time(): Float {
|
||||||
return kha.Scheduler.time();
|
return kha.Scheduler.time();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static inline function realTime(): Float {
|
public static inline function realTime(): Float {
|
||||||
return kha.Scheduler.realTime();
|
return kha.Scheduler.realTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
static var frequency: Null<Int> = null;
|
public static function update() {
|
||||||
|
_delta = realTime() - lastTime;
|
||||||
static function initFrequency() {
|
lastTime = realTime();
|
||||||
frequency = kha.Display.primary != null ? kha.Display.primary.frequency : 60;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function update() {
|
public static function render() {
|
||||||
realDelta = realTime() - last;
|
_renderDelta = realTime() - lastRenderTime;
|
||||||
last = realTime();
|
lastRenderTime = realTime();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
52
leenkx/Sources/iron/system/VR.hx
Normal file
52
leenkx/Sources/iron/system/VR.hx
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
package iron.system;
|
||||||
|
|
||||||
|
import iron.math.Mat4;
|
||||||
|
|
||||||
|
#if lnx_vr
|
||||||
|
class VR {
|
||||||
|
|
||||||
|
static var undistortionMatrix: Mat4 = null;
|
||||||
|
|
||||||
|
public function new() {}
|
||||||
|
|
||||||
|
public static function getUndistortionMatrix(): Mat4 {
|
||||||
|
if (undistortionMatrix == null) {
|
||||||
|
undistortionMatrix = Mat4.identity();
|
||||||
|
}
|
||||||
|
|
||||||
|
return undistortionMatrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getMaxRadiusSq(): Float {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function initButton() {
|
||||||
|
function vrDownListener(index: Int, x: Float, y: Float) {
|
||||||
|
var vr = kha.vr.VrInterface.instance;
|
||||||
|
if (vr == null || !vr.IsVrEnabled() || vr.IsPresenting()) return;
|
||||||
|
var w: Float = iron.App.w();
|
||||||
|
var h: Float = iron.App.h();
|
||||||
|
if (x < w - 150 || y < h - 150) return;
|
||||||
|
vr.onVRRequestPresent();
|
||||||
|
}
|
||||||
|
|
||||||
|
function vrRender2D(g: kha.graphics2.Graphics) {
|
||||||
|
var vr = kha.vr.VrInterface.instance;
|
||||||
|
if (vr == null || !vr.IsVrEnabled() || vr.IsPresenting()) return;
|
||||||
|
var w: Float = iron.App.w();
|
||||||
|
var h: Float = iron.App.h();
|
||||||
|
g.color = 0xffff0000;
|
||||||
|
g.fillRect(w - 150, h - 150, 140, 140);
|
||||||
|
}
|
||||||
|
|
||||||
|
kha.input.Mouse.get().notify(vrDownListener, null, null, null);
|
||||||
|
iron.App.notifyOnRender2D(vrRender2D);
|
||||||
|
|
||||||
|
var vr = kha.vr.VrInterface.instance; // Straight to VR (Oculus Carmel)
|
||||||
|
if (vr != null && vr.IsVrEnabled()) {
|
||||||
|
vr.onVRRequestPresent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#end
|
@ -20,6 +20,7 @@ class Config {
|
|||||||
var path = iron.data.Data.dataPath + "config.lnx";
|
var path = iron.data.Data.dataPath + "config.lnx";
|
||||||
var bytes = haxe.io.Bytes.ofString(haxe.Json.stringify(raw));
|
var bytes = haxe.io.Bytes.ofString(haxe.Json.stringify(raw));
|
||||||
#if kha_krom
|
#if kha_krom
|
||||||
|
if (iron.data.Data.dataPath == '') path = Krom.getFilesLocation() + "/config.lnx";
|
||||||
Krom.fileSaveBytes(path, bytes.getData());
|
Krom.fileSaveBytes(path, bytes.getData());
|
||||||
#elseif kha_kore
|
#elseif kha_kore
|
||||||
sys.io.File.saveBytes(path, bytes);
|
sys.io.File.saveBytes(path, bytes);
|
||||||
@ -47,6 +48,7 @@ typedef TConfig = {
|
|||||||
@:optional var rp_ssr: Null<Bool>;
|
@:optional var rp_ssr: Null<Bool>;
|
||||||
@:optional var rp_ssrefr: Null<Bool>;
|
@:optional var rp_ssrefr: Null<Bool>;
|
||||||
@:optional var rp_bloom: Null<Bool>;
|
@:optional var rp_bloom: Null<Bool>;
|
||||||
|
@:optional var rp_chromatic_aberration: Null<Bool>;
|
||||||
@:optional var rp_motionblur: Null<Bool>;
|
@:optional var rp_motionblur: Null<Bool>;
|
||||||
@:optional var rp_gi: Null<Bool>; // voxelao
|
@:optional var rp_gi: Null<Bool>; // voxelao
|
||||||
@:optional var rp_dynres: Null<Bool>; // dynamic resolution scaling
|
@: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);
|
||||||
|
}
|
||||||
|
}
|
@ -2,25 +2,48 @@ package leenkx.logicnode;
|
|||||||
|
|
||||||
class CameraSetNode extends LogicNode {
|
class CameraSetNode extends LogicNode {
|
||||||
|
|
||||||
|
public var property0: String;
|
||||||
|
|
||||||
public function new(tree:LogicTree) {
|
public function new(tree:LogicTree) {
|
||||||
super(tree);
|
super(tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
override function run(from:Int) {
|
override function run(from:Int) {
|
||||||
|
|
||||||
|
switch (property0) {
|
||||||
|
case 'F-stop':
|
||||||
leenkx.renderpath.Postprocess.camera_uniforms[0] = inputs[1].get();//Camera: F-Number
|
leenkx.renderpath.Postprocess.camera_uniforms[0] = inputs[1].get();//Camera: F-Number
|
||||||
leenkx.renderpath.Postprocess.camera_uniforms[1] = inputs[2].get();//Camera: Shutter time
|
case 'Shutter Time':
|
||||||
leenkx.renderpath.Postprocess.camera_uniforms[2] = inputs[3].get();//Camera: ISO
|
leenkx.renderpath.Postprocess.camera_uniforms[1] = inputs[1].get();//Camera: Shutter time
|
||||||
leenkx.renderpath.Postprocess.camera_uniforms[3] = inputs[4].get();//Camera: Exposure Compensation
|
case 'ISO':
|
||||||
leenkx.renderpath.Postprocess.camera_uniforms[4] = inputs[5].get();//Fisheye Distortion
|
leenkx.renderpath.Postprocess.camera_uniforms[2] = inputs[1].get();//Camera: ISO
|
||||||
leenkx.renderpath.Postprocess.camera_uniforms[5] = inputs[6].get();//DoF AutoFocus §§ If true, it ignores the DoF Distance setting
|
case 'Exposure Compensation':
|
||||||
leenkx.renderpath.Postprocess.camera_uniforms[6] = inputs[7].get();//DoF Distance
|
leenkx.renderpath.Postprocess.camera_uniforms[3] = inputs[1].get();//Camera: Exposure Compensation
|
||||||
leenkx.renderpath.Postprocess.camera_uniforms[7] = inputs[8].get();//DoF Focal Length mm
|
case 'Fisheye Distortion':
|
||||||
leenkx.renderpath.Postprocess.camera_uniforms[8] = inputs[9].get();//DoF F-Stop
|
leenkx.renderpath.Postprocess.camera_uniforms[4] = inputs[1].get();//Fisheye Distortion
|
||||||
leenkx.renderpath.Postprocess.camera_uniforms[9] = inputs[10].get();//Tonemapping Method
|
case 'Auto Focus':
|
||||||
leenkx.renderpath.Postprocess.camera_uniforms[10] = inputs[11].get();//Distort
|
leenkx.renderpath.Postprocess.camera_uniforms[5] = inputs[1].get();//DoF AutoFocus §§ If true, it ignores the DoF Distance setting
|
||||||
leenkx.renderpath.Postprocess.camera_uniforms[11] = inputs[12].get();//Film Grain
|
case 'DoF Distance':
|
||||||
leenkx.renderpath.Postprocess.camera_uniforms[12] = inputs[13].get();//Sharpen
|
leenkx.renderpath.Postprocess.camera_uniforms[6] = inputs[1].get();//DoF Distance
|
||||||
leenkx.renderpath.Postprocess.camera_uniforms[13] = inputs[14].get();//Vignette
|
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);
|
runOutput(0);
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ class ChromaticAberrationGetNode extends LogicNode {
|
|||||||
return switch (from) {
|
return switch (from) {
|
||||||
case 0: leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[0];
|
case 0: leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[0];
|
||||||
case 1: leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[1];
|
case 1: leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[1];
|
||||||
|
case 2: leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[2];
|
||||||
default: 0.0;
|
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[0] = inputs[1].get();
|
||||||
leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[1] = inputs[2].get();
|
leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[1] = inputs[2].get();
|
||||||
|
leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[2] = inputs[3].get();
|
||||||
|
|
||||||
runOutput(0);
|
runOutput(0);
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,9 @@ package leenkx.logicnode;
|
|||||||
|
|
||||||
import iron.Scene;
|
import iron.Scene;
|
||||||
import iron.object.CameraObject;
|
import iron.object.CameraObject;
|
||||||
|
import iron.math.Vec4;
|
||||||
|
import iron.math.Quat;
|
||||||
|
import leenkx.math.Helper;
|
||||||
|
|
||||||
import leenkx.renderpath.RenderPathCreator;
|
import leenkx.renderpath.RenderPathCreator;
|
||||||
|
|
||||||
@ -27,11 +30,19 @@ class DrawCameraTextureNode extends LogicNode {
|
|||||||
final c = inputs[2].get();
|
final c = inputs[2].get();
|
||||||
assert(Error, Std.isOfType(c, CameraObject), "Camera must be a camera object!");
|
assert(Error, Std.isOfType(c, CameraObject), "Camera must be a camera object!");
|
||||||
cam = cast(c, CameraObject);
|
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');
|
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);
|
tree.notifyOnRender(render);
|
||||||
runOutput(0);
|
runOutput(0);
|
||||||
|
|
||||||
@ -48,8 +59,20 @@ class DrawCameraTextureNode extends LogicNode {
|
|||||||
iron.Scene.active.camera = cam;
|
iron.Scene.active.camera = cam;
|
||||||
cam.renderTarget = rt;
|
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);
|
cam.renderFrame(g);
|
||||||
|
|
||||||
|
#if kha_html5
|
||||||
|
cam.transform.rot.mult(q);
|
||||||
|
cam.transform.buildMatrix();
|
||||||
|
#end
|
||||||
|
|
||||||
cam.renderTarget = oldRT;
|
cam.renderTarget = oldRT;
|
||||||
iron.Scene.active.camera = sceneCam;
|
iron.Scene.active.camera = sceneCam;
|
||||||
}
|
}
|
||||||
|
@ -99,8 +99,6 @@ class DrawImageSequenceNode extends LogicNode {
|
|||||||
final colorVec = inputs[4].get();
|
final colorVec = inputs[4].get();
|
||||||
g.color = Color.fromFloats(colorVec.x, colorVec.y, colorVec.z, colorVec.w);
|
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());
|
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);
|
||||||
|
}
|
||||||
|
}
|
17
leenkx/Sources/leenkx/logicnode/GetAudioPositionNode.hx
Normal file
17
leenkx/Sources/leenkx/logicnode/GetAudioPositionNode.hx
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package leenkx.logicnode;
|
||||||
|
|
||||||
|
import aura.Aura;
|
||||||
|
import aura.Types;
|
||||||
|
|
||||||
|
class GetAudioPositionNode extends LogicNode {
|
||||||
|
|
||||||
|
public function new(tree: LogicTree) {
|
||||||
|
super(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
override function get(from: Int): Dynamic {
|
||||||
|
var audio = inputs[0].get();
|
||||||
|
if (audio == null || audio.channel == null) return 0.0;
|
||||||
|
return audio.channel.floatPosition / audio.channel.sampleRate;
|
||||||
|
}
|
||||||
|
}
|
19
leenkx/Sources/leenkx/logicnode/GetCameraRenderFilterNode.hx
Normal file
19
leenkx/Sources/leenkx/logicnode/GetCameraRenderFilterNode.hx
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package leenkx.logicnode;
|
||||||
|
|
||||||
|
import iron.object.MeshObject;
|
||||||
|
import iron.object.CameraObject;
|
||||||
|
|
||||||
|
class GetCameraRenderFilterNode extends LogicNode {
|
||||||
|
|
||||||
|
public function new(tree: LogicTree) {
|
||||||
|
super(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
override function get(from: Int): Dynamic {
|
||||||
|
var mo: MeshObject = cast inputs[0].get();
|
||||||
|
|
||||||
|
if (mo == null) return null;
|
||||||
|
|
||||||
|
return mo.cameraList;
|
||||||
|
}
|
||||||
|
}
|
@ -8,7 +8,7 @@ class GetFPSNode extends LogicNode {
|
|||||||
|
|
||||||
override function get(from: Int): Dynamic {
|
override function get(from: Int): Dynamic {
|
||||||
if (from == 0) {
|
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))) {
|
if ((fps == Math.POSITIVE_INFINITY) || (fps == Math.NEGATIVE_INFINITY) || (Math.isNaN(fps))) {
|
||||||
return 0;
|
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;
|
||||||
|
}
|
||||||
|
}
|
33
leenkx/Sources/leenkx/logicnode/GetPositionSpeakerNode.hx
Normal file
33
leenkx/Sources/leenkx/logicnode/GetPositionSpeakerNode.hx
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package leenkx.logicnode;
|
||||||
|
|
||||||
|
#if lnx_audio
|
||||||
|
import iron.object.SpeakerObject;
|
||||||
|
import kha.audio1.AudioChannel;
|
||||||
|
#end
|
||||||
|
|
||||||
|
class GetPositionSpeakerNode extends LogicNode {
|
||||||
|
|
||||||
|
public function new(tree: LogicTree) {
|
||||||
|
super(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
override function get(from: Int): Dynamic {
|
||||||
|
#if lnx_audio
|
||||||
|
var object: SpeakerObject = cast(inputs[0].get(), SpeakerObject);
|
||||||
|
if (object == null || object.sound == null) return 0.0;
|
||||||
|
|
||||||
|
if (object.channels.length == 0) return 0.0;
|
||||||
|
|
||||||
|
var channel = object.channels[0];
|
||||||
|
|
||||||
|
var position = 0.0;
|
||||||
|
if (channel != null) {
|
||||||
|
position = @:privateAccess channel.get_position();
|
||||||
|
}
|
||||||
|
|
||||||
|
return position;
|
||||||
|
#else
|
||||||
|
return 0.0;
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
}
|
@ -1,26 +1,12 @@
|
|||||||
package leenkx.logicnode;
|
package leenkx.logicnode;
|
||||||
|
|
||||||
import iron.object.Object;
|
|
||||||
import iron.math.Vec4;
|
|
||||||
|
|
||||||
class GetWorldNode extends LogicNode {
|
class GetWorldNode extends LogicNode {
|
||||||
|
|
||||||
public var property0: String;
|
|
||||||
|
|
||||||
public function new(tree: LogicTree) {
|
public function new(tree: LogicTree) {
|
||||||
super(tree);
|
super(tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
override function get(from: Int): Dynamic {
|
override function get(from: Int): Dynamic {
|
||||||
var object: Object = inputs[0].get();
|
return iron.Scene.active.raw.world_ref;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
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 GetWorldOrientationNode extends LogicNode {
|
||||||
|
|
||||||
|
public var property0: String;
|
||||||
|
|
||||||
|
public function new(tree: LogicTree) {
|
||||||
|
super(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
override function get(from: Int): Dynamic {
|
||||||
|
var object: Object = inputs[0].get();
|
||||||
|
|
||||||
|
if (object == null) return null;
|
||||||
|
|
||||||
|
return switch (property0) {
|
||||||
|
case "Right": object.transform.world.right();
|
||||||
|
case "Look": object.transform.world.look();
|
||||||
|
case "Up": object.transform.world.up();
|
||||||
|
default: null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
232
leenkx/Sources/leenkx/logicnode/MouseLookNode.hx
Normal file
232
leenkx/Sources/leenkx/logicnode/MouseLookNode.hx
Normal file
@ -0,0 +1,232 @@
|
|||||||
|
package leenkx.logicnode;
|
||||||
|
|
||||||
|
import iron.math.Vec4;
|
||||||
|
import iron.system.Input;
|
||||||
|
import iron.object.Object;
|
||||||
|
import kha.System;
|
||||||
|
import kha.FastFloat;
|
||||||
|
|
||||||
|
class MouseLookNode extends LogicNode {
|
||||||
|
// Note: This implementation works in degrees internally and converts to radians only when applying rotations
|
||||||
|
// Sub-pixel interpolation is always enabled for optimal precision
|
||||||
|
// Features: Resolution-adaptive scaling and precise low-sensitivity support
|
||||||
|
|
||||||
|
public var property0: String; // Front axis
|
||||||
|
public var property1: Bool; // Center Mouse
|
||||||
|
public var property2: Bool; // Invert X
|
||||||
|
public var property3: Bool; // Invert Y
|
||||||
|
public var property4: Bool; // Cap Left/Right
|
||||||
|
public var property5: Bool; // Cap Up/Down
|
||||||
|
|
||||||
|
// New strategy toggles
|
||||||
|
public var property6: Bool; // Resolution-Adaptive Scaling
|
||||||
|
|
||||||
|
// Smoothing variables
|
||||||
|
var smoothX: FastFloat = 0.0;
|
||||||
|
var smoothY: FastFloat = 0.0;
|
||||||
|
|
||||||
|
// Capping limits (in degrees)
|
||||||
|
var maxHorizontal: FastFloat = 180.0; // 180 degrees
|
||||||
|
var maxVertical: FastFloat = 90.0; // 90 degrees
|
||||||
|
|
||||||
|
// Current accumulated rotations for capping
|
||||||
|
var currentHorizontal: FastFloat = 0.0;
|
||||||
|
var currentVertical: FastFloat = 0.0;
|
||||||
|
|
||||||
|
// Sub-pixel interpolation accumulators
|
||||||
|
var accumulatedHorizontalRotation: FastFloat = 0.0;
|
||||||
|
var accumulatedVerticalRotation: FastFloat = 0.0;
|
||||||
|
var minimumRotationThreshold: FastFloat = 0.01; // degrees (was 0.0001 radians)
|
||||||
|
|
||||||
|
// Frame rate independence removed - not applicable to mouse input
|
||||||
|
|
||||||
|
// Resolution adaptive scaling
|
||||||
|
var baseResolutionWidth: FastFloat = 1920.0;
|
||||||
|
var baseResolutionHeight: FastFloat = 1080.0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public function new(tree: LogicTree) {
|
||||||
|
super(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
override function run(from: Int) {
|
||||||
|
var bodyObject: Object = inputs[1].get();
|
||||||
|
var headObject: Object = inputs[2].get();
|
||||||
|
var sensitivity: FastFloat = inputs[3].get();
|
||||||
|
var smoothing: FastFloat = inputs[4].get();
|
||||||
|
|
||||||
|
if (bodyObject == null) {
|
||||||
|
runOutput(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var mouse = Input.getMouse();
|
||||||
|
|
||||||
|
// Handle mouse centering/locking
|
||||||
|
if (property1) {
|
||||||
|
if (mouse.started() && !mouse.locked) {
|
||||||
|
mouse.lock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only process if mouse is active
|
||||||
|
if (!mouse.locked && !mouse.down()) {
|
||||||
|
runOutput(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get mouse movement deltas
|
||||||
|
var deltaX: FastFloat = mouse.movementX;
|
||||||
|
var deltaY: FastFloat = mouse.movementY;
|
||||||
|
|
||||||
|
// Note: Sensitivity will be applied later to preserve precision for small movements
|
||||||
|
|
||||||
|
// Apply inversion
|
||||||
|
if (property2) deltaX = -deltaX;
|
||||||
|
if (property3) deltaY = -deltaY;
|
||||||
|
|
||||||
|
// Strategy 1: Resolution-Adaptive Scaling
|
||||||
|
var resolutionMultiplier: FastFloat = 1.0;
|
||||||
|
if (property6) {
|
||||||
|
var currentWidth = System.windowWidth();
|
||||||
|
var currentHeight = System.windowHeight();
|
||||||
|
resolutionMultiplier = (currentWidth / baseResolutionWidth) * (currentHeight / baseResolutionHeight);
|
||||||
|
resolutionMultiplier = Math.sqrt(resolutionMultiplier); // Take square root to avoid over-scaling
|
||||||
|
}
|
||||||
|
|
||||||
|
// Frame Rate Independence disabled for mouse input - mouse deltas are inherently frame-rate independent
|
||||||
|
|
||||||
|
// Apply smoothing
|
||||||
|
if (smoothing > 0.0) {
|
||||||
|
var smoothFactor = 1.0 - Math.min(smoothing, 0.99); // Prevent complete smoothing
|
||||||
|
smoothX = smoothX * smoothing + deltaX * smoothFactor;
|
||||||
|
smoothY = smoothY * smoothing + deltaY * smoothFactor;
|
||||||
|
deltaX = smoothX;
|
||||||
|
deltaY = smoothY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine rotation axes based on front axis setting
|
||||||
|
var horizontalAxis = new Vec4();
|
||||||
|
var verticalAxis = new Vec4();
|
||||||
|
|
||||||
|
switch (property0) {
|
||||||
|
case "X": // X is front
|
||||||
|
horizontalAxis.set(0, 0, 1); // Z axis for horizontal (yaw)
|
||||||
|
verticalAxis.set(0, 1, 0); // Y axis for vertical (pitch)
|
||||||
|
case "Y": // Y is front (default)
|
||||||
|
#if lnx_yaxisup
|
||||||
|
horizontalAxis.set(0, 0, 1); // Z axis for horizontal (yaw)
|
||||||
|
verticalAxis.set(1, 0, 0); // X axis for vertical (pitch)
|
||||||
|
#else
|
||||||
|
horizontalAxis.set(0, 0, 1); // Z axis for horizontal (yaw)
|
||||||
|
verticalAxis.set(1, 0, 0); // X axis for vertical (pitch)
|
||||||
|
#end
|
||||||
|
case "Z": // Z is front
|
||||||
|
horizontalAxis.set(0, 1, 0); // Y axis for horizontal (yaw)
|
||||||
|
verticalAxis.set(1, 0, 0); // X axis for vertical (pitch)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Base scaling
|
||||||
|
var baseScale: FastFloat = 1500.0;
|
||||||
|
var finalScale = baseScale;
|
||||||
|
|
||||||
|
// Apply resolution scaling
|
||||||
|
if (property6) {
|
||||||
|
finalScale *= resolutionMultiplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Apply sensitivity scaling after all enhancement strategies to preserve precision
|
||||||
|
deltaX *= sensitivity;
|
||||||
|
deltaY *= sensitivity;
|
||||||
|
|
||||||
|
// Calculate rotation amounts (in degrees)
|
||||||
|
var horizontalRotation: FastFloat = (-deltaX / finalScale) * 180.0 / Math.PI;
|
||||||
|
var verticalRotation: FastFloat = (-deltaY / finalScale) * 180.0 / Math.PI;
|
||||||
|
|
||||||
|
// Note: Frame rate independence removed for mouse input as mouse deltas
|
||||||
|
// are already frame-rate independent by nature. Mouse input represents
|
||||||
|
// instantaneous user intent, not time-based movement.
|
||||||
|
|
||||||
|
// Strategy 2: Sub-Pixel Interpolation (always enabled)
|
||||||
|
accumulatedHorizontalRotation += horizontalRotation;
|
||||||
|
accumulatedVerticalRotation += verticalRotation;
|
||||||
|
|
||||||
|
// Only apply rotation if accumulated amount exceeds threshold
|
||||||
|
if (Math.abs(accumulatedHorizontalRotation) >= minimumRotationThreshold) {
|
||||||
|
horizontalRotation = accumulatedHorizontalRotation;
|
||||||
|
accumulatedHorizontalRotation = 0.0;
|
||||||
|
} else {
|
||||||
|
horizontalRotation = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Math.abs(accumulatedVerticalRotation) >= minimumRotationThreshold) {
|
||||||
|
verticalRotation = accumulatedVerticalRotation;
|
||||||
|
accumulatedVerticalRotation = 0.0;
|
||||||
|
} else {
|
||||||
|
verticalRotation = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply capping constraints
|
||||||
|
if (property4) { // Cap Left/Right
|
||||||
|
currentHorizontal += horizontalRotation;
|
||||||
|
if (currentHorizontal > maxHorizontal) {
|
||||||
|
horizontalRotation -= (currentHorizontal - maxHorizontal);
|
||||||
|
currentHorizontal = maxHorizontal;
|
||||||
|
} else if (currentHorizontal < -maxHorizontal) {
|
||||||
|
horizontalRotation -= (currentHorizontal + maxHorizontal);
|
||||||
|
currentHorizontal = -maxHorizontal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (property5) { // Cap Up/Down
|
||||||
|
currentVertical += verticalRotation;
|
||||||
|
if (currentVertical > maxVertical) {
|
||||||
|
verticalRotation -= (currentVertical - maxVertical);
|
||||||
|
currentVertical = maxVertical;
|
||||||
|
} else if (currentVertical < -maxVertical) {
|
||||||
|
verticalRotation -= (currentVertical + maxVertical);
|
||||||
|
currentVertical = -maxVertical;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply horizontal rotation to body (yaw)
|
||||||
|
if (Math.abs(horizontalRotation) > 0.01) { // 0.01 degrees threshold
|
||||||
|
bodyObject.transform.rotate(horizontalAxis, horizontalRotation * Math.PI / 180.0); // Convert degrees to radians
|
||||||
|
|
||||||
|
// Sync physics if needed
|
||||||
|
#if lnx_physics
|
||||||
|
var rigidBody = bodyObject.getTrait(leenkx.trait.physics.RigidBody);
|
||||||
|
if (rigidBody != null) rigidBody.syncTransform();
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply vertical rotation to head (pitch) if head object is provided
|
||||||
|
if (headObject != null && Math.abs(verticalRotation) > 0.01) { // 0.01 degrees threshold
|
||||||
|
// For head rotation, use the head's local coordinate system
|
||||||
|
var headVerticalAxis = headObject.transform.world.right();
|
||||||
|
headObject.transform.rotate(headVerticalAxis, verticalRotation * Math.PI / 180.0); // Convert degrees to radians
|
||||||
|
|
||||||
|
// Sync physics if needed
|
||||||
|
#if lnx_physics
|
||||||
|
var headRigidBody = headObject.getTrait(leenkx.trait.physics.RigidBody);
|
||||||
|
if (headRigidBody != null) headRigidBody.syncTransform();
|
||||||
|
#end
|
||||||
|
} else if (headObject == null) {
|
||||||
|
// If no head object, apply vertical rotation to body as well
|
||||||
|
if (Math.abs(verticalRotation) > 0.01) { // 0.01 degrees threshold
|
||||||
|
bodyObject.transform.rotate(verticalAxis, verticalRotation * Math.PI / 180.0); // Convert degrees to radians
|
||||||
|
|
||||||
|
// Sync physics if needed
|
||||||
|
#if lnx_physics
|
||||||
|
var rigidBody = bodyObject.getTrait(leenkx.trait.physics.RigidBody);
|
||||||
|
if (rigidBody != null) rigidBody.syncTransform();
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
runOutput(0);
|
||||||
|
}
|
||||||
|
}
|
@ -9,19 +9,38 @@ import iron.Scene;
|
|||||||
|
|
||||||
class PlayAnimationTreeNode extends LogicNode {
|
class PlayAnimationTreeNode extends LogicNode {
|
||||||
|
|
||||||
|
var object: Object;
|
||||||
|
var action: Dynamic;
|
||||||
|
var init: Bool = false;
|
||||||
|
|
||||||
public function new(tree: LogicTree) {
|
public function new(tree: LogicTree) {
|
||||||
super(tree);
|
super(tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
override function run(from: Int) {
|
override function run(from: Int) {
|
||||||
var object: Object = inputs[1].get();
|
object = inputs[1].get();
|
||||||
var action: Dynamic = inputs[2].get();
|
action = inputs[2].get();
|
||||||
|
|
||||||
assert(Error, object != null, "The object input not be null");
|
assert(Error, object != null, "The object input not be null");
|
||||||
|
init = true;
|
||||||
|
tree.notifyOnUpdate(playAnim);
|
||||||
|
// TO DO: Investigate AnimAction get and PlayAnimationTree notifiers
|
||||||
|
}
|
||||||
|
|
||||||
|
function playAnim() {
|
||||||
|
if (init = false) return;
|
||||||
|
|
||||||
|
init = false;
|
||||||
|
tree.removeUpdate(playAnim);
|
||||||
|
|
||||||
var animation = object.animation;
|
var animation = object.animation;
|
||||||
if(animation == null) {
|
if(animation == null) {
|
||||||
#if lnx_skin
|
#if lnx_skin
|
||||||
animation = object.getBoneAnimation(object.uid);
|
animation = object.getBoneAnimation(object.uid);
|
||||||
|
if (animation == null) {
|
||||||
|
tree.notifyOnUpdate(playAnim);
|
||||||
|
init = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
cast(animation, BoneAnimation).setAnimationLoop(function f(mats) {
|
cast(animation, BoneAnimation).setAnimationLoop(function f(mats) {
|
||||||
action(mats);
|
action(mats);
|
||||||
});
|
});
|
||||||
@ -32,7 +51,6 @@ class PlayAnimationTreeNode extends LogicNode {
|
|||||||
action(mats);
|
action(mats);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
runOutput(0);
|
runOutput(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,6 @@ class ProbabilisticOutputNode extends LogicNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (sum > 1){
|
if (sum > 1){
|
||||||
trace(sum);
|
|
||||||
for (p in 0...probs.length)
|
for (p in 0...probs.length)
|
||||||
probs[p] /= sum;
|
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;
|
on ? leenkx.data.Config.raw.rp_ssrefr = true : leenkx.data.Config.raw.rp_ssrefr = false;
|
||||||
case "Bloom":
|
case "Bloom":
|
||||||
on ? leenkx.data.Config.raw.rp_bloom = true : leenkx.data.Config.raw.rp_bloom = false;
|
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":
|
case "GI":
|
||||||
on ? leenkx.data.Config.raw.rp_gi = true : leenkx.data.Config.raw.rp_gi = false;
|
on ? leenkx.data.Config.raw.rp_gi = true : leenkx.data.Config.raw.rp_gi = false;
|
||||||
case "Motion Blur":
|
case "Motion Blur":
|
||||||
|
23
leenkx/Sources/leenkx/logicnode/SetAudioPositionNode.hx
Normal file
23
leenkx/Sources/leenkx/logicnode/SetAudioPositionNode.hx
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package leenkx.logicnode;
|
||||||
|
|
||||||
|
import aura.Aura;
|
||||||
|
import aura.Types;
|
||||||
|
|
||||||
|
class SetAudioPositionNode extends LogicNode {
|
||||||
|
|
||||||
|
public function new(tree: LogicTree) {
|
||||||
|
super(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
override function run(from: Int) {
|
||||||
|
var audio = inputs[1].get();
|
||||||
|
if (audio == null) return;
|
||||||
|
|
||||||
|
var positionInSeconds:Float = inputs[2].get();
|
||||||
|
if (positionInSeconds < 0.0) positionInSeconds = 0.0;
|
||||||
|
|
||||||
|
audio.channel.floatPosition = positionInSeconds * audio.channel.sampleRate;
|
||||||
|
|
||||||
|
runOutput(0);
|
||||||
|
}
|
||||||
|
}
|
38
leenkx/Sources/leenkx/logicnode/SetCameraRenderFilterNode.hx
Normal file
38
leenkx/Sources/leenkx/logicnode/SetCameraRenderFilterNode.hx
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
package leenkx.logicnode;
|
||||||
|
|
||||||
|
import iron.object.MeshObject;
|
||||||
|
import iron.object.CameraObject;
|
||||||
|
|
||||||
|
class SetCameraRenderFilterNode extends LogicNode {
|
||||||
|
|
||||||
|
public var property0: String;
|
||||||
|
|
||||||
|
public function new(tree: LogicTree) {
|
||||||
|
super(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
override function run(from: Int) {
|
||||||
|
var mo: MeshObject = cast inputs[1].get();
|
||||||
|
var camera: CameraObject = inputs[2].get();
|
||||||
|
|
||||||
|
assert(Error, Std.isOfType(camera, CameraObject), "Camera must be a camera object!");
|
||||||
|
|
||||||
|
if (camera == null || mo == null) return;
|
||||||
|
|
||||||
|
if (property0 == 'Add'){
|
||||||
|
if (mo.cameraList == null || mo.cameraList.indexOf(camera.name) == -1){
|
||||||
|
if (mo.cameraList == null) mo.cameraList = [];
|
||||||
|
mo.cameraList.push(camera.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if (mo.cameraList != null){
|
||||||
|
mo.cameraList.remove(camera.name);
|
||||||
|
if (mo.cameraList.length == 0)
|
||||||
|
mo.cameraList = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
runOutput(0);
|
||||||
|
}
|
||||||
|
}
|
21
leenkx/Sources/leenkx/logicnode/SetLightShadowNode.hx
Normal file
21
leenkx/Sources/leenkx/logicnode/SetLightShadowNode.hx
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package leenkx.logicnode;
|
||||||
|
|
||||||
|
import iron.object.LightObject;
|
||||||
|
|
||||||
|
class SetLightShadowNode extends LogicNode {
|
||||||
|
|
||||||
|
public function new(tree: LogicTree) {
|
||||||
|
super(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
override function run(from: Int) {
|
||||||
|
var light: LightObject = inputs[1].get();
|
||||||
|
var shadow: Bool = inputs[2].get();
|
||||||
|
|
||||||
|
if (light == null) return;
|
||||||
|
|
||||||
|
light.data.raw.cast_shadow = shadow;
|
||||||
|
|
||||||
|
runOutput(0);
|
||||||
|
}
|
||||||
|
}
|
206
leenkx/Sources/leenkx/logicnode/SetLookAtRotationNode.hx
Normal file
206
leenkx/Sources/leenkx/logicnode/SetLookAtRotationNode.hx
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
package leenkx.logicnode;
|
||||||
|
|
||||||
|
import iron.math.Vec4;
|
||||||
|
import iron.math.Quat;
|
||||||
|
import iron.math.Mat4;
|
||||||
|
import iron.object.Object;
|
||||||
|
|
||||||
|
class SetLookAtRotationNode extends LogicNode {
|
||||||
|
|
||||||
|
public var property0: String; // Axis to align
|
||||||
|
public var property1: String; // Use vector for target (true/false)
|
||||||
|
public var property2: String; // Use vector for source (true/false)
|
||||||
|
public var property3: String; // Damping value (backward compatibility, now input socket)
|
||||||
|
public var property4: String; // Disable rotation on aligning axis (true/false)
|
||||||
|
public var property5: String; // Use local space (true/false)
|
||||||
|
|
||||||
|
// Store the calculated rotation for output
|
||||||
|
var calculatedRotation: Quat = null;
|
||||||
|
// Store the previous rotation for smooth interpolation
|
||||||
|
var previousRotation: Quat = null;
|
||||||
|
|
||||||
|
public function new(tree: LogicTree) {
|
||||||
|
super(tree);
|
||||||
|
previousRotation = new Quat();
|
||||||
|
}
|
||||||
|
|
||||||
|
override function run(from: Int): Void {
|
||||||
|
// Determine if we're using a vector or an object as source
|
||||||
|
var useSourceVector: Bool = property2 == "true";
|
||||||
|
var objectToUse: Object = null;
|
||||||
|
var objectLoc: Vec4 = null;
|
||||||
|
|
||||||
|
if (useSourceVector) {
|
||||||
|
// Use tree.object as the object to rotate
|
||||||
|
objectToUse = tree.object;
|
||||||
|
if (objectToUse == null) {
|
||||||
|
runOutput(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the source location directly
|
||||||
|
objectLoc = inputs[1].get();
|
||||||
|
if (objectLoc == null) {
|
||||||
|
runOutput(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Get the source object (or fallback to tree.object)
|
||||||
|
objectToUse = (inputs.length > 1 && inputs[1] != null) ? inputs[1].get() : tree.object;
|
||||||
|
if (objectToUse == null) {
|
||||||
|
runOutput(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get source object's WORLD position (important for child objects)
|
||||||
|
objectLoc = new Vec4(objectToUse.transform.worldx(), objectToUse.transform.worldy(), objectToUse.transform.worldz());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine if we're using a vector or an object as target
|
||||||
|
var useTargetVector: Bool = property1 == "true";
|
||||||
|
var targetLoc: Vec4 = null;
|
||||||
|
|
||||||
|
if (useTargetVector) {
|
||||||
|
// Get the target location directly
|
||||||
|
targetLoc = inputs[2].get();
|
||||||
|
if (targetLoc == null) {
|
||||||
|
runOutput(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Get the target object
|
||||||
|
var targetObject: Object = inputs[2].get();
|
||||||
|
if (targetObject == null) {
|
||||||
|
runOutput(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get target object's WORLD position (important for child objects)
|
||||||
|
targetLoc = new Vec4(targetObject.transform.worldx(), targetObject.transform.worldy(), targetObject.transform.worldz());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate direction to target
|
||||||
|
var direction = new Vec4(
|
||||||
|
targetLoc.x - objectLoc.x,
|
||||||
|
targetLoc.y - objectLoc.y,
|
||||||
|
targetLoc.z - objectLoc.z
|
||||||
|
);
|
||||||
|
direction.normalize();
|
||||||
|
|
||||||
|
// Calculate target rotation based on selected axis
|
||||||
|
calculatedRotation = new Quat();
|
||||||
|
switch (property0) {
|
||||||
|
case "X":
|
||||||
|
calculatedRotation.fromTo(new Vec4(1, 0, 0), direction);
|
||||||
|
case "-X":
|
||||||
|
calculatedRotation.fromTo(new Vec4(-1, 0, 0), direction);
|
||||||
|
case "Y":
|
||||||
|
calculatedRotation.fromTo(new Vec4(0, 1, 0), direction);
|
||||||
|
case "-Y":
|
||||||
|
calculatedRotation.fromTo(new Vec4(0, -1, 0), direction);
|
||||||
|
case "Z":
|
||||||
|
calculatedRotation.fromTo(new Vec4(0, 0, 1), direction);
|
||||||
|
case "-Z":
|
||||||
|
calculatedRotation.fromTo(new Vec4(0, 0, -1), direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If disable rotation on aligning axis is enabled, constrain the target rotation
|
||||||
|
if (property4 == "true") {
|
||||||
|
// Apply constraint to the target rotation BEFORE damping to avoid jiggling
|
||||||
|
var eulerAngles = calculatedRotation.toEulerOrdered("XYZ");
|
||||||
|
|
||||||
|
// Set the rotation around the selected axis to 0
|
||||||
|
switch (property0) {
|
||||||
|
case "X", "-X":
|
||||||
|
eulerAngles.x = 0.0;
|
||||||
|
case "Y", "-Y":
|
||||||
|
eulerAngles.y = 0.0;
|
||||||
|
case "Z", "-Z":
|
||||||
|
eulerAngles.z = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert back to quaternion
|
||||||
|
calculatedRotation.fromEulerOrdered(eulerAngles, "XYZ");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert world rotation to local rotation if local space is enabled and object has a parent
|
||||||
|
var targetRotation = new Quat();
|
||||||
|
if (property5 == "true" && objectToUse.parent != null) {
|
||||||
|
// Get parent's world rotation
|
||||||
|
var parentWorldLoc = new Vec4();
|
||||||
|
var parentWorldRot = new Quat();
|
||||||
|
var parentWorldScale = new Vec4();
|
||||||
|
objectToUse.parent.transform.world.decompose(parentWorldLoc, parentWorldRot, parentWorldScale);
|
||||||
|
|
||||||
|
// Convert world rotation to local space by removing parent's rotation influence
|
||||||
|
// local_rotation = inverse(parent_world_rotation) * world_rotation
|
||||||
|
var invParentRot = new Quat().setFrom(parentWorldRot);
|
||||||
|
invParentRot.x = -invParentRot.x;
|
||||||
|
invParentRot.y = -invParentRot.y;
|
||||||
|
invParentRot.z = -invParentRot.z;
|
||||||
|
|
||||||
|
targetRotation.multquats(invParentRot, calculatedRotation);
|
||||||
|
} else {
|
||||||
|
// No local space conversion needed, use world rotation directly
|
||||||
|
targetRotation.setFrom(calculatedRotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply rotation with damping
|
||||||
|
var dampingValue: Float = 0.0;
|
||||||
|
|
||||||
|
// Try to get damping from input socket first (index 3), fallback to property
|
||||||
|
if (inputs.length > 3 && inputs[3] != null) {
|
||||||
|
var dampingInput: Dynamic = inputs[3].get();
|
||||||
|
if (dampingInput != null) {
|
||||||
|
dampingValue = dampingInput;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Fallback to property for backward compatibility
|
||||||
|
dampingValue = Std.parseFloat(property3);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dampingValue > 0.0) {
|
||||||
|
// Create a fixed interpolation rate that never reaches exactly 1.0
|
||||||
|
// Higher damping = slower rotation (smaller step)
|
||||||
|
var step = Math.max(0.001, (1.0 - dampingValue) * 0.2); // 0.001 to 0.2 range
|
||||||
|
|
||||||
|
// Get current local rotation as quaternion
|
||||||
|
var currentLocalRot = new Quat().setFrom(objectToUse.transform.rot);
|
||||||
|
|
||||||
|
// Calculate the difference between current and target rotation
|
||||||
|
var diffQuat = new Quat();
|
||||||
|
// q1 * inverse(q2) gives the rotation from q2 to q1
|
||||||
|
var invCurrent = new Quat().setFrom(currentLocalRot);
|
||||||
|
invCurrent.x = -invCurrent.x;
|
||||||
|
invCurrent.y = -invCurrent.y;
|
||||||
|
invCurrent.z = -invCurrent.z;
|
||||||
|
diffQuat.multquats(targetRotation, invCurrent);
|
||||||
|
|
||||||
|
// Convert to axis-angle representation
|
||||||
|
var axis = new Vec4();
|
||||||
|
var angle = diffQuat.toAxisAngle(axis);
|
||||||
|
|
||||||
|
// Apply only a portion of this rotation (step)
|
||||||
|
var partialAngle = angle * step;
|
||||||
|
|
||||||
|
// Create partial rotation quaternion
|
||||||
|
var partialRot = new Quat().fromAxisAngle(axis, partialAngle);
|
||||||
|
|
||||||
|
// Apply this partial rotation to current local rotation
|
||||||
|
var newLocalRot = new Quat();
|
||||||
|
newLocalRot.multquats(partialRot, currentLocalRot);
|
||||||
|
|
||||||
|
// Apply the new local rotation
|
||||||
|
objectToUse.transform.rot.setFrom(newLocalRot);
|
||||||
|
} else {
|
||||||
|
// No damping, apply instant rotation
|
||||||
|
objectToUse.transform.rot.setFrom(targetRotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
objectToUse.transform.buildMatrix();
|
||||||
|
|
||||||
|
runOutput(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// No output sockets needed - this node only performs actions
|
||||||
|
}
|
@ -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':
|
||||||
|
@:privateAccess psys.r.factor_random = inputs[3].get();
|
||||||
|
case 'Weight Gravity':
|
||||||
|
@:privateAccess psys.r.weight_gravity = inputs[3].get();
|
||||||
|
if (iron.Scene.active.raw.gravity != null) {
|
||||||
|
@:privateAccess psys.gx = iron.Scene.active.raw.gravity[0] * @:privateAccess psys.r.weight_gravity;
|
||||||
|
@:privateAccess psys.gy = iron.Scene.active.raw.gravity[1] * @:privateAccess psys.r.weight_gravity;
|
||||||
|
@:privateAccess psys.gz = iron.Scene.active.raw.gravity[2] * @:privateAccess psys.r.weight_gravity;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
@:privateAccess psys.gx = 0;
|
||||||
|
@:privateAccess psys.gy = 0;
|
||||||
|
@:privateAccess psys.gz = -9.81 * @:privateAccess psys.r.weight_gravity;
|
||||||
|
}
|
||||||
|
case 'Speed':
|
||||||
|
psys.speed = inputs[3].get();
|
||||||
|
default:
|
||||||
|
null;
|
||||||
|
}
|
||||||
|
|
||||||
|
#end
|
||||||
|
|
||||||
|
runOutput(0);
|
||||||
|
}
|
||||||
|
}
|
@ -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) {
|
override function run(from: Int) {
|
||||||
#if lnx_particles
|
#if lnx_particles
|
||||||
var object: Object = inputs[1].get();
|
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;
|
if (object == null) return;
|
||||||
|
|
||||||
var mo = cast(object, iron.object.MeshObject);
|
var mo = cast(object, iron.object.MeshObject);
|
||||||
var psys = mo.particleSystems.length > 0 ? mo.particleSystems[0] : null;
|
var psys = mo.particleSystems != null ? mo.particleSystems[slot] :
|
||||||
if (psys == null) mo.particleOwner.particleSystems[0];
|
mo.particleOwner != null && mo.particleOwner.particleSystems != null ? mo.particleOwner.particleSystems[slot] : null;
|
||||||
|
|
||||||
|
if (psys == null) return;
|
||||||
|
|
||||||
psys.speed = speed;
|
psys.speed = speed;
|
||||||
|
|
||||||
|
39
leenkx/Sources/leenkx/logicnode/SetPositionSpeakerNode.hx
Normal file
39
leenkx/Sources/leenkx/logicnode/SetPositionSpeakerNode.hx
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
package leenkx.logicnode;
|
||||||
|
|
||||||
|
#if lnx_audio
|
||||||
|
import iron.object.SpeakerObject;
|
||||||
|
import kha.audio1.AudioChannel;
|
||||||
|
import iron.system.Audio;
|
||||||
|
#end
|
||||||
|
|
||||||
|
class SetPositionSpeakerNode extends LogicNode {
|
||||||
|
|
||||||
|
public function new(tree: LogicTree) {
|
||||||
|
super(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
override function run(from: Int) {
|
||||||
|
#if lnx_audio
|
||||||
|
var object: SpeakerObject = cast(inputs[1].get(), SpeakerObject);
|
||||||
|
if (object == null || object.sound == null) return;
|
||||||
|
|
||||||
|
var positionInSeconds:Float = inputs[2].get();
|
||||||
|
if (positionInSeconds < 0) positionInSeconds = 0;
|
||||||
|
|
||||||
|
var volume = object.data.volume;
|
||||||
|
var loop = object.data.loop;
|
||||||
|
var stream = object.data.stream;
|
||||||
|
|
||||||
|
object.stop();
|
||||||
|
|
||||||
|
var channel = Audio.play(object.sound, loop, stream);
|
||||||
|
if (channel != null) {
|
||||||
|
object.channels.push(channel);
|
||||||
|
channel.volume = volume;
|
||||||
|
@:privateAccess channel.set_position(positionInSeconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
#end
|
||||||
|
runOutput(0);
|
||||||
|
}
|
||||||
|
}
|
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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -77,9 +77,6 @@ class Inc {
|
|||||||
#if (rp_voxels == "Voxel GI")
|
#if (rp_voxels == "Voxel GI")
|
||||||
static var voxel_sh5:kha.compute.Shader = null;
|
static var voxel_sh5:kha.compute.Shader = null;
|
||||||
static var voxel_ta5:kha.compute.TextureUnit;
|
static var voxel_ta5:kha.compute.TextureUnit;
|
||||||
static var voxel_te5:kha.compute.TextureUnit;
|
|
||||||
static var voxel_tf5:kha.compute.TextureUnit;
|
|
||||||
static var voxel_tg5:kha.compute.TextureUnit;
|
|
||||||
static var voxel_ca5:kha.compute.ConstantLocation;
|
static var voxel_ca5:kha.compute.ConstantLocation;
|
||||||
static var voxel_cb5:kha.compute.ConstantLocation;
|
static var voxel_cb5:kha.compute.ConstantLocation;
|
||||||
static var voxel_cc5:kha.compute.ConstantLocation;
|
static var voxel_cc5:kha.compute.ConstantLocation;
|
||||||
@ -532,8 +529,14 @@ class Inc {
|
|||||||
public static function applyConfig() {
|
public static function applyConfig() {
|
||||||
#if lnx_config
|
#if lnx_config
|
||||||
var config = leenkx.data.Config.raw;
|
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
|
// Resize shadow map
|
||||||
var l = path.light;
|
var l = path.light;
|
||||||
|
if (l != null){
|
||||||
if (l.data.raw.type == "sun" && l.data.raw.shadowmap_size != config.rp_shadowmap_cascade) {
|
if (l.data.raw.type == "sun" && l.data.raw.shadowmap_size != config.rp_shadowmap_cascade) {
|
||||||
l.data.raw.shadowmap_size = config.rp_shadowmap_cascade;
|
l.data.raw.shadowmap_size = config.rp_shadowmap_cascade;
|
||||||
var rt = path.renderTargets.get("shadowMap");
|
var rt = path.renderTargets.get("shadowMap");
|
||||||
@ -550,6 +553,7 @@ class Inc {
|
|||||||
path.renderTargets.remove("shadowMapCube");
|
path.renderTargets.remove("shadowMapCube");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (superSample != config.rp_supersample) {
|
if (superSample != config.rp_supersample) {
|
||||||
superSample = config.rp_supersample;
|
superSample = config.rp_supersample;
|
||||||
for (rt in path.renderTargets) {
|
for (rt in path.renderTargets) {
|
||||||
@ -680,7 +684,7 @@ class Inc {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (t.name == "voxelsSDF" || t.name == "voxelsSDFtmp") {
|
if (t.name == "voxelsSDF" || t.name == "voxelsSDFtmp") {
|
||||||
t.format = "R8";
|
t.format = "R16";
|
||||||
t.width = res;
|
t.width = res;
|
||||||
t.height = res * Main.voxelgiClipmapCount;
|
t.height = res * Main.voxelgiClipmapCount;
|
||||||
t.depth = res;
|
t.depth = res;
|
||||||
@ -689,7 +693,7 @@ class Inc {
|
|||||||
#if (rp_voxels == "Voxel AO")
|
#if (rp_voxels == "Voxel AO")
|
||||||
{
|
{
|
||||||
if (t.name == "voxelsOut" || t.name == "voxelsOutB") {
|
if (t.name == "voxelsOut" || t.name == "voxelsOutB") {
|
||||||
t.format = "R8";
|
t.format = "R16";
|
||||||
t.width = res * (6 + 16);
|
t.width = res * (6 + 16);
|
||||||
t.height = res * Main.voxelgiClipmapCount;
|
t.height = res * Main.voxelgiClipmapCount;
|
||||||
t.depth = res;
|
t.depth = res;
|
||||||
@ -781,7 +785,11 @@ class Inc {
|
|||||||
|
|
||||||
public static inline function getDisplayp(): Null<Int> {
|
public static inline function getDisplayp(): Null<Int> {
|
||||||
#if rp_resolution_filter // Custom resolution set
|
#if rp_resolution_filter // Custom resolution set
|
||||||
|
#if rp_pp
|
||||||
|
return leenkx.renderpath.Postprocess.resolution_uniforms[0];
|
||||||
|
#else
|
||||||
return Main.resolutionSize;
|
return Main.resolutionSize;
|
||||||
|
#end
|
||||||
#else
|
#else
|
||||||
return null;
|
return null;
|
||||||
#end
|
#end
|
||||||
@ -895,9 +903,7 @@ class Inc {
|
|||||||
{
|
{
|
||||||
voxel_sh5 = path.getComputeShader("voxel_light");
|
voxel_sh5 = path.getComputeShader("voxel_light");
|
||||||
voxel_ta5 = voxel_sh5.getTextureUnit("voxelsLight");
|
voxel_ta5 = voxel_sh5.getTextureUnit("voxelsLight");
|
||||||
voxel_te5 = voxel_sh5.getTextureUnit("voxels");
|
|
||||||
voxel_tf5 = voxel_sh5.getTextureUnit("voxelsSampler");
|
|
||||||
voxel_tg5 = voxel_sh5.getTextureUnit("voxelsSDFSampler");
|
|
||||||
voxel_ca5 = voxel_sh5.getConstantLocation("clipmaps");
|
voxel_ca5 = voxel_sh5.getConstantLocation("clipmaps");
|
||||||
voxel_cb5 = voxel_sh5.getConstantLocation("clipmapLevel");
|
voxel_cb5 = voxel_sh5.getConstantLocation("clipmapLevel");
|
||||||
|
|
||||||
@ -1218,7 +1224,7 @@ class Inc {
|
|||||||
kha.compute.Compute.setSampledTexture(voxel_td4, rts.get("voxelsSDF").image);
|
kha.compute.Compute.setSampledTexture(voxel_td4, rts.get("voxelsSDF").image);
|
||||||
kha.compute.Compute.setTexture(voxel_te4, rts.get("voxels_specular").image, kha.compute.Access.Write);
|
kha.compute.Compute.setTexture(voxel_te4, rts.get("voxels_specular").image, kha.compute.Access.Write);
|
||||||
|
|
||||||
kha.compute.Compute.setSampledTexture(voxel_tf4, rts.get("gbuffer2").image);
|
//kha.compute.Compute.setSampledTexture(voxel_tf4, rts.get("gbuffer2").image);
|
||||||
|
|
||||||
var fa:Float32Array = new Float32Array(Main.voxelgiClipmapCount * 10);
|
var fa:Float32Array = new Float32Array(Main.voxelgiClipmapCount * 10);
|
||||||
for (i in 0...Main.voxelgiClipmapCount) {
|
for (i in 0...Main.voxelgiClipmapCount) {
|
||||||
@ -1293,9 +1299,7 @@ class Inc {
|
|||||||
kha.compute.Compute.setShader(voxel_sh5);
|
kha.compute.Compute.setShader(voxel_sh5);
|
||||||
|
|
||||||
kha.compute.Compute.setTexture(voxel_ta5, rts.get("voxelsLight").image, kha.compute.Access.Write);
|
kha.compute.Compute.setTexture(voxel_ta5, rts.get("voxelsLight").image, kha.compute.Access.Write);
|
||||||
kha.compute.Compute.setTexture(voxel_te5, rts.get("voxels").image, kha.compute.Access.Read);
|
|
||||||
kha.compute.Compute.setSampledTexture(voxel_tf5, rts.get("voxelsOut").image);
|
|
||||||
kha.compute.Compute.setSampledTexture(voxel_tg5, rts.get("voxelsSDF").image);
|
|
||||||
var fa:Float32Array = new Float32Array(Main.voxelgiClipmapCount * 10);
|
var fa:Float32Array = new Float32Array(Main.voxelgiClipmapCount * 10);
|
||||||
for (i in 0...Main.voxelgiClipmapCount) {
|
for (i in 0...Main.voxelgiClipmapCount) {
|
||||||
fa[i * 10] = clipmaps[i].voxelSize;
|
fa[i * 10] = clipmaps[i].voxelSize;
|
||||||
|
@ -49,15 +49,20 @@ class Postprocess {
|
|||||||
0.01, //4: Fisheye Distortion
|
0.01, //4: Fisheye Distortion
|
||||||
1, //5: DoF AutoFocus §§ If true, it ignores the DoF Distance setting
|
1, //5: DoF AutoFocus §§ If true, it ignores the DoF Distance setting
|
||||||
10.0, //6: DoF Distance
|
10.0, //6: DoF Distance
|
||||||
160.0, //7: DoF Focal Length mm
|
50.0, //7: DoF Focal Length mm
|
||||||
128, //8: DoF F-Stop
|
128, //8: DoF F-Stop
|
||||||
0, //9: Tonemapping Method
|
0, //9: Tonemapping Method
|
||||||
2.0, //10: Distort
|
2.0, //10: Distort
|
||||||
2.0, //11: Film Grain
|
2.0, //11: Film Grain
|
||||||
0.25, //12: Sharpen
|
0.25, //12: Sharpen Strength
|
||||||
0.7 //13: Vignette
|
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 = [
|
public static var tonemapper_uniforms = [
|
||||||
1.0, //0: Slope
|
1.0, //0: Slope
|
||||||
1.0, //1: Toe
|
1.0, //1: Toe
|
||||||
@ -102,7 +107,35 @@ class Postprocess {
|
|||||||
|
|
||||||
public static var chromatic_aberration_uniforms = [
|
public static var chromatic_aberration_uniforms = [
|
||||||
2.0, //0: Strength
|
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 {
|
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.x = lenstexture_uniforms[2]; //Lum min
|
||||||
v.y = lenstexture_uniforms[3]; //Lum max
|
v.y = lenstexture_uniforms[3]; //Lum max
|
||||||
v.z = lenstexture_uniforms[4]; //Expo
|
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":
|
case "_PPComp9":
|
||||||
v = iron.object.Uniforms.helpVec;
|
v = iron.object.Uniforms.helpVec;
|
||||||
v.x = ssr_uniforms[0]; //Step
|
v.x = ssr_uniforms[0]; //Step
|
||||||
@ -297,8 +335,8 @@ class Postprocess {
|
|||||||
case "_PPComp11":
|
case "_PPComp11":
|
||||||
v = iron.object.Uniforms.helpVec;
|
v = iron.object.Uniforms.helpVec;
|
||||||
v.x = bloom_uniforms[2]; // Bloom Strength
|
v.x = bloom_uniforms[2]; // Bloom Strength
|
||||||
v.y = 0; // Unused
|
v.y = volumetric_light_uniforms[2][0]; //Volumetric Light Steps
|
||||||
v.z = 0; // Unused
|
v.z = volumetric_fog_uniforms[2][0]; //Volumetric Fog Amount B
|
||||||
case "_PPComp12":
|
case "_PPComp12":
|
||||||
v = iron.object.Uniforms.helpVec;
|
v = iron.object.Uniforms.helpVec;
|
||||||
v.x = ssao_uniforms[0]; //SSAO Strength
|
v.x = ssao_uniforms[0]; //SSAO Strength
|
||||||
@ -308,7 +346,8 @@ class Postprocess {
|
|||||||
v = iron.object.Uniforms.helpVec;
|
v = iron.object.Uniforms.helpVec;
|
||||||
v.x = chromatic_aberration_uniforms[0]; //CA Strength
|
v.x = chromatic_aberration_uniforms[0]; //CA Strength
|
||||||
v.y = chromatic_aberration_uniforms[1]; //CA Samples
|
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":
|
case "_PPComp14":
|
||||||
v = iron.object.Uniforms.helpVec;
|
v = iron.object.Uniforms.helpVec;
|
||||||
v.x = camera_uniforms[10]; //Distort
|
v.x = camera_uniforms[10]; //Distort
|
||||||
@ -338,6 +377,24 @@ class Postprocess {
|
|||||||
v.y = letterbox_uniforms[0][1];
|
v.y = letterbox_uniforms[0][1];
|
||||||
v.z = letterbox_uniforms[0][2];
|
v.z = letterbox_uniforms[0][2];
|
||||||
v.w = letterbox_uniforms[1][0]; //Size
|
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;
|
return v;
|
||||||
|
@ -368,7 +368,7 @@ class RenderPathDeferred {
|
|||||||
t.scale = Inc.getSuperSampling();
|
t.scale = Inc.getSuperSampling();
|
||||||
path.createRenderTarget(t);
|
path.createRenderTarget(t);
|
||||||
|
|
||||||
// holds background color
|
// holds background depth
|
||||||
var t = new RenderTargetRaw();
|
var t = new RenderTargetRaw();
|
||||||
t.name = "refr";
|
t.name = "refr";
|
||||||
t.width = 0;
|
t.width = 0;
|
||||||
@ -473,13 +473,6 @@ class RenderPathDeferred {
|
|||||||
}
|
}
|
||||||
#end
|
#end
|
||||||
|
|
||||||
#if rp_ssrefr
|
|
||||||
{
|
|
||||||
path.setTarget("gbuffer_refraction");
|
|
||||||
path.clearTarget(0xffffff00);
|
|
||||||
}
|
|
||||||
#end
|
|
||||||
|
|
||||||
RenderPathCreator.setTargetMeshes();
|
RenderPathCreator.setTargetMeshes();
|
||||||
|
|
||||||
#if rp_dynres
|
#if rp_dynres
|
||||||
@ -844,7 +837,7 @@ class RenderPathDeferred {
|
|||||||
{
|
{
|
||||||
path.bindTarget("voxelsOut", "voxels");
|
path.bindTarget("voxelsOut", "voxels");
|
||||||
path.bindTarget("voxelsSDF", "voxelsSDF");
|
path.bindTarget("voxelsSDF", "voxelsSDF");
|
||||||
path.bindTarget("gbuffer2", "gbuffer2");
|
path.bindTarget("gbuffer2", "sveloc");
|
||||||
}
|
}
|
||||||
#end
|
#end
|
||||||
|
|
||||||
|
@ -522,17 +522,6 @@ class RenderPathForward {
|
|||||||
|
|
||||||
path.setTarget("lbuffer0", ["lbuffer1", "gbuffer_refraction"]);
|
path.setTarget("lbuffer0", ["lbuffer1", "gbuffer_refraction"]);
|
||||||
|
|
||||||
#if rp_shadowmap
|
|
||||||
{
|
|
||||||
#if lnx_shadowmap_atlas
|
|
||||||
Inc.bindShadowMapAtlas();
|
|
||||||
#else
|
|
||||||
Inc.bindShadowMap();
|
|
||||||
#end
|
|
||||||
}
|
|
||||||
#end
|
|
||||||
|
|
||||||
|
|
||||||
#if (rp_voxels != "Off")
|
#if (rp_voxels != "Off")
|
||||||
path.bindTarget("voxelsOut", "voxels");
|
path.bindTarget("voxelsOut", "voxels");
|
||||||
path.bindTarget("voxelsSDF", "voxelsSDF");
|
path.bindTarget("voxelsSDF", "voxelsSDF");
|
||||||
|
@ -41,11 +41,7 @@ class Starter {
|
|||||||
try {
|
try {
|
||||||
#end
|
#end
|
||||||
|
|
||||||
kha.System.start({title: Main.projectName, width: c.window_w, height: c.window_h, window: {
|
kha.System.start({title: Main.projectName, width: c.window_w, height: c.window_h, window: {mode: windowMode, windowFeatures: windowFeatures}, framebuffer: {samplesPerPixel: c.window_msaa, verticalSync: c.window_vsync}}, function(window: kha.Window) {
|
||||||
#if lnx_render_viewport
|
|
||||||
visible: false,
|
|
||||||
#end
|
|
||||||
mode: windowMode, windowFeatures: windowFeatures}, framebuffer: {samplesPerPixel: c.window_msaa, verticalSync: c.window_vsync}}, function(window: kha.Window) {
|
|
||||||
|
|
||||||
iron.App.init(function() {
|
iron.App.init(function() {
|
||||||
#if lnx_loadscreen
|
#if lnx_loadscreen
|
||||||
|
@ -280,6 +280,10 @@ class DebugConsole extends Trait {
|
|||||||
|
|
||||||
function drawObjectNameInList(object: iron.object.Object, selected: Bool) {
|
function drawObjectNameInList(object: iron.object.Object, selected: Bool) {
|
||||||
var _y = ui._y;
|
var _y = ui._y;
|
||||||
|
|
||||||
|
if (object.parent.name == 'Root')
|
||||||
|
ui.text(object.uid+'_'+object.name+' ('+iron.Scene.active.raw.world_ref+')');
|
||||||
|
else
|
||||||
ui.text(object.uid+'_'+object.name);
|
ui.text(object.uid+'_'+object.name);
|
||||||
|
|
||||||
if (object == iron.Scene.active.camera) {
|
if (object == iron.Scene.active.camera) {
|
||||||
|
@ -45,7 +45,7 @@ class DebugDrawHelper {
|
|||||||
|
|
||||||
iron.App.notifyOnRender2D(onRender);
|
iron.App.notifyOnRender2D(onRender);
|
||||||
if (debugDrawMode & DrawRayCast != 0) {
|
if (debugDrawMode & DrawRayCast != 0) {
|
||||||
iron.App.notifyOnUpdate(function () {
|
iron.App.notifyOnFixedUpdate(function () {
|
||||||
rayCasts.resize(0);
|
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();
|
super();
|
||||||
|
|
||||||
if (nullvec) {
|
if (nullvec) {
|
||||||
@ -120,6 +120,7 @@ class PhysicsWorld extends Trait {
|
|||||||
this.timeScale = timeScale;
|
this.timeScale = timeScale;
|
||||||
this.maxSteps = maxSteps;
|
this.maxSteps = maxSteps;
|
||||||
this.solverIterations = solverIterations;
|
this.solverIterations = solverIterations;
|
||||||
|
Time.initFixedStep(fixedStep);
|
||||||
|
|
||||||
// First scene
|
// First scene
|
||||||
if (active == null) {
|
if (active == null) {
|
||||||
@ -136,9 +137,9 @@ class PhysicsWorld extends Trait {
|
|||||||
conMap = new Map();
|
conMap = new Map();
|
||||||
active = this;
|
active = this;
|
||||||
|
|
||||||
// Ensure physics are updated first in the lateUpdate list
|
// Ensure physics are updated first in the fixedUpdate list
|
||||||
_lateUpdate = [lateUpdate];
|
_fixedUpdate = [fixedUpdate];
|
||||||
@:privateAccess iron.App.traitLateUpdates.insert(0, lateUpdate);
|
@:privateAccess iron.App.traitFixedUpdates.insert(0, fixedUpdate);
|
||||||
|
|
||||||
setDebugDrawMode(debugDrawMode);
|
setDebugDrawMode(debugDrawMode);
|
||||||
|
|
||||||
@ -298,8 +299,8 @@ class PhysicsWorld extends Trait {
|
|||||||
return rb;
|
return rb;
|
||||||
}
|
}
|
||||||
|
|
||||||
function lateUpdate() {
|
function fixedUpdate() {
|
||||||
var t = Time.delta * timeScale;
|
var t = Time.fixedStep * timeScale * Time.scale;
|
||||||
if (t == 0.0) return; // Simulation paused
|
if (t == 0.0) return; // Simulation paused
|
||||||
|
|
||||||
#if lnx_debug
|
#if lnx_debug
|
||||||
@ -308,13 +309,10 @@ class PhysicsWorld extends Trait {
|
|||||||
|
|
||||||
if (preUpdates != null) for (f in preUpdates) f();
|
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
|
//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();
|
updateContacts();
|
||||||
|
|
||||||
for (rb in rbMap) @:privateAccess rb.physicsUpdate();
|
for (rb in rbMap) @:privateAccess rb.physicsUpdate();
|
||||||
@ -436,8 +434,8 @@ class PhysicsWorld extends Trait {
|
|||||||
from: from,
|
from: from,
|
||||||
to: to,
|
to: to,
|
||||||
hasHit: rc.hasHit(),
|
hasHit: rc.hasHit(),
|
||||||
hitPoint: hitPointWorld,
|
hitPoint: hitPointWorld.clone(),
|
||||||
hitNormal: hitNormalWorld
|
hitNormal: hitNormalWorld.clone()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,11 +2,13 @@ package leenkx.trait.physics.bullet;
|
|||||||
|
|
||||||
#if lnx_bullet
|
#if lnx_bullet
|
||||||
|
|
||||||
|
import leenkx.math.Helper;
|
||||||
|
import iron.data.MeshData;
|
||||||
import iron.math.Vec4;
|
import iron.math.Vec4;
|
||||||
import iron.math.Quat;
|
import iron.math.Quat;
|
||||||
import iron.object.Transform;
|
import iron.object.Transform;
|
||||||
import iron.object.MeshObject;
|
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.
|
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 triangleMeshCache = new Map<MeshData, bullet.Bt.TriangleMesh>();
|
||||||
static var usersCache = new Map<MeshData, Int>();
|
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,
|
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) {
|
params: RigidBodyParams = null, flags: RigidBodyFlags = null) {
|
||||||
super();
|
super();
|
||||||
@ -85,7 +95,7 @@ class RigidBody extends iron.Trait {
|
|||||||
vec1 = new bullet.Bt.Vector3(0, 0, 0);
|
vec1 = new bullet.Bt.Vector3(0, 0, 0);
|
||||||
vec2 = new bullet.Bt.Vector3(0, 0, 0);
|
vec2 = new bullet.Bt.Vector3(0, 0, 0);
|
||||||
vec3 = 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();
|
trans1 = new bullet.Bt.Transform();
|
||||||
trans2 = new bullet.Bt.Transform();
|
trans2 = new bullet.Bt.Transform();
|
||||||
}
|
}
|
||||||
@ -117,6 +127,7 @@ class RigidBody extends iron.Trait {
|
|||||||
animated: false,
|
animated: false,
|
||||||
trigger: false,
|
trigger: false,
|
||||||
ccd: false,
|
ccd: false,
|
||||||
|
interpolate: false,
|
||||||
staticObj: false,
|
staticObj: false,
|
||||||
useDeactivation: true
|
useDeactivation: true
|
||||||
};
|
};
|
||||||
@ -131,6 +142,7 @@ class RigidBody extends iron.Trait {
|
|||||||
this.animated = flags.animated;
|
this.animated = flags.animated;
|
||||||
this.trigger = flags.trigger;
|
this.trigger = flags.trigger;
|
||||||
this.ccd = flags.ccd;
|
this.ccd = flags.ccd;
|
||||||
|
this.interpolate = flags.interpolate;
|
||||||
this.staticObj = flags.staticObj;
|
this.staticObj = flags.staticObj;
|
||||||
this.useDeactivation = flags.useDeactivation;
|
this.useDeactivation = flags.useDeactivation;
|
||||||
|
|
||||||
@ -153,6 +165,7 @@ class RigidBody extends iron.Trait {
|
|||||||
if (!Std.isOfType(object, MeshObject)) return; // No mesh data
|
if (!Std.isOfType(object, MeshObject)) return; // No mesh data
|
||||||
|
|
||||||
transform = object.transform;
|
transform = object.transform;
|
||||||
|
transform.buildMatrix();
|
||||||
physics = leenkx.trait.physics.PhysicsWorld.active;
|
physics = leenkx.trait.physics.PhysicsWorld.active;
|
||||||
|
|
||||||
if (shape == Shape.Box) {
|
if (shape == Shape.Box) {
|
||||||
@ -244,6 +257,9 @@ class RigidBody extends iron.Trait {
|
|||||||
quat1.setValue(quat.x, quat.y, quat.z, quat.w);
|
quat1.setValue(quat.x, quat.y, quat.z, quat.w);
|
||||||
trans1.setRotation(quat1);
|
trans1.setRotation(quat1);
|
||||||
|
|
||||||
|
currentPos.setValue(vec1.x(), vec1.y(), vec1.z());
|
||||||
|
currentRot.setValue(quat.x, quat.y, quat.z, quat.w);
|
||||||
|
|
||||||
var centerOfMassOffset = trans2;
|
var centerOfMassOffset = trans2;
|
||||||
centerOfMassOffset.setIdentity();
|
centerOfMassOffset.setIdentity();
|
||||||
motionState = new bullet.Bt.DefaultMotionState(trans1, centerOfMassOffset);
|
motionState = new bullet.Bt.DefaultMotionState(trans1, centerOfMassOffset);
|
||||||
@ -307,6 +323,7 @@ class RigidBody extends iron.Trait {
|
|||||||
|
|
||||||
physics.addRigidBody(this);
|
physics.addRigidBody(this);
|
||||||
notifyOnRemove(removeFromWorld);
|
notifyOnRemove(removeFromWorld);
|
||||||
|
if (!animated) notifyOnUpdate(update);
|
||||||
|
|
||||||
if (onReady != null) onReady();
|
if (onReady != null) onReady();
|
||||||
|
|
||||||
@ -317,26 +334,71 @@ class RigidBody extends iron.Trait {
|
|||||||
#end
|
#end
|
||||||
}
|
}
|
||||||
|
|
||||||
function physicsUpdate() {
|
|
||||||
if (!ready) return;
|
|
||||||
if (animated) {
|
|
||||||
syncTransform();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
var trans = body.getWorldTransform();
|
|
||||||
var p = trans.getOrigin();
|
|
||||||
var q = trans.getRotation();
|
|
||||||
|
|
||||||
transform.loc.set(p.x(), p.y(), p.z());
|
function update() {
|
||||||
transform.rot.set(q.x(), q.y(), q.z(), q.w());
|
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) {
|
if (object.parent != null) {
|
||||||
var ptransform = object.parent.transform;
|
var ptransform = object.parent.transform;
|
||||||
transform.loc.x -= ptransform.worldx();
|
transform.loc.x -= ptransform.worldx();
|
||||||
transform.loc.y -= ptransform.worldy();
|
transform.loc.y -= ptransform.worldy();
|
||||||
transform.loc.z -= ptransform.worldz();
|
transform.loc.z -= ptransform.worldz();
|
||||||
}
|
}
|
||||||
transform.clearDelta();
|
|
||||||
transform.buildMatrix();
|
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 {
|
||||||
|
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.clearDelta();
|
||||||
|
// transform.buildMatrix();
|
||||||
|
currentPos.setValue(p.x(), p.y(), p.z());
|
||||||
|
currentRot.setValue(q.x(), q.y(), q.z(), q.w());
|
||||||
|
|
||||||
|
|
||||||
#if hl
|
#if hl
|
||||||
p.delete();
|
p.delete();
|
||||||
@ -689,6 +751,7 @@ typedef RigidBodyFlags = {
|
|||||||
var animated: Bool;
|
var animated: Bool;
|
||||||
var trigger: Bool;
|
var trigger: Bool;
|
||||||
var ccd: Bool;
|
var ccd: Bool;
|
||||||
|
var interpolate: Bool;
|
||||||
var staticObj: Bool;
|
var staticObj: Bool;
|
||||||
var useDeactivation: Bool;
|
var useDeactivation: Bool;
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user