Compare commits
337 commits
Author | SHA1 | Date | |
---|---|---|---|
9220e6b57e | |||
15ec53830f | |||
946610c793 | |||
1430e22a90 | |||
07f4bea206 | |||
8581a75f9c | |||
6bb2513001 | |||
f581e91ba9 | |||
263d5853a5 | |||
1cec287891 | |||
83a60e7462 | |||
603d23fbfd | |||
03090cafa2 | |||
a1951bb66e | |||
3c0f580f69 | |||
8116729822 | |||
6c0d4bdead | |||
8f733222a9 | |||
4b65d8d68c | |||
13a2f4538a | |||
b7cafbb4e3 | |||
d4f9982768 | |||
8e69bea14e | |||
669898fae1 | |||
8df6fc9176 | |||
edeaf488b9 | |||
cb2cf0c9b4 | |||
4522055fac | |||
1d0eaf9371 | |||
e562d2515e | |||
8e7d8a4f56 | |||
6e153569dc | |||
d01c55fcd4 | |||
3814cd9da7 | |||
0636eb85c6 | |||
2f77c5b060 | |||
26a0fb8c5a | |||
8c034655be | |||
6f9b51a57a | |||
34243ed74c | |||
fb004f5dcc | |||
867100d151 | |||
09433f2a19 | |||
10d41e5eca | |||
b7941d2fa8 | |||
93563dbba5 | |||
9094154440 | |||
6ad9941d43 | |||
326d3bbf0d | |||
b2566a8249 | |||
18c5636d03 | |||
07cfa40727 | |||
e06ca4b9e7 | |||
ec1f25cfec | |||
1dc733ca88 | |||
f22542a0b4 | |||
c97c738870 | |||
130e470290 | |||
fabb4c0c3c | |||
ca03897811 | |||
6e255bcb05 | |||
f6dfc43dde | |||
36e42ad736 | |||
3df2916f5b | |||
59aca7ea41 | |||
297f7cdfca | |||
176ab43fd0 | |||
6b1333902c | |||
89ff1c29fc | |||
086c05eba2 | |||
3e6e1e4bd1 | |||
977b2db376 | |||
ebb3076431 | |||
826dbd786d | |||
4fe8f683dc | |||
b9b5c65141 | |||
ec3054cdeb | |||
d3b006c873 | |||
9c931aff56 | |||
622b8a275f | |||
ea9b01e733 | |||
34897c9747 | |||
c1f98dc668 | |||
67d511568f | |||
b8319fe28b | |||
d5e0208fd6 | |||
0fadefab69 | |||
50a1994867 | |||
b9a220fbcb | |||
5e1105f51d | |||
b060953a7e | |||
a4d09936d6 | |||
786e68e475 | |||
c7cba9d792 | |||
d9ddb5f4a3 | |||
8e8e8f586d | |||
e8fa3b1b9a | |||
7289b95a48 | |||
7f5d382131 | |||
ea02600d14 | |||
a2c33b2f6a | |||
c40fd26c20 | |||
308ab2d77b | |||
d979e4fde9 | |||
1c237dd6c3 | |||
152959699a | |||
259c375fda | |||
b579c8a15d | |||
73a352b76e | |||
957c5371c8 | |||
962f8a79a5 | |||
8604e670c3 | |||
d1d266a0f0 | |||
62d399e01a | |||
128efcc0ef | |||
3920c475be | |||
e3a55db813 | |||
597c291da7 | |||
16976cdc5b | |||
d1fe4d6686 | |||
ca966588ff | |||
0ce0c5c115 | |||
05465bcea1 | |||
77815d95ed | |||
156f1f433a | |||
5b4d24f067 | |||
c24389813f | |||
c398c1181e | |||
7d9d5ac50f | |||
eb5ef99309 | |||
62294c8bb4 | |||
ed6aa96fb0 | |||
f3fcb2846e | |||
afeecd4df1 | |||
de72bbf3a4 | |||
ecc4317919 | |||
667e73c867 | |||
56d84b08f4 | |||
adb2468245 | |||
abc52627a3 | |||
68ef00b668 | |||
55cfead084 | |||
fe6d1fa372 | |||
974181e75e | |||
a4ab1dcc98 | |||
ccbc946bf1 | |||
fddef0983c | |||
e715bf0108 | |||
214b84fcf7 | |||
32b745f829 | |||
8caf859db9 | |||
d6692efbdc | |||
c77eea93fa | |||
e0cbf1b332 | |||
b7024a5854 | |||
44d8325001 | |||
052c7b00c5 | |||
675618e529 | |||
a6b67e4e00 | |||
4b75a896d6 | |||
ecddc0af92 | |||
e05d556552 | |||
85edde6d24 | |||
703c618c7d | |||
df715db381 | |||
a8a44df249 | |||
1eb087125f | |||
2347348504 | |||
3e22cb3375 | |||
4e526a6dd3 | |||
2630c159d8 | |||
a67452802d | |||
f892fdfd8a | |||
29785172f4 | |||
1d0a6d7955 | |||
7b6d3536e3 | |||
f017d68ed7 | |||
1de97e1898 | |||
ca96174b6b | |||
bd67667a6e | |||
2910fcf1a8 | |||
c56a0c3a72 | |||
d610cc6a2f | |||
34f6e0fc7c | |||
45e3c1c138 | |||
c49bece460 | |||
2ef4f19eb7 | |||
5509096158 | |||
2d3e15064a | |||
386d2a3bf4 | |||
7607cc8ccd | |||
52a594c910 | |||
4c4bebcf4f | |||
ea8c13686c | |||
4c34c2a5ce | |||
b664e3a010 | |||
60d0f443f8 | |||
aeffd76b75 | |||
1532a332ff | |||
4fc1f38b3b | |||
5f2dce140e | |||
13cf22ecc2 | |||
9f7af6a1cd | |||
9ec425f6ae | |||
3bad878650 | |||
ce75516c59 | |||
bce14549ac | |||
ee208ece18 | |||
549040fc09 | |||
62ff11747b | |||
6a3045477f | |||
8a758bbe26 | |||
ffee6dc521 | |||
cca82a69bf | |||
c52d25e471 | |||
cf1dd0ac71 | |||
8e1aa2fb0d | |||
6d2b825dd5 | |||
6050bceaf1 | |||
dbb0764ca7 | |||
568f4f3a6d | |||
0a58279756 | |||
ff5fd9c7ed | |||
0456d5f080 | |||
af520b518e | |||
82c7302dd9 | |||
2b6a7a4f78 | |||
7eced3b4f5 | |||
aa21402221 | |||
97cc737aff | |||
256d27e289 | |||
9ff726bac1 | |||
5276711094 | |||
4f13ebc439 | |||
1edc7a9469 | |||
3ed915b654 | |||
e930da7388 | |||
c65764be99 | |||
bdee03873b | |||
1b758ec32c | |||
cfa941eab4 | |||
9b1393ea41 | |||
bfde181da6 | |||
a59c789528 | |||
caa03b59c5 | |||
ff93e5f824 | |||
b3162d8f6e | |||
823cc379b6 | |||
ee194a1806 | |||
96aa0ee890 | |||
c0333db44f | |||
e0ff256f40 | |||
28d21bf35f | |||
b452acaebb | |||
3c88ddcb23 | |||
db5aed465e | |||
55cf2896a2 | |||
daee309ad8 | |||
43a574eb15 | |||
919512fad0 | |||
14b18408aa | |||
801668a0c2 | |||
dc6753c2ca | |||
6dd27bfeed | |||
e7da337530 | |||
50c8ceec1e | |||
a6ec652d5f | |||
cb800729d2 | |||
4e19ddfeb0 | |||
b2153dbcd2 | |||
4387d774cc | |||
738a217001 | |||
9e493f6e79 | |||
7504d5d92b | |||
e308d9058b | |||
c7e1f5d0a9 | |||
202138304a | |||
8c0b6ba13e | |||
7515a20d93 | |||
3d49edee71 | |||
34b816b4d9 | |||
13c1e0508d | |||
f940e8566e | |||
dfad6902af | |||
441f42383e | |||
616a0e230d | |||
20540ccb11 | |||
31a2c9c4d3 | |||
ac48fd0bc9 | |||
f2cf3bdeda | |||
112c00a649 | |||
ee43724b97 | |||
5a2f952f89 | |||
936f11ed8e | |||
eab7fcbbe6 | |||
5a591fa15a | |||
975ec76f38 | |||
340f7e8af4 | |||
fa44147ee6 | |||
c44e2cf555 | |||
15da6ccf58 | |||
39922bc0f3 | |||
ea4f88aca8 | |||
39bd32f9d3 | |||
e744fd901c | |||
dbd348ad5d | |||
f542dc00ca | |||
aaa21bc019 | |||
a9f430c374 | |||
6cf3299ffe | |||
a588396dea | |||
dc34e48c52 | |||
fce97a5ddf | |||
d18aede964 | |||
66856e7ecc | |||
ebfbb68bb4 | |||
3c1264378b | |||
cbcc3e4e04 | |||
f45304ea10 | |||
dd13cc31b7 | |||
a5fa3445d9 | |||
1ece052aee | |||
24d917ae6a | |||
3288c3dcf5 | |||
251ad8e47e | |||
b2619828eb | |||
6c6d7c1419 | |||
0e6ba5b0b0 | |||
107dc730f4 | |||
b72e85894a | |||
20f9f8a5f4 | |||
088bc0f666 | |||
9fbc3d6cd4 | |||
7b2961459c | |||
3d46910530 | |||
68825516c9 | |||
07ffe06c1d |
|
@ -4,7 +4,9 @@
|
|||
|
||||
uniform sampler2D tex;
|
||||
|
||||
#ifdef _CPostprocess
|
||||
uniform vec3 PPComp10;
|
||||
#endif
|
||||
|
||||
in vec2 texCoord;
|
||||
out vec4 fragColor;
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
"links": [
|
||||
{
|
||||
"name": "PPComp10",
|
||||
"link": "_PPComp10"
|
||||
"link": "_PPComp10",
|
||||
"ifdef": ["_CPostprocess"]
|
||||
}
|
||||
],
|
||||
"texture_params": [],
|
||||
|
|
|
@ -7,7 +7,9 @@ uniform sampler2D tex;
|
|||
uniform vec2 dir;
|
||||
uniform vec2 screenSize;
|
||||
|
||||
#ifdef _CPostprocess
|
||||
uniform vec3 PPComp11;
|
||||
#endif
|
||||
|
||||
in vec2 texCoord;
|
||||
out vec4 fragColor;
|
||||
|
@ -26,7 +28,7 @@ void main() {
|
|||
fragColor.rgb += textureLod(tex, texCoord + s, 0.0).rgb * weight[i];
|
||||
fragColor.rgb += textureLod(tex, texCoord - s, 0.0).rgb * weight[i];
|
||||
}
|
||||
|
||||
|
||||
#ifdef _CPostprocess
|
||||
fragColor.rgb *= PPComp11.x / 5;
|
||||
#else
|
||||
|
|
|
@ -16,7 +16,8 @@
|
|||
},
|
||||
{
|
||||
"name": "PPComp11",
|
||||
"link": "_PPComp11"
|
||||
"link": "_PPComp11",
|
||||
"ifdef": ["_CPostprocess"]
|
||||
}
|
||||
],
|
||||
"texture_params": [],
|
||||
|
@ -39,7 +40,8 @@
|
|||
},
|
||||
{
|
||||
"name": "PPComp11",
|
||||
"link": "_PPComp11"
|
||||
"link": "_PPComp11",
|
||||
"ifdef": ["_CPostprocess"]
|
||||
}
|
||||
],
|
||||
"texture_params": [],
|
||||
|
@ -65,7 +67,8 @@
|
|||
},
|
||||
{
|
||||
"name": "PPComp11",
|
||||
"link": "_PPComp11"
|
||||
"link": "_PPComp11",
|
||||
"ifdef": ["_CPostprocess"]
|
||||
}
|
||||
],
|
||||
"texture_params": [],
|
||||
|
|
|
@ -3,7 +3,10 @@
|
|||
#include "compiled.inc"
|
||||
|
||||
uniform sampler2D tex;
|
||||
|
||||
#ifdef _CPostprocess
|
||||
uniform vec3 PPComp13;
|
||||
#endif
|
||||
|
||||
in vec2 texCoord;
|
||||
out vec4 fragColor;
|
||||
|
|
|
@ -9,7 +9,8 @@
|
|||
"links": [
|
||||
{
|
||||
"name": "PPComp13",
|
||||
"link": "_PPComp13"
|
||||
"link": "_PPComp13",
|
||||
"ifdef": ["_CPostprocess"]
|
||||
}
|
||||
],
|
||||
"texture_params": [],
|
||||
|
|
|
@ -21,7 +21,9 @@
|
|||
uniform sampler2D gbufferD;
|
||||
uniform sampler2D gbuffer0;
|
||||
uniform sampler2D gbuffer1;
|
||||
#ifdef _gbuffer2
|
||||
uniform sampler2D gbuffer2;
|
||||
#endif
|
||||
|
||||
#ifdef _VoxelAOvar
|
||||
uniform sampler3D voxels;
|
||||
|
@ -206,7 +208,9 @@ void main() {
|
|||
vec3 v = normalize(eye - p);
|
||||
float dotNV = max(dot(n, v), 0.0);
|
||||
|
||||
#ifdef _gbuffer2
|
||||
vec4 g2 = textureLod(gbuffer2, texCoord, 0.0);
|
||||
#endif
|
||||
|
||||
#ifdef _MicroShadowing
|
||||
occspec.x = mix(1.0, occspec.x, dotNV); // AO Fresnel
|
||||
|
@ -221,14 +225,16 @@ void main() {
|
|||
|
||||
vec3 envl = shIrradiance(n, shirr);
|
||||
|
||||
if (g2.b < 0.5) {
|
||||
envl = envl;
|
||||
} else {
|
||||
envl = vec3(1.0);
|
||||
}
|
||||
#ifdef _gbuffer2
|
||||
if (g2.b < 0.5) {
|
||||
envl = envl;
|
||||
} else {
|
||||
envl = vec3(1.0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _EnvTex
|
||||
envl /= PI;
|
||||
envl /= PI;
|
||||
#endif
|
||||
#else
|
||||
vec3 envl = vec3(1.0);
|
||||
|
|
|
@ -12,8 +12,10 @@ uniform vec3 eyeLook;
|
|||
uniform vec2 screenSize;
|
||||
uniform mat4 invVP;
|
||||
|
||||
#ifdef _CPostprocess
|
||||
uniform vec3 PPComp11;
|
||||
uniform vec3 PPComp12;
|
||||
#endif
|
||||
|
||||
in vec2 texCoord;
|
||||
in vec3 viewRay;
|
||||
|
@ -23,12 +25,12 @@ void main() {
|
|||
float depth = textureLod(gbufferD, texCoord, 0.0).r * 2.0 - 1.0;
|
||||
if (depth == 1.0) { fragColor = 1.0; return; }
|
||||
|
||||
vec2 enc = textureLod(gbuffer0, texCoord, 0.0).rg;
|
||||
vec2 enc = textureLod(gbuffer0, texCoord, 0.0).rg;
|
||||
vec3 n;
|
||||
n.z = 1.0 - abs(enc.x) - abs(enc.y);
|
||||
n.xy = n.z >= 0.0 ? enc.xy : octahedronWrap(enc.xy);
|
||||
n = normalize(n);
|
||||
|
||||
|
||||
vec3 vray = normalize(viewRay);
|
||||
vec3 currentPos = getPosNoEye(eyeLook, vray, depth, cameraProj);
|
||||
// vec3 currentPos = getPos2NoEye(eye, invVP, depth, texCoord);
|
||||
|
@ -53,7 +55,7 @@ void main() {
|
|||
vec3 pos = getPos2NoEye(eye, invVP, depth, texCoord + k) - currentPos;
|
||||
fragColor += max(0, dot(pos, n) - currentDistanceB) / (dot(pos, pos) + 0.015);
|
||||
}
|
||||
|
||||
|
||||
#ifdef _CPostprocess
|
||||
fragColor *= (PPComp12.x * 0.3) / samples;
|
||||
#else
|
||||
|
|
|
@ -28,11 +28,13 @@
|
|||
},
|
||||
{
|
||||
"name": "PPComp11",
|
||||
"link": "_PPComp11"
|
||||
"link": "_PPComp11",
|
||||
"ifdef": ["_CPostprocess"]
|
||||
},
|
||||
{
|
||||
"name": "PPComp12",
|
||||
"link": "_PPComp12"
|
||||
"link": "_PPComp12",
|
||||
"ifdef": ["_CPostprocess"]
|
||||
}
|
||||
],
|
||||
"texture_params": [],
|
||||
|
|
|
@ -12,8 +12,10 @@ uniform mat4 P;
|
|||
uniform mat3 V3;
|
||||
uniform vec2 cameraProj;
|
||||
|
||||
#ifdef _CPostprocess
|
||||
uniform vec3 PPComp9;
|
||||
uniform vec3 PPComp10;
|
||||
#endif
|
||||
|
||||
in vec3 viewRay;
|
||||
in vec2 texCoord;
|
||||
|
|
|
@ -24,11 +24,13 @@
|
|||
},
|
||||
{
|
||||
"name": "PPComp9",
|
||||
"link": "_PPComp9"
|
||||
"link": "_PPComp9",
|
||||
"ifdef": ["_CPostprocess"]
|
||||
},
|
||||
{
|
||||
"name": "PPComp10",
|
||||
"link": "_PPComp10"
|
||||
"link": "_PPComp10",
|
||||
"ifdef": ["_CPostprocess"]
|
||||
}
|
||||
],
|
||||
"texture_params": [],
|
||||
|
|
|
@ -23,7 +23,7 @@ vec2 rand2(const vec2 coord) {
|
|||
const float width = 1100.0;
|
||||
const float height = 500.0;
|
||||
float noiseX = ((fract(1.0 - coord.s * (width / 2.0)) * 0.25) + (fract(coord.t * (height / 2.0)) * 0.75)) * 2.0 - 1.0;
|
||||
float noiseY = ((fract(1.0 - coord.s * (width / 2.0)) * 0.75) + (fract(coord.t * (height / 2.0)) * 0.25)) * 2.0 - 1.0;
|
||||
float noiseY = ((fract(1.0 - coord.s * (width / 2.0)) * 0.75) + (fract(coord.t * (height / 2.0)) * 0.25)) * 2.0 - 1.0;
|
||||
return vec2(noiseX, noiseY);
|
||||
}
|
||||
|
||||
|
@ -40,4 +40,9 @@ float attenuate(const float dist) {
|
|||
// 1.0 / (quadratic * dist * dist);
|
||||
}
|
||||
|
||||
float safe_acos(const float x) {
|
||||
// acos is undefined if |x| > 1
|
||||
return acos(clamp(x, -1.0, 1.0));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
53
Shaders/std/morph_target.glsl
Normal file
53
Shaders/std/morph_target.glsl
Normal file
|
@ -0,0 +1,53 @@
|
|||
uniform sampler2D morphDataPos;
|
||||
uniform sampler2D morphDataNor;
|
||||
uniform vec2 morphScaleOffset;
|
||||
uniform vec2 morphDataDim;
|
||||
uniform vec4 morphWeights[8];
|
||||
|
||||
void getMorphedVertex(vec2 uvCoord, inout vec3 A){
|
||||
for(int i = 0; i<8; i++ )
|
||||
{
|
||||
vec4 tempCoordY = vec4( uvCoord.y - (i * 4) * morphDataDim.y,
|
||||
uvCoord.y - (i * 4 + 1) * morphDataDim.y,
|
||||
uvCoord.y - (i * 4 + 2) * morphDataDim.y,
|
||||
uvCoord.y - (i * 4 + 3) * morphDataDim.y);
|
||||
|
||||
vec3 morph = texture(morphDataPos, vec2(uvCoord.x, tempCoordY.x)).rgb * morphScaleOffset.x + morphScaleOffset.y;
|
||||
A += morphWeights[i].x * morph;
|
||||
|
||||
morph = texture(morphDataPos, vec2(uvCoord.x, tempCoordY.y)).rgb * morphScaleOffset.x + morphScaleOffset.y;
|
||||
A += morphWeights[i].y * morph;
|
||||
|
||||
morph = texture(morphDataPos, vec2(uvCoord.x, tempCoordY.z)).rgb * morphScaleOffset.x + morphScaleOffset.y;
|
||||
A += morphWeights[i].z * morph;
|
||||
|
||||
morph = texture(morphDataPos, vec2(uvCoord.x, tempCoordY.w)).rgb * morphScaleOffset.x + morphScaleOffset.y;
|
||||
A += morphWeights[i].w * morph;
|
||||
}
|
||||
}
|
||||
|
||||
void getMorphedNormal(vec2 uvCoord, vec3 oldNor, inout vec3 morphNor){
|
||||
|
||||
for(int i = 0; i<8; i++ )
|
||||
{
|
||||
vec4 tempCoordY = vec4( uvCoord.y - (i * 4) * morphDataDim.y,
|
||||
uvCoord.y - (i * 4 + 1) * morphDataDim.y,
|
||||
uvCoord.y - (i * 4 + 2) * morphDataDim.y,
|
||||
uvCoord.y - (i * 4 + 3) * morphDataDim.y);
|
||||
|
||||
vec3 norm = oldNor + morphWeights[i].x * (texture(morphDataNor, vec2(uvCoord.x, tempCoordY.x)).rgb * 2.0 - 1.0);
|
||||
morphNor += norm;
|
||||
|
||||
norm = oldNor + morphWeights[i].y * (texture(morphDataNor, vec2(uvCoord.x, tempCoordY.y)).rgb * 2.0 - 1.0);
|
||||
morphNor += norm;
|
||||
|
||||
norm = oldNor + morphWeights[i].z * (texture(morphDataNor, vec2(uvCoord.x, tempCoordY.z)).rgb * 2.0 - 1.0);
|
||||
morphNor += norm;
|
||||
|
||||
norm = oldNor + morphWeights[i].w * (texture(morphDataNor, vec2(uvCoord.x, tempCoordY.w)).rgb * 2.0 - 1.0);
|
||||
morphNor += norm;
|
||||
|
||||
}
|
||||
|
||||
morphNor = normalize(morphNor);
|
||||
}
|
|
@ -20,6 +20,8 @@
|
|||
#ifndef _SKY_GLSL_
|
||||
#define _SKY_GLSL_
|
||||
|
||||
#include "std/math.glsl"
|
||||
|
||||
uniform sampler2D nishitaLUT;
|
||||
uniform vec2 nishitaDensity;
|
||||
|
||||
|
@ -44,20 +46,9 @@ uniform vec2 nishitaDensity;
|
|||
#define nishita_mie_dir 0.76 // Aerosols anisotropy ("direction")
|
||||
#define nishita_mie_dir_sq 0.5776 // Squared aerosols anisotropy
|
||||
|
||||
// The ozone absorption coefficients are taken from Cycles code.
|
||||
// Because Cycles calculates 21 wavelengths, we use the coefficients
|
||||
// which are closest to the RGB wavelengths (645nm, 510nm, 440nm).
|
||||
// Precalculating values by simulating Blender's spec_to_xyz() function
|
||||
// to include all 21 wavelengths gave unrealistic results
|
||||
#define nishita_ozone_coeff vec3(1.59051840791988e-6, 0.00000096707041180970, 0.00000007309568762914)
|
||||
|
||||
// Values from [Hill: 60]
|
||||
#define sun_limb_darkening_col vec3(0.397, 0.503, 0.652)
|
||||
|
||||
float random(vec2 coords) {
|
||||
return fract(sin(dot(coords.xy, vec2(12.9898,78.233))) * 43758.5453);
|
||||
}
|
||||
|
||||
vec3 nishita_lookupLUT(const float height, const float sunTheta) {
|
||||
vec2 coords = vec2(
|
||||
sqrt(height * (1 / nishita_atmo_radius)),
|
||||
|
@ -124,18 +115,19 @@ vec3 nishita_atmosphere(const vec3 r, const vec3 r0, const vec3 pSun, const floa
|
|||
|
||||
// Idea behind this: "Rotate" everything by iPos (-> iPos is the new zenith) and then all calculations for the
|
||||
// inner integral only depend on the sample height (iHeight) and sunTheta (angle between sun and new zenith).
|
||||
float sunTheta = acos(dot(normalize(iPos), normalize(pSun)));
|
||||
vec3 jODepth = nishita_lookupLUT(iHeight, sunTheta);
|
||||
|
||||
// Apply dithering to reduce visible banding
|
||||
jODepth += mix(-1000, 1000, random(r.xy));
|
||||
float sunTheta = safe_acos(dot(normalize(iPos), normalize(pSun)));
|
||||
vec3 jAttn = nishita_lookupLUT(iHeight, sunTheta);
|
||||
|
||||
// Calculate attenuation
|
||||
vec3 attn = exp(-(
|
||||
nishita_mie_coeff * (iOdMie + jODepth.y)
|
||||
+ (nishita_rayleigh_coeff) * (iOdRlh + jODepth.x)
|
||||
+ nishita_ozone_coeff * jODepth.z
|
||||
vec3 iAttn = exp(-(
|
||||
nishita_mie_coeff * iOdMie
|
||||
+ nishita_rayleigh_coeff * iOdRlh
|
||||
// + 0 for ozone
|
||||
));
|
||||
vec3 attn = iAttn * jAttn;
|
||||
|
||||
// Apply dithering to reduce visible banding
|
||||
attn *= 0.98 + rand(r.xy) * 0.04;
|
||||
|
||||
// Accumulate scattering
|
||||
totalRlh += odStepRlh * attn;
|
||||
|
|
|
@ -44,7 +44,15 @@ uniform vec2 cameraPlane;
|
|||
uniform vec3 sunDir;
|
||||
uniform vec3 sunCol;
|
||||
#ifdef _ShadowMap
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
uniform sampler2DShadow shadowMapAtlasSun;
|
||||
#else
|
||||
uniform sampler2DShadow shadowMapAtlas;
|
||||
#endif
|
||||
#else
|
||||
uniform sampler2DShadow shadowMap;
|
||||
#endif
|
||||
uniform float shadowsBias;
|
||||
#ifdef _CSM
|
||||
//!uniform vec4 casData[shadowmapCascades * 4 + 4];
|
||||
|
@ -95,7 +103,17 @@ void rayStep(inout vec3 curPos, inout float curOpticalDepth, inout float scatter
|
|||
#endif
|
||||
vec4 lPos = LWVP * vec4(curPos, 1.0);
|
||||
lPos.xyz /= lPos.w;
|
||||
visibility = texture(shadowMap, vec3(lPos.xy, lPos.z - shadowsBias));
|
||||
visibility = texture(
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
shadowMapAtlasSun
|
||||
#else
|
||||
shadowMapAtlas
|
||||
#endif
|
||||
#else
|
||||
shadowMap
|
||||
#endif
|
||||
, vec3(lPos.xy, lPos.z - shadowsBias));
|
||||
#endif
|
||||
|
||||
#ifdef _SinglePoint
|
||||
|
|
1
Sources/armory/import.hx
Normal file
1
Sources/armory/import.hx
Normal file
|
@ -0,0 +1 @@
|
|||
import armory.system.Assert.*;
|
|
@ -1,13 +1,11 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import armory.trait.physics.PhysicsConstraint;
|
||||
#if arm_physics
|
||||
import armory.trait.physics.bullet.PhysicsConstraint.ConstraintType;
|
||||
import armory.trait.physics.bullet.PhysicsConstraint.ConstraintAxis;
|
||||
#end
|
||||
import iron.object.Object;
|
||||
import armory.trait.physics.RigidBody;
|
||||
import armory.logicnode.PhysicsConstraintNode;
|
||||
|
||||
#if arm_physics
|
||||
import armory.trait.physics.PhysicsConstraint;
|
||||
import armory.trait.physics.bullet.PhysicsConstraint.ConstraintType;
|
||||
#end
|
||||
|
||||
class AddPhysicsConstraintNode extends LogicNode {
|
||||
|
||||
|
@ -21,115 +19,96 @@ class AddPhysicsConstraintNode extends LogicNode {
|
|||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
var pivotObject:Object = inputs[1].get();
|
||||
var pivotObject: Object = inputs[1].get();
|
||||
rb1 = inputs[2].get();
|
||||
rb2 = inputs[3].get();
|
||||
var disableCollisions: Bool = inputs[4].get();
|
||||
var breakable: Bool = inputs[5].get();
|
||||
var breakingThreshold: Float = inputs[6].get();
|
||||
var type: ConstraintType = 0;
|
||||
|
||||
if (pivotObject == null || rb1 == null || rb2 == null) return;
|
||||
|
||||
#if arm_physics
|
||||
|
||||
var disableCollisions: Bool = inputs[4].get();
|
||||
var breakable: Bool = inputs[5].get();
|
||||
var breakingThreshold: Float = inputs[6].get();
|
||||
var type: ConstraintType = 0;
|
||||
|
||||
var con: PhysicsConstraint = pivotObject.getTrait(PhysicsConstraint);
|
||||
if(con == null)
|
||||
{
|
||||
switch(property0)
|
||||
{
|
||||
case 'Fixed':
|
||||
type = Fixed;
|
||||
case 'Point':
|
||||
type = Point;
|
||||
case 'Hinge':
|
||||
type = Hinge;
|
||||
case 'Slider':
|
||||
type = Slider;
|
||||
case 'Piston':
|
||||
type = Piston;
|
||||
case 'Generic Spring':
|
||||
type = Generic;
|
||||
if (con == null) {
|
||||
switch (property0) {
|
||||
case "Fixed": type = Fixed;
|
||||
case "Point": type = Point;
|
||||
case "Hinge": type = Hinge;
|
||||
case "Slider": type = Slider;
|
||||
case "Piston": type = Piston;
|
||||
case "Generic Spring": type = Generic;
|
||||
}
|
||||
|
||||
if(! breakable) breakingThreshold = 0.0;
|
||||
if (!breakable) breakingThreshold = 0.0;
|
||||
|
||||
if (type != Generic) {
|
||||
|
||||
if(type != Generic) {
|
||||
|
||||
con = new PhysicsConstraint(rb1, rb2, type, disableCollisions, breakingThreshold);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
switch (type) {
|
||||
case Hinge:
|
||||
var setLimit:Bool = inputs[7].get();
|
||||
var low:Float = inputs[8].get();
|
||||
var up:Float = inputs[9].get();
|
||||
var setLimit: Bool = inputs[7].get();
|
||||
var low: Float = inputs[8].get();
|
||||
var up: Float = inputs[9].get();
|
||||
con.setHingeConstraintLimits(setLimit, low, up);
|
||||
|
||||
case Slider:
|
||||
var setLimit:Bool = inputs[7].get();
|
||||
var low:Float = inputs[8].get();
|
||||
var up:Float = inputs[9].get();
|
||||
var setLimit: Bool = inputs[7].get();
|
||||
var low: Float = inputs[8].get();
|
||||
var up: Float = inputs[9].get();
|
||||
con.setSliderConstraintLimits(setLimit, low, up);
|
||||
|
||||
case Piston:
|
||||
var setLinLimit:Bool = inputs[7].get();
|
||||
var linLow:Float = inputs[8].get();
|
||||
var linUp:Float = inputs[9].get();
|
||||
var setAngLimit:Bool = inputs[10].get();
|
||||
var angLow:Float = inputs[11].get();
|
||||
var angUp:Float = inputs[12].get();
|
||||
var setLinLimit: Bool = inputs[7].get();
|
||||
var linLow: Float = inputs[8].get();
|
||||
var linUp: Float = inputs[9].get();
|
||||
var setAngLimit: Bool = inputs[10].get();
|
||||
var angLow: Float = inputs[11].get();
|
||||
var angUp: Float = inputs[12].get();
|
||||
con.setPistonConstraintLimits(setLinLimit, linLow, linUp, setAngLimit, angLow, angUp);
|
||||
|
||||
default:
|
||||
default:
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
var spring: Bool = false;
|
||||
var prop: PhysicsConstraintNode;
|
||||
for(inp in 7...inputs.length)
|
||||
{
|
||||
|
||||
for (inp in 7...inputs.length) {
|
||||
prop = inputs[inp].get();
|
||||
if(prop == null) continue;
|
||||
if(prop.isSpring)
|
||||
{
|
||||
if (prop == null) continue;
|
||||
if (prop.isSpring) {
|
||||
spring = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(spring) {
|
||||
if (spring) {
|
||||
con = new PhysicsConstraint(rb1, rb2, GenericSpring, disableCollisions, breakingThreshold);
|
||||
}
|
||||
}
|
||||
else {
|
||||
con = new PhysicsConstraint(rb1, rb2, Generic, disableCollisions, breakingThreshold);
|
||||
}
|
||||
|
||||
for(inp in 7...inputs.length)
|
||||
{
|
||||
for (inp in 7...inputs.length) {
|
||||
prop = inputs[inp].get();
|
||||
if(prop == null) continue;
|
||||
(inp + ': ');
|
||||
if (prop == null) continue;
|
||||
|
||||
if(prop.isSpring)
|
||||
{
|
||||
if (prop.isSpring) {
|
||||
con.setSpringParams(prop.isSpring, prop.value1, prop.value2, prop.axis, prop.isAngular);
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
con.setGenericConstraintLimits(true, prop.value1, prop.value2, prop.axis, prop.isAngular);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
pivotObject.addTrait(con);
|
||||
|
||||
}
|
||||
#end
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,17 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.object.Object;
|
||||
|
||||
#if arm_physics
|
||||
import armory.trait.physics.RigidBody;
|
||||
import armory.trait.physics.bullet.RigidBody.Shape;
|
||||
#end
|
||||
import iron.object.Object;
|
||||
import armory.trait.physics.RigidBody;
|
||||
|
||||
|
||||
class AddRigidBodyNode extends LogicNode {
|
||||
|
||||
public var property0: String;//Shape
|
||||
public var property1: String;//Advanced
|
||||
public var property0: String; //Shape
|
||||
public var property1: Bool; //Advanced
|
||||
public var object: Object;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
|
@ -18,6 +20,10 @@ class AddRigidBodyNode extends LogicNode {
|
|||
|
||||
override function run(from: Int) {
|
||||
object = inputs[1].get();
|
||||
if (object == null) return;
|
||||
|
||||
#if arm_physics
|
||||
|
||||
var mass: Float = inputs[2].get();
|
||||
var active: Bool = inputs[3].get();
|
||||
var animated: Bool = inputs[4].get();
|
||||
|
@ -38,8 +44,7 @@ class AddRigidBodyNode extends LogicNode {
|
|||
|
||||
var shape: Shape = 1;
|
||||
|
||||
if(property1 == 'true')
|
||||
{
|
||||
if (property1) {
|
||||
margin = inputs[9].get();
|
||||
marginLen = inputs[10].get();
|
||||
linDamp = inputs[11].get();
|
||||
|
@ -49,50 +54,34 @@ class AddRigidBodyNode extends LogicNode {
|
|||
angVelThreshold = inputs[15].get();
|
||||
group = inputs[16].get();
|
||||
mask = inputs[17].get();
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (object == null) return;
|
||||
|
||||
#if arm_physics
|
||||
var rb: RigidBody = object.getTrait(RigidBody);
|
||||
if((group < 0) || (group > 32)) group = 1; //Limiting max groups to 32
|
||||
if((mask < 0) || (mask > 32)) mask = 1; //Limiting max masks to 32
|
||||
if(rb == null)
|
||||
{
|
||||
|
||||
switch (property0){
|
||||
|
||||
case 'Box':
|
||||
shape = Box;
|
||||
case 'Sphere':
|
||||
shape = Sphere;
|
||||
case 'Capsule':
|
||||
shape = Capsule;
|
||||
case 'Cone':
|
||||
shape = Cone;
|
||||
case 'Cylinder':
|
||||
shape = Cylinder;
|
||||
case 'Convex Hull':
|
||||
shape = ConvexHull;
|
||||
case 'Mesh':
|
||||
shape = Mesh;
|
||||
if ((group < 0) || (group > 32)) group = 1; //Limiting max groups to 32
|
||||
if ((mask < 0) || (mask > 32)) mask = 1; //Limiting max masks to 32
|
||||
if (rb == null) {
|
||||
switch (property0) {
|
||||
case "Box": shape = Box;
|
||||
case "Sphere": shape = Sphere;
|
||||
case "Capsule": shape = Capsule;
|
||||
case "Cone": shape = Cone;
|
||||
case "Cylinder": shape = Cylinder;
|
||||
case "Convex Hull": shape = ConvexHull;
|
||||
case "Mesh": shape = Mesh;
|
||||
}
|
||||
|
||||
rb = new RigidBody(shape, mass, friction, bounciness, group, mask);
|
||||
rb.animated = animated;
|
||||
rb.staticObj = ! active;
|
||||
rb.staticObj = !active;
|
||||
rb.isTriggerObject(trigger);
|
||||
if(property1 == 'true')
|
||||
{
|
||||
|
||||
if (property1) {
|
||||
rb.linearDamping = linDamp;
|
||||
rb.angularDamping = angDamp;
|
||||
if(margin) rb.collisionMargin = marginLen;
|
||||
if(useDeactiv) {
|
||||
if (margin) rb.collisionMargin = marginLen;
|
||||
if (useDeactiv) {
|
||||
rb.setUpDeactivation(true, linearVelThreshold, angVelThreshold, 0.0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
object.addTrait(rb);
|
||||
|
|
|
@ -10,10 +10,17 @@ class AddTraitNode extends LogicNode {
|
|||
|
||||
override function run(from: Int) {
|
||||
var object: Object = inputs[1].get();
|
||||
var trait: Dynamic = inputs[2].get();
|
||||
var traitName: String = inputs[2].get();
|
||||
|
||||
if (object == null || trait == null) return;
|
||||
assert(Error, object != null, "Object should not be null");
|
||||
assert(Error, traitName != null, "Trait name should not be null");
|
||||
|
||||
var cname = Type.resolveClass(Main.projectPackage + "." + traitName);
|
||||
if (cname == null) cname = Type.resolveClass(Main.projectPackage + ".node." + traitName);
|
||||
assert(Error, cname != null, 'No trait with the name "$traitName" found, make sure that the trait is exported!');
|
||||
assert(Warning, object.getTrait(cname) == null, 'Object already has the trait "$traitName" applied');
|
||||
|
||||
var trait = Type.createInstance(cname, []);
|
||||
object.addTrait(trait);
|
||||
|
||||
runOutput(0);
|
||||
|
|
|
@ -12,11 +12,17 @@ class CallHaxeStaticNode extends LogicNode {
|
|||
|
||||
var path: String = inputs[1].get();
|
||||
if (path != "") {
|
||||
var args: Array<Dynamic> = [];
|
||||
|
||||
for (i in 2...inputs.length) {
|
||||
args.push(inputs[i].get());
|
||||
}
|
||||
|
||||
var dotIndex = path.lastIndexOf(".");
|
||||
var classPath = path.substr(0, dotIndex);
|
||||
var classType = Type.resolveClass(classPath);
|
||||
var funName = path.substr(dotIndex + 1);
|
||||
result = Reflect.callMethod(classType, Reflect.field(classType, funName), [tree]);
|
||||
result = Reflect.callMethod(classType, Reflect.field(classType, funName), args);
|
||||
}
|
||||
|
||||
runOutput(0);
|
||||
|
|
39
Sources/armory/logicnode/CanvasSetProgressBarColorNode.hx
Normal file
39
Sources/armory/logicnode/CanvasSetProgressBarColorNode.hx
Normal file
|
@ -0,0 +1,39 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.Scene;
|
||||
import armory.trait.internal.CanvasScript;
|
||||
import kha.Color;
|
||||
import iron.math.Vec4;
|
||||
|
||||
class CanvasSetProgressBarColorNode extends LogicNode {
|
||||
|
||||
var canvas: CanvasScript;
|
||||
var element: String;
|
||||
var color = new Vec4();
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
#if arm_ui
|
||||
function update() {
|
||||
if (!canvas.ready) return;
|
||||
tree.removeUpdate(update);
|
||||
|
||||
var e = canvas.getElement(element);
|
||||
if (e != null) e.color_progress = Color.fromFloats(color.x, color.y, color.z, color.w);
|
||||
runOutput(0);
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
element = inputs[1].get();
|
||||
color = inputs[2].get();
|
||||
canvas = Scene.active.getTrait(CanvasScript);
|
||||
if (canvas == null) canvas = Scene.active.camera.getTrait(CanvasScript);
|
||||
|
||||
// Ensure canvas is ready
|
||||
tree.notifyOnUpdate(update);
|
||||
update();
|
||||
}
|
||||
#end
|
||||
}
|
|
@ -19,9 +19,11 @@ class CompareNode extends LogicNode {
|
|||
|
||||
switch (property0) {
|
||||
case "Equal":
|
||||
cond = Std.is(v1, Vec4) ? v1.equals(v2) : v1 == v2;
|
||||
cond = Std.isOfType(v1, Vec4) ? v1.equals(v2) : v1 == v2;
|
||||
case "Not Equal":
|
||||
cond = Std.isOfType(v1, Vec4) ? !v1.equals(v2) : v1 != v2;
|
||||
case "Almost Equal":
|
||||
cond = Std.is(v1, Vec4) ? v1.almostEquals(v2, property1) : Math.abs(v1 - v2) < property1;
|
||||
cond = Std.isOfType(v1, Vec4) ? v1.almostEquals(v2, property1) : Math.abs(v1 - v2) < property1;
|
||||
case "Greater":
|
||||
cond = v1 > v2;
|
||||
case "Greater Equal":
|
||||
|
@ -30,6 +32,9 @@ class CompareNode extends LogicNode {
|
|||
cond = v1 < v2;
|
||||
case "Less Equal":
|
||||
cond = v1 <= v2;
|
||||
case "Between":
|
||||
var v3: Dynamic = inputs[2].get();
|
||||
cond = v2 <= v1 && v1 <= v3;
|
||||
case "Or":
|
||||
for (input in inputs) {
|
||||
if (input.get()) {
|
||||
|
|
|
@ -18,9 +18,11 @@ class GateNode extends LogicNode {
|
|||
|
||||
switch (property0) {
|
||||
case "Equal":
|
||||
cond = Std.is(v1, Vec4) ? v1.equals(v2) : v1 == v2;
|
||||
cond = Std.isOfType(v1, Vec4) ? v1.equals(v2) : v1 == v2;
|
||||
case "Not Equal":
|
||||
cond = Std.isOfType(v1, Vec4) ? !v1.equals(v2) : v1 != v2;
|
||||
case "Almost Equal":
|
||||
cond = Std.is(v1, Vec4) ? v1.almostEquals(v2, property1) : Math.abs(v1 - v2) < property1;
|
||||
cond = Std.isOfType(v1, Vec4) ? v1.almostEquals(v2, property1) : Math.abs(v1 - v2) < property1;
|
||||
case "Greater":
|
||||
cond = v1 > v2;
|
||||
case "Greater Equal":
|
||||
|
@ -29,6 +31,9 @@ class GateNode extends LogicNode {
|
|||
cond = v1 < v2;
|
||||
case "Less Equal":
|
||||
cond = v1 <= v2;
|
||||
case "Between":
|
||||
var v3: Dynamic = inputs[3].get();
|
||||
cond = v2 <= v1 && v1 <= v3;
|
||||
case "Or":
|
||||
for (i in 1...inputs.length) {
|
||||
if (inputs[i].get()) {
|
||||
|
|
25
Sources/armory/logicnode/GetAgentDataNode.hx
Normal file
25
Sources/armory/logicnode/GetAgentDataNode.hx
Normal file
|
@ -0,0 +1,25 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.object.Object;
|
||||
|
||||
class GetAgentDataNode extends LogicNode {
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function get(from: Int): Float {
|
||||
var object: Object = inputs[0].get();
|
||||
|
||||
assert(Error, object != null, "The object to naviagte should not be null");
|
||||
|
||||
#if arm_navigation
|
||||
var agent: armory.trait.NavAgent = object.getTrait(armory.trait.NavAgent);
|
||||
assert(Error, agent != null, "The object does not have NavAgent Trait");
|
||||
if(from == 0) return agent.speed;
|
||||
else return agent.turnDuration;
|
||||
#else
|
||||
return null;
|
||||
#end
|
||||
}
|
||||
}
|
|
@ -23,7 +23,7 @@ class GetBoneFkIkOnlyNode extends LogicNode {
|
|||
var bone = anim.getBone(boneName);
|
||||
|
||||
//Get bone transform in world coordinates
|
||||
return bone.is_IK_FK_only;
|
||||
return bone.is_ik_fk_only;
|
||||
|
||||
|
||||
#end
|
||||
|
|
33
Sources/armory/logicnode/GetGamepadStartedNode.hx
Normal file
33
Sources/armory/logicnode/GetGamepadStartedNode.hx
Normal file
|
@ -0,0 +1,33 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.system.Input;
|
||||
|
||||
class GetGamepadStartedNode extends LogicNode {
|
||||
|
||||
var buttonStarted: Null<String>;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
var g = Input.getGamepad(inputs[0].get());
|
||||
|
||||
buttonStarted = null;
|
||||
|
||||
for (b in Gamepad.buttons) {
|
||||
if (g.started(b)) {
|
||||
buttonStarted = b;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (buttonStarted != null) {
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
||||
|
||||
override function get(from: Int) {
|
||||
return buttonStarted;
|
||||
}
|
||||
}
|
22
Sources/armory/logicnode/GetGlobalCanvasFontSizeNode.hx
Normal file
22
Sources/armory/logicnode/GetGlobalCanvasFontSizeNode.hx
Normal file
|
@ -0,0 +1,22 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.Scene;
|
||||
import armory.trait.internal.CanvasScript;
|
||||
|
||||
class GetGlobalCanvasFontSizeNode extends LogicNode {
|
||||
|
||||
var canvas: CanvasScript;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
#if arm_ui
|
||||
override function get(from: Int): Dynamic {
|
||||
canvas = Scene.active.getTrait(CanvasScript);
|
||||
if (canvas == null) canvas = Scene.active.camera.getTrait(CanvasScript);
|
||||
|
||||
return canvas.getCanvasFontSize();
|
||||
}
|
||||
#end
|
||||
}
|
22
Sources/armory/logicnode/GetGlobalCanvasScaleNode.hx
Normal file
22
Sources/armory/logicnode/GetGlobalCanvasScaleNode.hx
Normal file
|
@ -0,0 +1,22 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.Scene;
|
||||
import armory.trait.internal.CanvasScript;
|
||||
|
||||
class GetGlobalCanvasScaleNode extends LogicNode {
|
||||
|
||||
var canvas: CanvasScript;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
#if arm_ui
|
||||
override function get(from: Int): Dynamic {
|
||||
canvas = Scene.active.getTrait(CanvasScript);
|
||||
if (canvas == null) canvas = Scene.active.camera.getTrait(CanvasScript);
|
||||
|
||||
return canvas.getUiScale();
|
||||
}
|
||||
#end
|
||||
}
|
24
Sources/armory/logicnode/GetInputMapKeyNode.hx
Normal file
24
Sources/armory/logicnode/GetInputMapKeyNode.hx
Normal file
|
@ -0,0 +1,24 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import armory.system.InputMap;
|
||||
|
||||
class GetInputMapKeyNode extends LogicNode {
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function get(from: Int): Dynamic {
|
||||
var inputMap = inputs[0].get();
|
||||
var key = inputs[1].get();
|
||||
|
||||
var k = InputMap.getInputMapKey(inputMap, key);
|
||||
|
||||
if (k != null) {
|
||||
if (from == 0) return k.scale;
|
||||
else if (from == 1) return k.deadzone;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
32
Sources/armory/logicnode/GetKeyboardStartedNode.hx
Normal file
32
Sources/armory/logicnode/GetKeyboardStartedNode.hx
Normal file
|
@ -0,0 +1,32 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.system.Input;
|
||||
|
||||
class GetKeyboardStartedNode extends LogicNode {
|
||||
|
||||
var kb = Input.getKeyboard();
|
||||
var keyStarted: Null<String>;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
keyStarted = null;
|
||||
|
||||
for (k in Keyboard.keys) {
|
||||
if (kb.started(k)) {
|
||||
keyStarted = k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (keyStarted != null) {
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
||||
|
||||
override function get(from: Int) {
|
||||
return keyStarted;
|
||||
}
|
||||
}
|
|
@ -10,9 +10,22 @@ class GetLocationNode extends LogicNode {
|
|||
|
||||
override function get(from: Int): Dynamic {
|
||||
var object: Object = inputs[0].get();
|
||||
var relative: Bool = inputs[1].get();
|
||||
|
||||
if (object == null) return null;
|
||||
|
||||
return object.transform.world.getLoc();
|
||||
var loc = object.transform.world.getLoc();
|
||||
|
||||
if (relative && object.parent != null) {
|
||||
loc.sub(object.parent.transform.world.getLoc()); // Add parent location influence
|
||||
|
||||
// Convert loc to parent local space
|
||||
var dotX = loc.dot(object.parent.transform.right());
|
||||
var dotY = loc.dot(object.parent.transform.look());
|
||||
var dotZ = loc.dot(object.parent.transform.up());
|
||||
loc.set(dotX, dotY, dotZ);
|
||||
}
|
||||
|
||||
return loc;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.object.MeshObject;
|
||||
import iron.object.DecalObject;
|
||||
|
||||
class GetMaterialNode extends LogicNode {
|
||||
|
||||
|
@ -9,11 +10,27 @@ class GetMaterialNode extends LogicNode {
|
|||
}
|
||||
|
||||
override function get(from: Int): Dynamic {
|
||||
var object: MeshObject = inputs[0].get();
|
||||
var slot: Int = inputs[1].get();
|
||||
|
||||
if (object == null) return null;
|
||||
var object = inputs[0].get();
|
||||
|
||||
return object.materials[slot];
|
||||
assert(Error, object != null, "The object input must not be null");
|
||||
|
||||
#if rp_decals
|
||||
if (Std.isOfType(object, DecalObject)) {
|
||||
var decal = cast(object, DecalObject);
|
||||
return decal.material;
|
||||
}
|
||||
#end
|
||||
|
||||
if (Std.isOfType(object, MeshObject)) {
|
||||
var mesh = cast(object, MeshObject);
|
||||
var slot: Int = inputs[1].get();
|
||||
|
||||
if (mesh == null) return null;
|
||||
|
||||
return mesh.materials[slot];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
32
Sources/armory/logicnode/GetMouseStartedNode.hx
Normal file
32
Sources/armory/logicnode/GetMouseStartedNode.hx
Normal file
|
@ -0,0 +1,32 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.system.Input;
|
||||
|
||||
class GetMouseStartedNode extends LogicNode {
|
||||
|
||||
var m = Input.getMouse();
|
||||
var buttonStarted: Null<String>;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
buttonStarted = null;
|
||||
|
||||
for (b in Mouse.buttons) {
|
||||
if (m.started(b)) {
|
||||
buttonStarted = b;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (buttonStarted != null) {
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
||||
|
||||
override function get(from: Int) {
|
||||
return buttonStarted;
|
||||
}
|
||||
}
|
22
Sources/armory/logicnode/GetObjectByUidNode.hx
Normal file
22
Sources/armory/logicnode/GetObjectByUidNode.hx
Normal file
|
@ -0,0 +1,22 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.data.SceneFormat;
|
||||
import iron.object.Object;
|
||||
|
||||
class GetObjectByUidNode extends LogicNode {
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function get(from: Int): Dynamic {
|
||||
var objectUid: Int = inputs[0].get();
|
||||
|
||||
var obj = iron.Scene.active.getChildren(true);
|
||||
|
||||
for (obji in obj) if (obji.uid == objectUid) return obji;
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
|
@ -1,10 +1,13 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.object.Object;
|
||||
import iron.math.Vec3;
|
||||
import iron.math.Quat;
|
||||
import iron.math.Vec4;
|
||||
|
||||
class GetRotationNode extends LogicNode {
|
||||
|
||||
public var property0: String;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
@ -16,34 +19,16 @@ class GetRotationNode extends LogicNode {
|
|||
return null;
|
||||
}
|
||||
|
||||
var rot = object.transform.rot;
|
||||
|
||||
switch (from) {
|
||||
case 0:
|
||||
// euler angles
|
||||
return object.transform.rot.getEuler();
|
||||
case 1:
|
||||
// vector
|
||||
var sqrtW = Math.sqrt(1 - (rot.w * rot.w));
|
||||
if (sqrtW == 0) {
|
||||
return new Vec3(0, 0, 1);
|
||||
}
|
||||
return new Vec3(rot.x / sqrtW, rot.y / sqrtW, rot.z / sqrtW);
|
||||
case 2:
|
||||
// angle radians
|
||||
var angle = 2 * Math.acos(rot.w);
|
||||
return angle;
|
||||
case 3:
|
||||
// angle degrees
|
||||
var angle = 2 * Math.acos(rot.w);
|
||||
return angle * (180 / Math.PI);
|
||||
case 4:
|
||||
//quaternion xyz
|
||||
return new Vec3(rot.x, rot.y, rot.z);
|
||||
case 5:
|
||||
//quaternion w
|
||||
return rot.w;
|
||||
}
|
||||
switch(property0){
|
||||
case "Local":
|
||||
return object.transform.rot;
|
||||
case "Global":{
|
||||
var useless1 = new Vec4();
|
||||
var ret = new Quat();
|
||||
object.transform.world.decompose(useless1, ret, useless1);
|
||||
return ret;
|
||||
}}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,12 +16,12 @@ class GetTraitNameNode extends LogicNode {
|
|||
case 0: {
|
||||
// Check CanvasScript
|
||||
var cname = cast Type.resolveClass("armory.trait.internal.CanvasScript");
|
||||
if (Std.is(trait, cname)) {
|
||||
if (Std.isOfType(trait, cname)) {
|
||||
return trait.cnvName;
|
||||
}
|
||||
// Check WasmScript
|
||||
var cname = cast Type.resolveClass("armory.trait.internal.WasmScript");
|
||||
if (Std.is(trait, cname)) {
|
||||
if (Std.isOfType(trait, cname)) {
|
||||
return trait.wasmName;
|
||||
}
|
||||
// Other
|
||||
|
|
18
Sources/armory/logicnode/GetUidNode.hx
Normal file
18
Sources/armory/logicnode/GetUidNode.hx
Normal file
|
@ -0,0 +1,18 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.object.Object;
|
||||
|
||||
class GetUidNode 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;
|
||||
|
||||
return object.uid;
|
||||
}
|
||||
}
|
|
@ -13,15 +13,26 @@ class GoToLocationNode extends LogicNode {
|
|||
override function run(from: Int) {
|
||||
var object: Object = inputs[1].get();
|
||||
var location: Vec4 = inputs[2].get();
|
||||
var speed: Float = inputs[3].get();
|
||||
var turnDuration: Float = inputs[4].get();
|
||||
|
||||
if (object == null || location == null) return;
|
||||
assert(Error, object != null, "The object input not be null");
|
||||
assert(Error, location != null, "The location to navigate to must not be null");
|
||||
assert(Error, speed != null, "Speed of Nav Agent should not be null");
|
||||
assert(Warning, speed >= 0, "Speed of Nav Agent should be positive");
|
||||
assert(Error, turnDuration != null, "Turn Duration of Nav Agent should not be null");
|
||||
assert(Warning, turnDuration >= 0, "Turn Duration of Nav Agent should be positive");
|
||||
|
||||
#if arm_navigation
|
||||
// Assume navmesh exists..
|
||||
var from = object.transform.world.getLoc();
|
||||
var to = location;
|
||||
|
||||
assert(Error, Navigation.active.navMeshes.length > 0, "No Navigation Mesh Present");
|
||||
Navigation.active.navMeshes[0].findPath(from, to, function(path: Array<iron.math.Vec4>) {
|
||||
var agent: armory.trait.NavAgent = object.getTrait(armory.trait.NavAgent);
|
||||
assert(Error, agent != null, "Object does not have a NavAgent trait");
|
||||
agent.speed = speed;
|
||||
agent.turnDuration = turnDuration;
|
||||
agent.setPath(path);
|
||||
});
|
||||
#end
|
||||
|
|
|
@ -1,31 +1,136 @@
|
|||
package armory.logicnode;
|
||||
|
||||
#if arm_patch @:keep @:keepSub #end
|
||||
class LogicNode {
|
||||
|
||||
var tree: LogicTree;
|
||||
var inputs: Array<LogicNodeInput> = [];
|
||||
var outputs: Array<Array<LogicNode>> = [];
|
||||
var inputs: Array<LogicNodeLink> = [];
|
||||
var outputs: Array<Array<LogicNodeLink>> = [];
|
||||
|
||||
#if arm_debug
|
||||
#if (arm_debug || arm_patch)
|
||||
public var name = "";
|
||||
public function watch(b: Bool) { // Watch in debug console
|
||||
var nodes = armory.trait.internal.DebugConsole.watchNodes;
|
||||
b ? nodes.push(this) : nodes.remove(this);
|
||||
}
|
||||
|
||||
#if (arm_debug)
|
||||
public function watch(b: Bool) { // Watch in debug console
|
||||
var nodes = armory.trait.internal.DebugConsole.watchNodes;
|
||||
b ? nodes.push(this) : nodes.remove(this);
|
||||
}
|
||||
#end
|
||||
#end
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
this.tree = tree;
|
||||
}
|
||||
|
||||
public function addInput(node: LogicNode, from: Int) {
|
||||
inputs.push(new LogicNodeInput(node, from));
|
||||
/**
|
||||
Resize the inputs array to a given size to minimize dynamic
|
||||
reallocation and over-allocation later.
|
||||
**/
|
||||
inline function preallocInputs(amount: Int) {
|
||||
this.inputs.resize(amount);
|
||||
}
|
||||
|
||||
public function addOutputs(nodes: Array<LogicNode>) {
|
||||
outputs.push(nodes);
|
||||
/**
|
||||
Resize the outputs array to a given size to minimize dynamic
|
||||
reallocation and over-allocation later.
|
||||
**/
|
||||
inline function preallocOutputs(amount: Int) {
|
||||
this.outputs.resize(amount);
|
||||
for (i in 0...outputs.length) {
|
||||
outputs[i] = [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Add a link between to nodes to the tree.
|
||||
**/
|
||||
public static function addLink(fromNode: LogicNode, toNode: LogicNode, fromIndex: Int, toIndex: Int): LogicNodeLink {
|
||||
var link = new LogicNodeLink(fromNode, toNode, fromIndex, toIndex);
|
||||
|
||||
if (toNode.inputs.length <= toIndex) {
|
||||
toNode.inputs.resize(toIndex + 1);
|
||||
}
|
||||
toNode.inputs[toIndex] = link;
|
||||
|
||||
var fromNodeOuts = fromNode.outputs;
|
||||
var outLen = fromNodeOuts.length;
|
||||
if (outLen <= fromIndex) {
|
||||
fromNodeOuts.resize(fromIndex + 1);
|
||||
|
||||
// Initialize with empty arrays
|
||||
for (i in outLen...fromIndex + 1) {
|
||||
fromNodeOuts[i] = [];
|
||||
}
|
||||
}
|
||||
fromNodeOuts[fromIndex].push(link);
|
||||
|
||||
return link;
|
||||
}
|
||||
|
||||
#if arm_patch
|
||||
/**
|
||||
Removes a link from the tree.
|
||||
**/
|
||||
static function removeLink(link: LogicNodeLink) {
|
||||
link.fromNode.outputs[link.fromIndex].remove(link);
|
||||
|
||||
// Reuse the same link and connect a default input node to it.
|
||||
// That's why this function is only available in arm_patch mode, we need
|
||||
// access to the link's type and value.
|
||||
link.fromNode = LogicNode.createSocketDefaultNode(link.toNode.tree, link.toType, link.toValue);
|
||||
link.fromIndex = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
Removes all inputs and their links from this node.
|
||||
Warning: this function changes the amount of node inputs to 0!
|
||||
**/
|
||||
function clearInputs() {
|
||||
for (link in inputs) {
|
||||
link.fromNode.outputs[link.fromIndex].remove(link);
|
||||
}
|
||||
inputs.resize(0);
|
||||
}
|
||||
|
||||
/**
|
||||
Removes all outputs and their links from this node.
|
||||
Warning: this function changes the amount of node inputs to 0!
|
||||
**/
|
||||
function clearOutputs() {
|
||||
for (links in outputs) {
|
||||
for (link in links) {
|
||||
var defaultNode = LogicNode.createSocketDefaultNode(tree, link.toType, link.toValue);
|
||||
link.fromNode = defaultNode;
|
||||
link.fromIndex = 0;
|
||||
defaultNode.outputs[0] = [link];
|
||||
}
|
||||
}
|
||||
outputs.resize(0);
|
||||
}
|
||||
|
||||
/**
|
||||
Creates a default node for a socket so that get() and set() can be
|
||||
used without null checks.
|
||||
Loosely equivalent to `make_logic.build_default_node()` in Python.
|
||||
**/
|
||||
static inline function createSocketDefaultNode(tree: LogicTree, socketType: String, value: Dynamic): LogicNode {
|
||||
// Make sure to not add these nodes to the LogicTree.nodes array as they
|
||||
// won't be garbage collected then if unlinked later.
|
||||
return switch (socketType) {
|
||||
case "VECTOR": new armory.logicnode.VectorNode(tree, value[0], value[1], value[2]);
|
||||
case "RGBA": new armory.logicnode.ColorNode(tree, value[0], value[1], value[2], value[3]);
|
||||
case "RGB": new armory.logicnode.ColorNode(tree, value[0], value[1], value[2]);
|
||||
case "VALUE": new armory.logicnode.FloatNode(tree, value);
|
||||
case "INT": new armory.logicnode.IntegerNode(tree, value);
|
||||
case "BOOLEAN": new armory.logicnode.BooleanNode(tree, value);
|
||||
case "STRING": new armory.logicnode.StringNode(tree, value);
|
||||
case "NONE": new armory.logicnode.NullNode(tree);
|
||||
case "OBJECT": new armory.logicnode.ObjectNode(tree, value);
|
||||
default: new armory.logicnode.DynamicNode(tree, value);
|
||||
}
|
||||
}
|
||||
#end
|
||||
|
||||
/**
|
||||
Called when this node is activated.
|
||||
@param from impulse index
|
||||
|
@ -38,42 +143,45 @@ class LogicNode {
|
|||
**/
|
||||
function runOutput(i: Int) {
|
||||
if (i >= outputs.length) return;
|
||||
for (o in outputs[i]) {
|
||||
// Check which input activated the node
|
||||
for (j in 0...o.inputs.length) {
|
||||
if (o.inputs[j].node == this) {
|
||||
o.run(j);
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (outLink in outputs[i]) {
|
||||
outLink.toNode.run(outLink.toIndex);
|
||||
}
|
||||
}
|
||||
|
||||
@:allow(armory.logicnode.LogicNodeInput)
|
||||
@:allow(armory.logicnode.LogicNodeLink)
|
||||
function get(from: Int): Dynamic { return this; }
|
||||
|
||||
@:allow(armory.logicnode.LogicNodeInput)
|
||||
@:allow(armory.logicnode.LogicNodeLink)
|
||||
function set(value: Dynamic) {}
|
||||
}
|
||||
|
||||
class LogicNodeInput {
|
||||
@:allow(armory.logicnode.LogicNode)
|
||||
@:allow(armory.logicnode.LogicTree)
|
||||
class LogicNodeLink {
|
||||
|
||||
@:allow(armory.logicnode.LogicNode)
|
||||
var node: LogicNode;
|
||||
var from: Int; // Socket index
|
||||
var fromNode: LogicNode;
|
||||
var toNode: LogicNode;
|
||||
var fromIndex: Int;
|
||||
var toIndex: Int;
|
||||
|
||||
public function new(node: LogicNode, from: Int) {
|
||||
this.node = node;
|
||||
this.from = from;
|
||||
#if arm_patch
|
||||
var fromType: String;
|
||||
var toType: String;
|
||||
var toValue: Dynamic;
|
||||
#end
|
||||
|
||||
inline function new(fromNode: LogicNode, toNode: LogicNode, fromIndex: Int, toIndex: Int) {
|
||||
this.fromNode = fromNode;
|
||||
this.toNode = toNode;
|
||||
this.fromIndex = fromIndex;
|
||||
this.toIndex = toIndex;
|
||||
}
|
||||
|
||||
@:allow(armory.logicnode.LogicNode)
|
||||
function get(): Dynamic {
|
||||
return node.get(from);
|
||||
inline function get(): Dynamic {
|
||||
return fromNode.get(fromIndex);
|
||||
}
|
||||
|
||||
@:allow(armory.logicnode.LogicNode)
|
||||
function set(value: Dynamic) {
|
||||
node.set(value);
|
||||
inline function set(value: Dynamic) {
|
||||
fromNode.set(value);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,10 +2,26 @@ package armory.logicnode;
|
|||
|
||||
class LogicTree extends iron.Trait {
|
||||
|
||||
#if arm_patch
|
||||
/**
|
||||
Stores all trait instances of the tree via its name.
|
||||
**/
|
||||
public static var nodeTrees = new Map<String, Array<LogicTree>>();
|
||||
|
||||
/**
|
||||
[node name => logic node] for later node replacement for live patching.
|
||||
**/
|
||||
public var nodes: Map<String, LogicNode>;
|
||||
#end
|
||||
|
||||
public var loopBreak = false; // Trigger break from loop nodes
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
|
||||
#if arm_patch
|
||||
nodes = new Map<String, LogicNode>();
|
||||
#end
|
||||
}
|
||||
|
||||
public function add() {}
|
||||
|
|
|
@ -37,6 +37,6 @@ class LookAtNode extends LogicNode {
|
|||
v2.setFrom(vto).sub(vfrom).normalize();
|
||||
|
||||
q.fromTo(v1, v2);
|
||||
return q.getEuler();
|
||||
return q;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ package armory.logicnode;
|
|||
class MathNode extends LogicNode {
|
||||
|
||||
public var property0: String; // Operation
|
||||
public var property1: String; // Clamp
|
||||
public var property1: Bool; // Clamp
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
|
@ -80,8 +80,8 @@ class MathNode extends LogicNode {
|
|||
}
|
||||
}
|
||||
// Clamp
|
||||
if (property1 == "true") r = r < 0.0 ? 0.0 : (r > 1.0 ? 1.0 : r);
|
||||
if (property1) r = r < 0.0 ? 0.0 : (r > 1.0 ? 1.0 : r);
|
||||
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ class MixNode extends LogicNode {
|
|||
|
||||
public var property0: String; // Type
|
||||
public var property1: String; // Ease
|
||||
public var property2: String; // Clamp
|
||||
public var property2: Bool; // Clamp
|
||||
|
||||
var ease: Float->Float = null;
|
||||
|
||||
|
@ -50,7 +50,9 @@ class MixNode extends LogicNode {
|
|||
var v2: Float = inputs[2].get();
|
||||
var f = v1 + (v2 - v1) * ease(k);
|
||||
|
||||
if (property2 == "true") f = f < 0 ? 0 : f > 1 ? 1 : f;
|
||||
// Clamp
|
||||
if (property2) f = f < 0 ? 0 : f > 1 ? 1 : f;
|
||||
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ class ObjectNode extends LogicNode {
|
|||
override function set(value: Dynamic) {
|
||||
if (inputs.length > 0) inputs[0].set(value);
|
||||
else {
|
||||
objectName = value.name;
|
||||
objectName = value != null ? value.name : "";
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import armory.trait.internal.CanvasScript;
|
|||
import iron.Scene;
|
||||
|
||||
#if arm_ui
|
||||
import zui.Canvas.Anchor;
|
||||
import armory.ui.Canvas.Anchor;
|
||||
#end
|
||||
|
||||
class OnCanvasElementNode extends LogicNode {
|
||||
|
|
35
Sources/armory/logicnode/OnInputMapNode.hx
Normal file
35
Sources/armory/logicnode/OnInputMapNode.hx
Normal file
|
@ -0,0 +1,35 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import armory.system.InputMap;
|
||||
|
||||
class OnInputMapNode extends LogicNode {
|
||||
|
||||
var inputMap: Null<InputMap>;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
|
||||
tree.notifyOnUpdate(update);
|
||||
}
|
||||
|
||||
function update() {
|
||||
var i = inputs[0].get();
|
||||
|
||||
inputMap = InputMap.getInputMap(i);
|
||||
|
||||
if (inputMap != null) {
|
||||
if (inputMap.started()) {
|
||||
runOutput(0);
|
||||
}
|
||||
|
||||
if (inputMap.released()) {
|
||||
runOutput(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override function get(from: Int): Dynamic {
|
||||
if (from == 2) return inputMap.value();
|
||||
else return inputMap.lastKeyPressed;
|
||||
}
|
||||
}
|
22
Sources/armory/logicnode/OncePerFrameNode.hx
Normal file
22
Sources/armory/logicnode/OncePerFrameNode.hx
Normal file
|
@ -0,0 +1,22 @@
|
|||
package armory.logicnode;
|
||||
|
||||
class OncePerFrameNode extends LogicNode {
|
||||
|
||||
var c = false;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
tree.notifyOnUpdate(update);
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
if(c) {
|
||||
c = false;
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
||||
|
||||
function update() {
|
||||
c = true;
|
||||
}
|
||||
}
|
|
@ -8,7 +8,7 @@ class PauseTraitNode extends LogicNode {
|
|||
|
||||
override function run(from: Int) {
|
||||
var trait: Dynamic = inputs[1].get();
|
||||
if (trait == null || !Std.is(trait, LogicTree)) return;
|
||||
if (trait == null || !Std.isOfType(trait, LogicTree)) return;
|
||||
|
||||
cast(trait, LogicTree).pause();
|
||||
|
||||
|
|
|
@ -3,50 +3,39 @@ package armory.logicnode;
|
|||
#if arm_physics
|
||||
import armory.trait.physics.bullet.PhysicsConstraint.ConstraintAxis;
|
||||
#end
|
||||
import iron.object.Object;
|
||||
|
||||
class PhysicsConstraintNode extends LogicNode {
|
||||
|
||||
public var property0: String;//Linear or Angular
|
||||
public var property1: String;//Axis
|
||||
public var property2: String;//Is a spring
|
||||
public var value1: Float;//Lower limit or Spring Stiffness
|
||||
public var value2: Float;//Upper limit or Spring Damping
|
||||
public var property0: String; //Linear or Angular
|
||||
public var property1: String; //Axis
|
||||
public var property2: Bool; //Is a spring
|
||||
|
||||
#if arm_physics
|
||||
public var value1: Float; //Lower limit or Spring Stiffness
|
||||
public var value2: Float; //Upper limit or Spring Damping
|
||||
public var isAngular: Bool;
|
||||
public var axis: ConstraintAxis;
|
||||
public var isSpring: Bool;
|
||||
#end
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function get(from: Int): PhysicsConstraintNode {
|
||||
#if arm_physics
|
||||
value1 = inputs[0].get();
|
||||
value2 = inputs[1].get();
|
||||
|
||||
if(property0 == 'Linear') {
|
||||
isAngular = false;
|
||||
}
|
||||
else{
|
||||
isAngular = true;
|
||||
}
|
||||
isAngular = property0 != "Linear";
|
||||
isSpring = property2;
|
||||
|
||||
if(property2 == 'true'){
|
||||
isSpring = true;
|
||||
switch (property1) {
|
||||
case "X": axis = X;
|
||||
case "Y": axis = Y;
|
||||
case "Z": axis = Z;
|
||||
}
|
||||
else {
|
||||
isSpring = false;
|
||||
}
|
||||
|
||||
switch (property1){
|
||||
case 'X':
|
||||
axis = X;
|
||||
case 'Y':
|
||||
axis = Y;
|
||||
case 'Z':
|
||||
axis = Z;
|
||||
}
|
||||
|
||||
#end
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,8 +4,6 @@ import iron.math.Vec4;
|
|||
|
||||
class PickObjectNode extends LogicNode {
|
||||
|
||||
var v = new Vec4();
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
@ -24,9 +22,14 @@ class PickObjectNode extends LogicNode {
|
|||
if (from == 0) { // Object
|
||||
return rb.object;
|
||||
}
|
||||
else { // Hit
|
||||
else if(from == 1){ // Hit
|
||||
var v = new Vec4();
|
||||
return v.set(physics.hitPointWorld.x, physics.hitPointWorld.y, physics.hitPointWorld.z);
|
||||
}
|
||||
else { // Normal
|
||||
var v = new Vec4();
|
||||
return v.set(physics.hitNormalWorld.x, physics.hitNormalWorld.y, physics.hitNormalWorld.z, 0);
|
||||
}
|
||||
#end
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ class QuaternionMathNode extends LogicNode {
|
|||
|
||||
override function get(from: Int): Dynamic {
|
||||
switch (property0) {
|
||||
// 1 argument: Module, Normalize, GetEuler
|
||||
// 1 argument: Module, Normalize
|
||||
case "Module": {
|
||||
var q: Quat = inputs[0].get();
|
||||
if (q == null) return null;
|
||||
|
@ -32,159 +32,106 @@ class QuaternionMathNode extends LogicNode {
|
|||
res_q.setFrom(q);
|
||||
res_q = res_q.normalize();
|
||||
}
|
||||
case "GetEuler": {
|
||||
var q: Quat = inputs[0].get();
|
||||
if (q == null) return null;
|
||||
res_q.setFrom(q);
|
||||
res_v = res_q.getEuler();
|
||||
}
|
||||
// 2 arguments: FromTo, FromMat, FromRotationMat, ToAxisAngle
|
||||
case "FromTo": {
|
||||
var v1: Vec4 = inputs[0].get();
|
||||
var v2: Vec4 = inputs[1].get();
|
||||
if ((v1 == null) || (v2 == null)) return null;
|
||||
res_q.fromTo(v1, v2);
|
||||
}
|
||||
case "FromMat": {
|
||||
var q: Quat = inputs[0].get();
|
||||
var m: Mat4 = inputs[1].get();
|
||||
if ((q == null) || (m == null)) return null;
|
||||
res_q.setFrom(q);
|
||||
res_q = res_q.fromMat(m);
|
||||
}
|
||||
case "FromRotationMat": {
|
||||
var q: Quat = inputs[0].get();
|
||||
var m: Mat4 = inputs[1].get();
|
||||
if ((q == null) || (m == null)) return null;
|
||||
res_q.setFrom(q);
|
||||
res_q = res_q.fromRotationMat(m);
|
||||
}
|
||||
case "ToAxisAngle": {
|
||||
var q: Quat = inputs[0].get();
|
||||
var v: Vec4 = inputs[1].get();
|
||||
if ((q == null) || (v == null)) return null;
|
||||
res_q.setFrom(q);
|
||||
res_f = res_q.toAxisAngle(v);
|
||||
}
|
||||
// # 3 arguments: Lerp, Slerp, FromAxisAngle, FromEuler
|
||||
case "Lerp": {
|
||||
var from: Quat = inputs[0].get();
|
||||
var to: Quat = inputs[1].get();
|
||||
var f: Float = inputs[2].get();
|
||||
if ((from == null) || (to == null)) return null;
|
||||
res_q = res_q.lerp(from, to, f);
|
||||
}
|
||||
case "Slerp": {
|
||||
var from: Quat = inputs[0].get();
|
||||
var to: Quat = inputs[1].get();
|
||||
var f: Float = inputs[2].get();
|
||||
if ((from == null) || (to == null)) return null;
|
||||
res_q = res_q.slerp(from, to, f);
|
||||
}
|
||||
case "FromAxisAngle": {
|
||||
var q: Quat = inputs[0].get();
|
||||
var axis: Vec4 = inputs[1].get();
|
||||
var angle: Float = inputs[2].get();
|
||||
if ((q == null) || (axis == null)) return null;
|
||||
res_q.setFrom(q);
|
||||
res_q = res_q.fromAxisAngle(axis, angle);
|
||||
}
|
||||
case "FromEuler": {
|
||||
var x: Float = inputs[0].get();
|
||||
var y: Float = inputs[1].get();
|
||||
var z: Float = inputs[2].get();
|
||||
res_q = res_q.fromEuler(x, y, z);
|
||||
}
|
||||
// Many arguments: Add, Subtract, DotProduct, Multiply
|
||||
case "Add": {
|
||||
var q: Quat = inputs[0].get();
|
||||
if (q == null) return null;
|
||||
res_q.setFrom(q);
|
||||
var q2 = new Quat();
|
||||
res_v = inputs[0].get();
|
||||
res_f = inputs[1].get();
|
||||
if (res_v == null || res_f == null) return null;
|
||||
|
||||
res_q.set(res_v.x, res_v.y, res_v.z, res_f);
|
||||
var i = 1;
|
||||
while (i < inputs.length) {
|
||||
q2 = inputs[i].get();
|
||||
if (q2 == null) return null;
|
||||
res_q.add(q2);
|
||||
while (2*i+1 < inputs.length) {
|
||||
res_v = inputs[2*i].get();
|
||||
res_f = inputs[2*i+1].get();
|
||||
if (res_v == null || res_f == null) return null;
|
||||
res_q.x += res_v.x;
|
||||
res_q.y += res_v.y;
|
||||
res_q.z += res_v.z;
|
||||
res_q.w += res_f;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
case "Subtract": {
|
||||
var q: Quat = inputs[0].get();
|
||||
if (q == null) return null;
|
||||
res_q.setFrom(q);
|
||||
var q2 = new Quat();
|
||||
res_v = inputs[0].get();
|
||||
res_f = inputs[1].get();
|
||||
if (res_v == null || res_f == null) return null;
|
||||
|
||||
res_q.set(res_v.x, res_v.y, res_v.z, res_f);
|
||||
var i = 1;
|
||||
while (i < inputs.length) {
|
||||
q2 = inputs[i].get();
|
||||
if (q2 == null) return null;
|
||||
res_q.sub(q2);
|
||||
while (2*i+1 < inputs.length) {
|
||||
res_v = inputs[2*i].get();
|
||||
res_f = inputs[2*i+1].get();
|
||||
if (res_v == null || res_f == null) return null;
|
||||
res_q.x -= res_v.x;
|
||||
res_q.y -= res_v.y;
|
||||
res_q.z -= res_v.z;
|
||||
res_q.w -= res_f;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
case "Multiply": {
|
||||
var q: Quat = inputs[0].get();
|
||||
if (q == null) return null;
|
||||
res_q.setFrom(q);
|
||||
var q2 = new Quat();
|
||||
res_v = inputs[0].get();
|
||||
res_f = inputs[1].get();
|
||||
if (res_v == null || res_f == null) return null;
|
||||
|
||||
res_q.set(res_v.x, res_v.y, res_v.z, res_f);
|
||||
var i = 1;
|
||||
while (i < inputs.length) {
|
||||
q2 = inputs[i].get();
|
||||
if (q2 == null) return null;
|
||||
res_q.mult(q2);
|
||||
while (2*i+1 < inputs.length) {
|
||||
res_v = inputs[2*i].get();
|
||||
res_f = inputs[2*i+1].get();
|
||||
if (res_v == null || res_f == null) return null;
|
||||
var temp_q = new Quat(res_v.x, res_v.y, res_v.z, res_f);
|
||||
res_q.mult(temp_q);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
case "MultiplyFloats": {
|
||||
var q: Quat = inputs[0].get();
|
||||
if (q == null) return null;
|
||||
res_q.setFrom(q);
|
||||
res_v = inputs[0].get();
|
||||
res_f = inputs[1].get();
|
||||
if (res_v == null || res_f == null) return null;
|
||||
|
||||
res_q.set(res_v.x, res_v.y, res_v.z, res_f);
|
||||
var f: Float = 1.0;
|
||||
var i = 1;
|
||||
var i = 2;
|
||||
while (i < inputs.length) {
|
||||
f = inputs[i].get();
|
||||
res_q.scale(f);
|
||||
f *= inputs[i].get();
|
||||
if (f == null) return null;
|
||||
i++;
|
||||
}
|
||||
res_q.scale(f);
|
||||
}
|
||||
case "DotProduct": {
|
||||
var q: Quat = inputs[0].get();
|
||||
if (q == null) return null;
|
||||
res_q.setFrom(q);
|
||||
var q2 = new Quat();
|
||||
case "DotProduct": { // what this does with more than 2 terms is not *remotely* intuitive. Heck, you could consider it a footgun!
|
||||
|
||||
res_v = inputs[0].get();
|
||||
var temp_f = inputs[1].get();
|
||||
if (res_v == null || temp_f == null) return null;
|
||||
|
||||
res_q.set(res_v.x, res_v.y, res_v.z, temp_f);
|
||||
var i = 1;
|
||||
while (i < inputs.length) {
|
||||
q2 = inputs[i].get();
|
||||
if (q2 == null) return null;
|
||||
res_f = res_q.dot(q2);
|
||||
while (2*i+1 < inputs.length) {
|
||||
res_v = inputs[2*i].get();
|
||||
temp_f = inputs[2*i+1].get();
|
||||
if (res_v == null || temp_f == null) return null;
|
||||
var temp_q = new Quat(res_v.x, res_v.y, res_v.z, temp_f);
|
||||
res_f = res_q.dot(temp_q);
|
||||
res_q.set(res_f, res_f, res_f, res_f);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Return and check separator
|
||||
switch (from) {
|
||||
case 0: {
|
||||
if (property0 == 'GetEuler')
|
||||
return res_v;
|
||||
else
|
||||
return res_q;
|
||||
return res_q;
|
||||
}
|
||||
case 1:
|
||||
if (property1) {
|
||||
return res_q.x;
|
||||
} else {
|
||||
if (property0 == "DotProduct" || property0 == "Module") {
|
||||
return res_f;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
case 2:
|
||||
if (property1) return res_q.y;
|
||||
case 3:
|
||||
if (property1) return res_q.z;
|
||||
case 4:
|
||||
if (property1) return res_q.w;
|
||||
case 5:
|
||||
if (property1) return res_f;
|
||||
default: {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -11,10 +11,10 @@ class QuaternionNode extends LogicNode {
|
|||
super(tree);
|
||||
|
||||
if (x != null) {
|
||||
addInput(new FloatNode(tree, x), 0);
|
||||
addInput(new FloatNode(tree, y), 0);
|
||||
addInput(new FloatNode(tree, z), 0);
|
||||
addInput(new FloatNode(tree, w), 0);
|
||||
LogicNode.addLink(new FloatNode(tree, x), this, 0, 0);
|
||||
LogicNode.addLink(new FloatNode(tree, y), this, 0, 1);
|
||||
LogicNode.addLink(new FloatNode(tree, z), this, 0, 2);
|
||||
LogicNode.addLink(new FloatNode(tree, w), this, 0, 3);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,15 +27,15 @@ class QuaternionNode extends LogicNode {
|
|||
switch (from){
|
||||
case 0:
|
||||
return value;
|
||||
case 1:
|
||||
var value1 = new Vec4();
|
||||
case 1:
|
||||
var value1 = new Vec4();
|
||||
value1.x = value.x;
|
||||
value1.y = value.y;
|
||||
value1.z = value.z;
|
||||
value1.w = 0; // use 0 to avoid this vector being translated.
|
||||
return value1;
|
||||
case 2:
|
||||
return value.w;
|
||||
return value.w;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -4,18 +4,17 @@ import iron.math.Vec4;
|
|||
|
||||
class RandomColorNode extends LogicNode {
|
||||
|
||||
var v = new Vec4();
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function get(from: Int): Dynamic {
|
||||
|
||||
var r = Math.random();
|
||||
var g = Math.random();
|
||||
var b = Math.random();
|
||||
// var a = Math.random();
|
||||
v.set(r, g, b);
|
||||
var v = new Vec4(r, g, b);
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
|
19
Sources/armory/logicnode/RemoveInputMapKeyNode.hx
Normal file
19
Sources/armory/logicnode/RemoveInputMapKeyNode.hx
Normal file
|
@ -0,0 +1,19 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import armory.system.InputMap;
|
||||
|
||||
class RemoveInputMapKeyNode extends LogicNode {
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
var inputMap = inputs[1].get();
|
||||
var key = inputs[2].get();
|
||||
|
||||
if (InputMap.removeInputMapKey(inputMap, key)) {
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,7 +8,7 @@ class ResumeTraitNode extends LogicNode {
|
|||
|
||||
override function run(from: Int) {
|
||||
var trait: Dynamic = inputs[1].get();
|
||||
if (trait == null || !Std.is(trait, LogicTree)) return;
|
||||
if (trait == null || !Std.isOfType(trait, LogicTree)) return;
|
||||
|
||||
cast(trait, LogicTree).resume();
|
||||
|
||||
|
|
|
@ -2,13 +2,11 @@ package armory.logicnode;
|
|||
|
||||
import iron.object.Object;
|
||||
import iron.math.Quat;
|
||||
import iron.math.Vec4;
|
||||
import armory.trait.physics.RigidBody;
|
||||
|
||||
class RotateObjectNode extends LogicNode {
|
||||
|
||||
public var property0 = "Euler Angles";
|
||||
var q = new Quat();
|
||||
public var property0 = "Local";
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
|
@ -16,32 +14,19 @@ class RotateObjectNode extends LogicNode {
|
|||
|
||||
override function run(from: Int) {
|
||||
var object: Object = inputs[1].get();
|
||||
var vec: Vec4 = inputs[2].get();
|
||||
var q: Quat = inputs[2].get();
|
||||
|
||||
// note: here, the next line is disabled because old versions of the node don't have a third input.
|
||||
// when those old versions will be considered remove, feel free to uncomment that, and replace the other `inputs[3].get()` by `w` in this file.
|
||||
//var w: Float = inputs[3].get();
|
||||
if (object == null || q == null) return;
|
||||
|
||||
if (object == null || vec == null) return;
|
||||
|
||||
switch (property0) {
|
||||
case "Euler Angles":
|
||||
q.fromEuler(vec.x, vec.y, vec.z);
|
||||
case "Angle Axies (Degrees)" | "Angle Axies (Radians)":
|
||||
var angle: Float = inputs[3].get();
|
||||
if (property0 == "Angle Axies (Degrees)") {
|
||||
angle = angle * (Math.PI / 180);
|
||||
}
|
||||
var angleSin = Math.sin(angle / 2);
|
||||
vec = vec.normalize();
|
||||
var angleCos = Math.cos(angle / 2);
|
||||
q = new Quat(vec.x * angleSin, vec.y * angleSin, vec.z * angleSin, angleCos);
|
||||
case "Quaternion":
|
||||
q = new Quat(vec.x, vec.y, vec.z, inputs[3].get());
|
||||
q.normalize();
|
||||
q.normalize();
|
||||
switch (property0){
|
||||
case "Local":
|
||||
object.transform.rot.mult(q);
|
||||
case "Global":
|
||||
object.transform.rot.multquats(q, object.transform.rot);
|
||||
// that function call (Quat.multquats) is weird: it both modifies the object, and returns `this`
|
||||
}
|
||||
|
||||
object.transform.rot.mult(q);
|
||||
|
||||
object.transform.buildMatrix();
|
||||
|
||||
#if arm_physics
|
||||
|
|
96
Sources/armory/logicnode/RotationMathNode.hx
Normal file
96
Sources/armory/logicnode/RotationMathNode.hx
Normal file
|
@ -0,0 +1,96 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.math.Quat;
|
||||
import iron.math.Vec4;
|
||||
import iron.math.Mat4;
|
||||
import kha.FastFloat;
|
||||
|
||||
class RotationMathNode extends LogicNode {
|
||||
|
||||
public var property0: String; // Operation
|
||||
var res_q = new Quat();
|
||||
var res_v = new Vec4();
|
||||
var res_f: FastFloat = 0.0;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function get(from: Int): Dynamic {
|
||||
//var q: Quat = inputs[0].get();
|
||||
//if (q==null) return null;
|
||||
|
||||
//var res_q: Quat = new Quat();
|
||||
switch (property0) {
|
||||
// 1 argument: Normalize, Inverse
|
||||
case "Normalize": {
|
||||
var q: Quat = inputs[0].get();
|
||||
if (q==null) return null;
|
||||
res_q.setFrom(q);
|
||||
res_q = res_q.normalize();
|
||||
}
|
||||
case "Inverse": {
|
||||
var q: Quat = inputs[0].get();
|
||||
if (q==null) return null;
|
||||
var modl = q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w;
|
||||
modl = -1/modl;
|
||||
res_q.w = -q.w*modl;
|
||||
res_q.x = q.x*modl;
|
||||
res_q.y = q.y*modl;
|
||||
res_q.z = q.z*modl;
|
||||
}
|
||||
// 2 arguments: Compose, Amplify, FromTo, FromRotationMat,
|
||||
case "FromTo": {
|
||||
var v1: Vec4 = inputs[0].get();
|
||||
var v2: Vec4 = inputs[1].get();
|
||||
if ((v1 == null) || (v2 == null)) return null;
|
||||
res_q.fromTo(v1, v2);
|
||||
}
|
||||
case "Compose": {
|
||||
var v1: Quat = inputs[0].get();
|
||||
var v2: Quat = inputs[1].get();
|
||||
if ((v1 == null) || (v2 == null)) return null;
|
||||
res_q.multquats(v1,v2);
|
||||
}
|
||||
case "Amplify": {
|
||||
var v1: Quat = inputs[0].get();
|
||||
var v2: Float = inputs[1].get();
|
||||
if ((v1 == null) || (v2 == null)) return null;
|
||||
res_q.setFrom(v1);
|
||||
var fac2 = Math.sqrt(1- res_q.w*res_q.w);
|
||||
if (fac2 > 0.001) {
|
||||
var fac1 = v2*Math.acos(res_q.w);
|
||||
res_q.w = Math.cos(fac1);
|
||||
fac1 = Math.sin(fac1)/fac2;
|
||||
res_q.x *= fac1;
|
||||
res_q.y *= fac1;
|
||||
res_q.z *= fac1;
|
||||
}
|
||||
}
|
||||
//case "FromRotationMat": {
|
||||
// var m: Mat4 = inputs[1].get();
|
||||
// if (m == null) return null;
|
||||
|
||||
// res_q = res_q.fromMat(m);
|
||||
//}
|
||||
// # 3 arguments: Lerp, Slerp, FromAxisAngle, FromEuler
|
||||
case "Lerp": {
|
||||
//var from = q;
|
||||
var from: Quat = inputs[0].get();
|
||||
var to: Quat = inputs[1].get();
|
||||
var f: Float = inputs[2].get();
|
||||
if ((from == null) || (f == null) || (to == null)) return null;
|
||||
res_q = res_q.lerp(from, to, f);
|
||||
}
|
||||
case "Slerp": {
|
||||
//var from = q;
|
||||
var from:Quat = inputs[0].get();
|
||||
var to: Quat = inputs[1].get();
|
||||
var f: Float = inputs[2].get();
|
||||
if ((from == null) || (f == null) || (to == null)) return null;
|
||||
res_q = res_q.slerp(from, to, f);
|
||||
}
|
||||
}
|
||||
return res_q;
|
||||
}
|
||||
}
|
120
Sources/armory/logicnode/RotationNode.hx
Normal file
120
Sources/armory/logicnode/RotationNode.hx
Normal file
|
@ -0,0 +1,120 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.math.Vec4;
|
||||
import iron.math.Quat;
|
||||
import kha.FastFloat;
|
||||
|
||||
class RotationNode extends LogicNode {
|
||||
|
||||
static inline var toRAD: FastFloat = 0.017453292519943295; // 180/pi
|
||||
|
||||
public var property0: String; // type of input (EulerAngles, AxisAngle, Quaternion)
|
||||
public var property1: String; // angle unit (Deg, Rad)
|
||||
public var property2: String; // euler order (XYZ, XZY, etc…)
|
||||
|
||||
public var value: Quat;
|
||||
//var input0_cache: Vec4 = new Vec4();
|
||||
//var input1_cache: Float = 0;
|
||||
var input_length: Int = 0;
|
||||
|
||||
public function new(tree: LogicTree, x: Null<Float> = null,
|
||||
y: Null<Float> = null,
|
||||
z: Null<Float> = null,
|
||||
w: Null<Float> = null
|
||||
) {
|
||||
super(tree);
|
||||
this.value = new Quat();
|
||||
if (x!=null) this.value.set(x,y,z,w);
|
||||
for (input in inputs) {
|
||||
if (input !=null)
|
||||
this.input_length +=1;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
override function get(from: Int): Dynamic {
|
||||
//var inp0 = inputs[0].get();
|
||||
//var inp
|
||||
//if (inputs[0].get())
|
||||
if (inputs.length == 0){
|
||||
return this.value;
|
||||
}
|
||||
|
||||
switch (property0){
|
||||
case "Quaternion": {
|
||||
if (inputs[0]!=null && inputs[1]!=null) {
|
||||
var vect: Vec4 = inputs[0].get();
|
||||
value.x = vect.x;
|
||||
value.y = vect.y;
|
||||
value.z = vect.z;
|
||||
value.w = inputs[1].get();
|
||||
}
|
||||
}
|
||||
case "AxisAngle": {
|
||||
if (inputs[0]!=null && inputs[1]!=null){
|
||||
var vec: Vec4 = inputs[0].get();
|
||||
var angle: FastFloat = inputs[1].get();
|
||||
if (property1=="Deg")
|
||||
angle *= toRAD;
|
||||
value.fromAxisAngle(vec, angle);
|
||||
}
|
||||
}
|
||||
case "EulerAngles": {
|
||||
if (inputs[0] != null){
|
||||
var vec: Vec4 = new Vec4().setFrom(inputs[0].get());
|
||||
if (property1=="Deg"){
|
||||
vec.x *= toRAD;
|
||||
vec.y *= toRAD;
|
||||
vec.z *= toRAD;
|
||||
}
|
||||
this.value.fromEulerOrdered(vec, property2);
|
||||
}
|
||||
}
|
||||
default: {
|
||||
return property0;
|
||||
}
|
||||
}
|
||||
return this.value;
|
||||
}
|
||||
|
||||
override function set(value: Dynamic) {
|
||||
switch (property0){
|
||||
case "Quaternion": {
|
||||
if (input_length>1) {
|
||||
var vect = new Vec4();
|
||||
vect.x = value.x;
|
||||
vect.y = value.y;
|
||||
vect.z = value.z;
|
||||
inputs[0].set(vect);
|
||||
inputs[1].set(value.w);
|
||||
}
|
||||
}
|
||||
case "AxisAngle": {
|
||||
if (input_length>1){
|
||||
var vec = new Vec4();
|
||||
var angle = this.value.toAxisAngle(vec);
|
||||
if (property1=="Deg")
|
||||
angle /= toRAD;
|
||||
inputs[0].set(vec);
|
||||
inputs[1].set(angle);
|
||||
|
||||
}
|
||||
}
|
||||
case "EulerAngles": {
|
||||
if (input_length>0){
|
||||
var vec:Vec4 = value.toEulerOrdered(property2);
|
||||
if (property1=="Deg"){
|
||||
vec.x /= toRAD;
|
||||
vec.y /= toRAD;
|
||||
vec.z /= toRAD;
|
||||
}
|
||||
inputs[0].set(vec);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (input_length > 0){
|
||||
// NYI
|
||||
}else this.value=value;
|
||||
}
|
||||
}
|
37
Sources/armory/logicnode/SelectNode.hx
Normal file
37
Sources/armory/logicnode/SelectNode.hx
Normal file
|
@ -0,0 +1,37 @@
|
|||
package armory.logicnode;
|
||||
|
||||
class SelectNode extends LogicNode {
|
||||
|
||||
/** Execution mode. **/
|
||||
public var property0: String;
|
||||
|
||||
var value: Dynamic = null;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
// Get value according to the activated input (run() can only be called
|
||||
// if the execution mode is from_input).
|
||||
value = inputs[from + Std.int(inputs.length / 2)].get();
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
|
||||
override function get(from: Int): Dynamic {
|
||||
if (property0 == "from_index") {
|
||||
var index = inputs[0].get() + 2;
|
||||
|
||||
// Return default value for invalid index
|
||||
if (index < 2 || index >= inputs.length) {
|
||||
return inputs[1].get();
|
||||
}
|
||||
|
||||
return inputs[index].get();
|
||||
}
|
||||
|
||||
// from_input
|
||||
return value;
|
||||
}
|
||||
}
|
60
Sources/armory/logicnode/SeparateRotationNode.hx
Normal file
60
Sources/armory/logicnode/SeparateRotationNode.hx
Normal file
|
@ -0,0 +1,60 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import kha.FastFloat;
|
||||
import iron.math.Quat;
|
||||
import iron.math.Vec4;
|
||||
|
||||
class SeparateRotationNode extends LogicNode {
|
||||
|
||||
public var property0 = "EulerAngles"; // EulerAngles, AxisAngle, or Quat
|
||||
public var property1 = "Rad"; // Rad or Deg
|
||||
public var property2 = "XYZ";
|
||||
|
||||
static inline var toDEG:FastFloat = 57.29577951308232; // 180/pi
|
||||
|
||||
var input_cache = new Quat();
|
||||
var euler_cache = new Vec4();
|
||||
var aa_axis_cache = new Vec4();
|
||||
var aa_angle_cache: Float = 0;
|
||||
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function get(from: Int): Dynamic {
|
||||
var q: Quat = inputs[0].get();
|
||||
if (q == null) return null;
|
||||
q.normalize();
|
||||
|
||||
switch (property0) {
|
||||
case "EulerAngles":
|
||||
if (q!=this.input_cache)
|
||||
euler_cache = q.toEulerOrdered(property2);
|
||||
if (from>0)
|
||||
return null;
|
||||
|
||||
switch (property1){
|
||||
case "Rad": return euler_cache;
|
||||
case "Deg": return new Vec4(euler_cache.x*toDEG, euler_cache.y*toDEG, euler_cache.z*toDEG);
|
||||
}
|
||||
|
||||
case "AxisAngle":
|
||||
if (q!=this.input_cache)
|
||||
aa_angle_cache = q.toAxisAngle(aa_axis_cache);
|
||||
switch (from){
|
||||
case 0: return aa_axis_cache;
|
||||
case 1: switch(property1){
|
||||
case "Rad": return aa_angle_cache;
|
||||
case "Deg": return toDEG*aa_angle_cache;
|
||||
}
|
||||
}
|
||||
case "Quaternion":
|
||||
switch(from){
|
||||
case 0: return new Vec4(q.x,q.y,q.z);
|
||||
case 1: return q.w;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -20,7 +20,7 @@ class SeparateTransformNode extends LogicNode {
|
|||
matrix.decompose(loc, rot, scale);
|
||||
|
||||
if (from == 0) return loc;
|
||||
else if (from == 1) return rot.getEuler();
|
||||
else if (from == 1) return rot;
|
||||
else return scale;
|
||||
}
|
||||
}
|
||||
|
|
25
Sources/armory/logicnode/SetGlobalCanvasFontSizeNode.hx
Normal file
25
Sources/armory/logicnode/SetGlobalCanvasFontSizeNode.hx
Normal file
|
@ -0,0 +1,25 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.Scene;
|
||||
import armory.trait.internal.CanvasScript;
|
||||
|
||||
class SetGlobalCanvasFontSizeNode extends LogicNode {
|
||||
|
||||
var canvas: CanvasScript;
|
||||
var factor: Int;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
#if arm_ui
|
||||
override function run(from: Int) {
|
||||
factor = inputs[1].get();
|
||||
canvas = Scene.active.getTrait(CanvasScript);
|
||||
if (canvas == null) canvas = Scene.active.camera.getTrait(CanvasScript);
|
||||
|
||||
canvas.setCanvasFontSize(factor);
|
||||
runOutput(0);
|
||||
}
|
||||
#end
|
||||
}
|
25
Sources/armory/logicnode/SetGlobalCanvasScaleNode.hx
Normal file
25
Sources/armory/logicnode/SetGlobalCanvasScaleNode.hx
Normal file
|
@ -0,0 +1,25 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.Scene;
|
||||
import armory.trait.internal.CanvasScript;
|
||||
|
||||
class SetGlobalCanvasScaleNode extends LogicNode {
|
||||
|
||||
var canvas: CanvasScript;
|
||||
var factor: Float;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
#if arm_ui
|
||||
override function run(from: Int) {
|
||||
factor = inputs[1].get();
|
||||
canvas = Scene.active.getTrait(CanvasScript);
|
||||
if (canvas == null) canvas = Scene.active.camera.getTrait(CanvasScript);
|
||||
|
||||
canvas.setUiScale(factor);
|
||||
runOutput(0);
|
||||
}
|
||||
#end
|
||||
}
|
46
Sources/armory/logicnode/SetInputMapKeyNode.hx
Normal file
46
Sources/armory/logicnode/SetInputMapKeyNode.hx
Normal file
|
@ -0,0 +1,46 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import armory.system.InputMap;
|
||||
|
||||
class SetInputMapKeyNode extends LogicNode {
|
||||
|
||||
public var property0: String;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
var inputMap = inputs[1].get();
|
||||
var key = inputs[2].get();
|
||||
var scale = inputs[3].get();
|
||||
var deadzone = inputs[4].get();
|
||||
var index = inputs[5].get();
|
||||
|
||||
var i = InputMap.getInputMap(inputMap);
|
||||
|
||||
if (i == null) {
|
||||
i = InputMap.addInputMap(inputMap);
|
||||
}
|
||||
|
||||
var k = InputMap.getInputMapKey(inputMap, key);
|
||||
|
||||
if (k == null) {
|
||||
switch(property0) {
|
||||
case "keyboard": k = i.addKeyboard(key, scale);
|
||||
case "mouse": k = i.addMouse(key, scale, deadzone);
|
||||
case "gamepad": {
|
||||
k = i.addGamepad(key, scale, deadzone);
|
||||
k.setIndex(index);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
k.scale = scale;
|
||||
k.deadzone = deadzone;
|
||||
k.setIndex(index);
|
||||
}
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
|
@ -13,9 +13,21 @@ class SetLocationNode extends LogicNode {
|
|||
override function run(from: Int) {
|
||||
var object: Object = inputs[1].get();
|
||||
var vec: Vec4 = inputs[2].get();
|
||||
var relative: Bool = inputs[3].get();
|
||||
|
||||
if (object == null || vec == null) return;
|
||||
|
||||
if (!relative && object.parent != null) {
|
||||
var loc = vec.clone();
|
||||
loc.sub(object.parent.transform.world.getLoc()); // Remove parent location influence
|
||||
|
||||
// Convert vec to parent local space
|
||||
var dotX = loc.dot(object.parent.transform.right());
|
||||
var dotY = loc.dot(object.parent.transform.look());
|
||||
var dotZ = loc.dot(object.parent.transform.up());
|
||||
vec.set(dotX, dotY, dotZ);
|
||||
}
|
||||
|
||||
object.transform.loc.setFrom(vec);
|
||||
object.transform.buildMatrix();
|
||||
|
||||
|
@ -26,4 +38,4 @@ class SetLocationNode extends LogicNode {
|
|||
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,40 +1,40 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.Scene;
|
||||
import iron.data.MaterialData;
|
||||
import iron.object.Object;
|
||||
import armory.trait.internal.UniformsManager;
|
||||
|
||||
class SetMaterialImageParamNode extends LogicNode {
|
||||
|
||||
static var registered = false;
|
||||
static var map = new Map<MaterialData, Map<String, kha.Image>>();
|
||||
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
if (!registered) {
|
||||
registered = true;
|
||||
iron.object.Uniforms.externalTextureLinks.push(textureLink);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
var mat = inputs[1].get();
|
||||
if (mat == null) return;
|
||||
var entry = map.get(mat);
|
||||
if (entry == null) {
|
||||
entry = new Map();
|
||||
map.set(mat, entry);
|
||||
var perObject: Null<Bool>;
|
||||
|
||||
var object = inputs[1].get();
|
||||
if(object == null) return;
|
||||
|
||||
perObject = inputs[2].get();
|
||||
if(perObject == null) perObject = false;
|
||||
|
||||
var mat = inputs[3].get();
|
||||
if(mat == null) return;
|
||||
|
||||
if(! perObject){
|
||||
UniformsManager.removeObjectFromMap(object, Texture);
|
||||
object = Scene.active.root;
|
||||
}
|
||||
|
||||
iron.data.Data.getImage(inputs[3].get(), function(image: kha.Image) {
|
||||
entry.set(inputs[2].get(), image); // Node name, value
|
||||
var img = inputs[5].get();
|
||||
if(img == null) return;
|
||||
iron.data.Data.getImage(img, function(image: kha.Image) {
|
||||
UniformsManager.setTextureValue(mat, object, inputs[4].get(), image);
|
||||
});
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
|
||||
static function textureLink(object: Object, mat: MaterialData, link: String): kha.Image {
|
||||
if (mat == null) return null;
|
||||
var entry = map.get(mat);
|
||||
if (entry == null) return null;
|
||||
return entry.get(link);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,38 +1,35 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.Scene;
|
||||
import iron.math.Vec4;
|
||||
import iron.data.MaterialData;
|
||||
import iron.object.Object;
|
||||
import armory.trait.internal.UniformsManager;
|
||||
|
||||
class SetMaterialRgbParamNode extends LogicNode {
|
||||
|
||||
static var registered = false;
|
||||
static var map = new Map<MaterialData, Map<String, Vec4>>();
|
||||
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
if (!registered) {
|
||||
registered = true;
|
||||
iron.object.Uniforms.externalVec3Links.push(vec3Link);
|
||||
}
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
var mat = inputs[1].get();
|
||||
if (mat == null) return;
|
||||
var entry = map.get(mat);
|
||||
if (entry == null) {
|
||||
entry = new Map();
|
||||
map.set(mat, entry);
|
||||
var perObject: Null<Bool>;
|
||||
|
||||
var object = inputs[1].get();
|
||||
if(object == null) return;
|
||||
|
||||
perObject = inputs[2].get();
|
||||
if(perObject == null) perObject = false;
|
||||
|
||||
var mat = inputs[3].get();
|
||||
if(mat == null) return;
|
||||
|
||||
if(! perObject){
|
||||
UniformsManager.removeObjectFromMap(object, Vector);
|
||||
object = Scene.active.root;
|
||||
}
|
||||
entry.set(inputs[2].get(), inputs[3].get()); // Node name, value
|
||||
|
||||
UniformsManager.setVec3Value(mat, object, inputs[4].get(), inputs[5].get());
|
||||
runOutput(0);
|
||||
}
|
||||
|
||||
static function vec3Link(object: Object, mat: MaterialData, link: String): iron.math.Vec4 {
|
||||
if (mat == null) return null;
|
||||
var entry = map.get(mat);
|
||||
if (entry == null) return null;
|
||||
return entry.get(link);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,37 +1,35 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.Scene;
|
||||
import iron.data.MaterialData;
|
||||
import iron.object.Object;
|
||||
import armory.trait.internal.UniformsManager;
|
||||
|
||||
class SetMaterialValueParamNode extends LogicNode {
|
||||
|
||||
static var registered = false;
|
||||
static var map = new Map<MaterialData, Map<String, Null<kha.FastFloat>>>();
|
||||
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
if (!registered) {
|
||||
registered = true;
|
||||
iron.object.Uniforms.externalFloatLinks.push(floatLink);
|
||||
}
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
var mat = inputs[1].get();
|
||||
if (mat == null) return;
|
||||
var entry = map.get(mat);
|
||||
if (entry == null) {
|
||||
entry = new Map();
|
||||
map.set(mat, entry);
|
||||
var perObject: Null<Bool>;
|
||||
|
||||
var object = inputs[1].get();
|
||||
if(object == null) return;
|
||||
|
||||
perObject = inputs[2].get();
|
||||
if(perObject == null) perObject = false;
|
||||
|
||||
var mat = inputs[3].get();
|
||||
if(mat == null) return;
|
||||
|
||||
if(! perObject){
|
||||
UniformsManager.removeObjectFromMap(object, Float);
|
||||
object = Scene.active.root;
|
||||
}
|
||||
entry.set(inputs[2].get(), inputs[3].get()); // Node name, value
|
||||
|
||||
UniformsManager.setFloatValue(mat, object, inputs[4].get(), inputs[5].get());
|
||||
runOutput(0);
|
||||
}
|
||||
|
||||
static function floatLink(object: Object, mat: MaterialData, link: String): Null<kha.FastFloat> {
|
||||
if (mat == null) return null;
|
||||
var entry = map.get(mat);
|
||||
if (entry == null) return null;
|
||||
return entry.get(link);
|
||||
}
|
||||
}
|
||||
|
|
25
Sources/armory/logicnode/SetObjectShapeKeyNode.hx
Normal file
25
Sources/armory/logicnode/SetObjectShapeKeyNode.hx
Normal file
|
@ -0,0 +1,25 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.object.MeshObject;
|
||||
|
||||
class SetObjectShapeKeyNode extends LogicNode {
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
#if arm_morph_target
|
||||
var object: Dynamic = inputs[1].get();
|
||||
var shapeKey: String = inputs[2].get();
|
||||
var value: Dynamic = inputs[3].get();
|
||||
|
||||
assert(Error, object != null, "Object should not be null");
|
||||
var morph = cast(object, MeshObject).morphTarget;
|
||||
|
||||
assert(Error, morph != null, "Object does not have shape keys");
|
||||
morph.setMorphValue(shapeKey, value);
|
||||
#end
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
|
@ -14,8 +14,9 @@ class SetParentNode extends LogicNode {
|
|||
|
||||
var parent: Object;
|
||||
var isUnparent = false;
|
||||
if (Std.is(inputs[2].node, ObjectNode)) {
|
||||
var parentNode = cast(inputs[2].node, ObjectNode);
|
||||
|
||||
if (Std.isOfType(inputs[2].fromNode, ObjectNode)) {
|
||||
var parentNode = cast(inputs[2].fromNode, ObjectNode);
|
||||
isUnparent = parentNode.objectName == "";
|
||||
}
|
||||
if (isUnparent) parent = iron.Scene.active.root;
|
||||
|
@ -24,7 +25,7 @@ class SetParentNode extends LogicNode {
|
|||
if (object == null || parent == null || object.parent == parent) return;
|
||||
|
||||
object.parent.removeChild(object, isUnparent); // keepTransform
|
||||
|
||||
|
||||
#if arm_physics
|
||||
var rigidBody = object.getTrait(RigidBody);
|
||||
if (rigidBody != null) rigidBody.setActivationState(0);
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
|
||||
package armory.logicnode;
|
||||
|
||||
import iron.object.Object;
|
||||
import iron.math.Quat;
|
||||
import iron.math.Vec4;
|
||||
import armory.trait.physics.RigidBody;
|
||||
|
||||
class SetRotationNode extends LogicNode {
|
||||
|
||||
public var property0: String;
|
||||
public var property0: String; // UNUSED
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
|
@ -16,27 +16,13 @@ class SetRotationNode extends LogicNode {
|
|||
override function run(from: Int) {
|
||||
var object: Object = inputs[1].get();
|
||||
if (object == null) return;
|
||||
var vec: Vec4 = inputs[2].get();
|
||||
if (vec == null) return;
|
||||
var w: Float = inputs[3].get();
|
||||
var q: Quat = inputs[2].get();
|
||||
if (q == null) return;
|
||||
|
||||
switch (property0) {
|
||||
case "Euler Angles":
|
||||
object.transform.rot.fromEuler(vec.x, vec.y, vec.z);
|
||||
case "Angle Axies (Degrees)" | "Angle Axies (Radians)":
|
||||
var angle: Float = w;
|
||||
if (property0 == "Angle Axies (Degrees)") {
|
||||
angle = angle * (Math.PI / 180);
|
||||
}
|
||||
var angleSin = Math.sin(angle / 2);
|
||||
vec = vec.normalize();
|
||||
var angleCos = Math.cos(angle / 2);
|
||||
object.transform.rot = new Quat(vec.x * angleSin, vec.y * angleSin, vec.z * angleSin, angleCos);
|
||||
case "Quaternion":
|
||||
object.transform.rot = new Quat(vec.x, vec.y, vec.z, w);
|
||||
object.transform.rot.normalize();
|
||||
}
|
||||
q.normalize();
|
||||
object.transform.rot = q;
|
||||
object.transform.buildMatrix();
|
||||
|
||||
#if arm_physics
|
||||
var rigidBody = object.getTrait(RigidBody);
|
||||
if (rigidBody != null) {
|
||||
|
|
|
@ -10,7 +10,7 @@ class SetTraitPausedNode extends LogicNode {
|
|||
var trait: Dynamic = inputs[1].get();
|
||||
var paused: Bool = inputs[2].get();
|
||||
|
||||
if (trait == null || !Std.is(trait, LogicTree)) return;
|
||||
if (trait == null || !Std.isOfType(trait, LogicTree)) return;
|
||||
|
||||
paused ? cast(trait, LogicTree).pause() : cast(trait, LogicTree).resume();
|
||||
|
||||
|
|
|
@ -7,9 +7,9 @@ import iron.math.Quat;
|
|||
class TransformNode extends LogicNode {
|
||||
|
||||
var value: Mat4 = Mat4.identity();
|
||||
static var q = new Quat();
|
||||
static var v1 = new Vec4();
|
||||
static var v2 = new Vec4();
|
||||
var q = new Quat();
|
||||
var v1 = new Vec4();
|
||||
var v2 = new Vec4();
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
|
@ -17,18 +17,21 @@ class TransformNode extends LogicNode {
|
|||
|
||||
override function get(from: Int): Dynamic {
|
||||
var loc: Vec4 = inputs[0].get();
|
||||
var rot: Vec4 = inputs[1].get();
|
||||
var rot: Quat = new Quat().setFrom(inputs[1].get());
|
||||
rot.normalize();
|
||||
var scale: Vec4 = inputs[2].get();
|
||||
if (loc == null && rot == null && scale == null) return this.value;
|
||||
if (loc == null || rot == null || scale == null) return null;
|
||||
q.fromEuler(rot.x, rot.y, rot.z);
|
||||
value.compose(loc, q, scale);
|
||||
return value;
|
||||
this.value.compose(loc, rot, scale);
|
||||
return this.value;
|
||||
}
|
||||
|
||||
override function set(value: Dynamic) {
|
||||
cast(value, Mat4).decompose(v1, q, v2);
|
||||
inputs[0].set(v1);
|
||||
inputs[1].set(q.getEuler());
|
||||
inputs[2].set(v2);
|
||||
if (inputs.length>0){
|
||||
cast(value, Mat4).decompose(v1, q, v2);
|
||||
inputs[0].set(v1);
|
||||
inputs[1].set(q);
|
||||
inputs[2].set(v2);
|
||||
}else this.value = value;
|
||||
}
|
||||
}
|
||||
|
|
114
Sources/armory/logicnode/TweenFloatNode.hx
Normal file
114
Sources/armory/logicnode/TweenFloatNode.hx
Normal file
|
@ -0,0 +1,114 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.system.Tween;
|
||||
|
||||
class TweenFloatNode extends LogicNode {
|
||||
|
||||
public var property0:String;
|
||||
|
||||
public var anim: TAnim;
|
||||
public var fromValue:Float = 0.0;
|
||||
public var toValue:Float = 1.0;
|
||||
public var duration:Float = 1.0;
|
||||
|
||||
public function new(tree:LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from:Int) {
|
||||
|
||||
if(from == 0){
|
||||
|
||||
if(anim != null){
|
||||
Tween.stop(anim);
|
||||
}
|
||||
|
||||
fromValue = inputs[2].get();
|
||||
toValue = inputs[3].get();
|
||||
duration = inputs[4].get();
|
||||
var type:Dynamic = Linear;
|
||||
|
||||
switch (property0) {
|
||||
case "Linear":
|
||||
type = Linear;
|
||||
case "SineIn":
|
||||
type = SineIn;
|
||||
case "SineOut":
|
||||
type = SineOut;
|
||||
case "SineInOut":
|
||||
type = SineInOut;
|
||||
case "QuadIn":
|
||||
type = QuadIn;
|
||||
case "QuadOut":
|
||||
type = QuadOut;
|
||||
case "QuadInOut":
|
||||
type = QuadInOut;
|
||||
case "CubicIn":
|
||||
type = CubicIn;
|
||||
case "CubicOut":
|
||||
type = CubicOut;
|
||||
case "CubicInOut":
|
||||
type = CubicInOut;
|
||||
case "QuartIn":
|
||||
type = QuartIn;
|
||||
case "QuartOut":
|
||||
type = QuartOut;
|
||||
case "QuartInOut":
|
||||
type = QuartInOut;
|
||||
case "QuintIn":
|
||||
type = QuintIn;
|
||||
case "QuintOut":
|
||||
type = QuintOut;
|
||||
case "QuintInOut":
|
||||
type = QuintInOut;
|
||||
case "ExpoIn":
|
||||
type = ExpoIn;
|
||||
case "ExpoOut":
|
||||
type = ExpoOut;
|
||||
case "ExpoInOut":
|
||||
type = ExpoInOut;
|
||||
case "CircIn":
|
||||
type = CircIn;
|
||||
case "CircOut":
|
||||
type = CircOut;
|
||||
case "CircInOut":
|
||||
type = CircInOut;
|
||||
case "BackIn":
|
||||
type = BackIn;
|
||||
case "BackOut":
|
||||
type = BackOut;
|
||||
case "BackInOut":
|
||||
type = BackInOut;
|
||||
}
|
||||
|
||||
anim = Tween.to({
|
||||
target: this,
|
||||
props: { fromValue: toValue },
|
||||
duration: duration,
|
||||
ease: type,
|
||||
tick: update,
|
||||
done: done
|
||||
});
|
||||
}
|
||||
else{
|
||||
if(anim != null){
|
||||
Tween.stop(anim);
|
||||
}
|
||||
}
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
|
||||
override function get(from: Int): Dynamic {
|
||||
if(from == 3) return fromValue;
|
||||
return null;
|
||||
}
|
||||
|
||||
function update() {
|
||||
runOutput(1);
|
||||
}
|
||||
|
||||
function done() {
|
||||
runOutput(2);
|
||||
}
|
||||
}
|
116
Sources/armory/logicnode/TweenRotationNode.hx
Normal file
116
Sources/armory/logicnode/TweenRotationNode.hx
Normal file
|
@ -0,0 +1,116 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.math.Quat;
|
||||
import iron.system.Tween;
|
||||
|
||||
class TweenRotationNode extends LogicNode {
|
||||
|
||||
public var property0:String;
|
||||
|
||||
public var anim: TAnim;
|
||||
public var fromValue:Quat = new Quat();
|
||||
public var toValue:Quat = new Quat();
|
||||
public var duration:Float = 1.0;
|
||||
|
||||
public function new(tree:LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from:Int) {
|
||||
|
||||
if(from == 0){
|
||||
|
||||
if(anim != null){
|
||||
Tween.stop(anim);
|
||||
}
|
||||
|
||||
fromValue.setFrom(inputs[2].get());
|
||||
toValue.setFrom(inputs[3].get());
|
||||
duration = inputs[4].get();
|
||||
var type:Dynamic = Linear;
|
||||
|
||||
switch (property0) {
|
||||
case "Linear":
|
||||
type = Linear;
|
||||
case "SineIn":
|
||||
type = SineIn;
|
||||
case "SineOut":
|
||||
type = SineOut;
|
||||
case "SineInOut":
|
||||
type = SineInOut;
|
||||
case "QuadIn":
|
||||
type = QuadIn;
|
||||
case "QuadOut":
|
||||
type = QuadOut;
|
||||
case "QuadInOut":
|
||||
type = QuadInOut;
|
||||
case "CubicIn":
|
||||
type = CubicIn;
|
||||
case "CubicOut":
|
||||
type = CubicOut;
|
||||
case "CubicInOut":
|
||||
type = CubicInOut;
|
||||
case "QuartIn":
|
||||
type = QuartIn;
|
||||
case "QuartOut":
|
||||
type = QuartOut;
|
||||
case "QuartInOut":
|
||||
type = QuartInOut;
|
||||
case "QuintIn":
|
||||
type = QuintIn;
|
||||
case "QuintOut":
|
||||
type = QuintOut;
|
||||
case "QuintInOut":
|
||||
type = QuintInOut;
|
||||
case "ExpoIn":
|
||||
type = ExpoIn;
|
||||
case "ExpoOut":
|
||||
type = ExpoOut;
|
||||
case "ExpoInOut":
|
||||
type = ExpoInOut;
|
||||
case "CircIn":
|
||||
type = CircIn;
|
||||
case "CircOut":
|
||||
type = CircOut;
|
||||
case "CircInOut":
|
||||
type = CircInOut;
|
||||
case "BackIn":
|
||||
type = BackIn;
|
||||
case "BackOut":
|
||||
type = BackOut;
|
||||
case "BackInOut":
|
||||
type = BackInOut;
|
||||
}
|
||||
|
||||
anim = Tween.to({
|
||||
target: this,
|
||||
props: { fromValue: toValue },
|
||||
duration: duration,
|
||||
ease: type,
|
||||
tick: update,
|
||||
done: done
|
||||
});
|
||||
}
|
||||
else{
|
||||
if(anim != null){
|
||||
Tween.stop(anim);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
|
||||
override function get(from: Int): Dynamic {
|
||||
if(from == 3) return fromValue;
|
||||
return null;
|
||||
}
|
||||
|
||||
function update() {
|
||||
runOutput(1);
|
||||
}
|
||||
|
||||
function done() {
|
||||
runOutput(2);
|
||||
}
|
||||
}
|
116
Sources/armory/logicnode/TweenVectorNode.hx
Normal file
116
Sources/armory/logicnode/TweenVectorNode.hx
Normal file
|
@ -0,0 +1,116 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.math.Vec4;
|
||||
import iron.system.Tween;
|
||||
|
||||
class TweenVectorNode extends LogicNode {
|
||||
|
||||
public var property0:String;
|
||||
|
||||
public var anim: TAnim;
|
||||
public var fromValue:Vec4 = new Vec4();
|
||||
public var toValue:Vec4 = new Vec4();
|
||||
public var duration:Float = 1.0;
|
||||
|
||||
public function new(tree:LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from:Int) {
|
||||
|
||||
if(from == 0){
|
||||
|
||||
if(anim != null){
|
||||
Tween.stop(anim);
|
||||
}
|
||||
|
||||
fromValue.setFrom(inputs[2].get());
|
||||
toValue.setFrom(inputs[3].get());
|
||||
duration = inputs[4].get();
|
||||
var type:Dynamic = Linear;
|
||||
|
||||
switch (property0) {
|
||||
case "Linear":
|
||||
type = Linear;
|
||||
case "SineIn":
|
||||
type = SineIn;
|
||||
case "SineOut":
|
||||
type = SineOut;
|
||||
case "SineInOut":
|
||||
type = SineInOut;
|
||||
case "QuadIn":
|
||||
type = QuadIn;
|
||||
case "QuadOut":
|
||||
type = QuadOut;
|
||||
case "QuadInOut":
|
||||
type = QuadInOut;
|
||||
case "CubicIn":
|
||||
type = CubicIn;
|
||||
case "CubicOut":
|
||||
type = CubicOut;
|
||||
case "CubicInOut":
|
||||
type = CubicInOut;
|
||||
case "QuartIn":
|
||||
type = QuartIn;
|
||||
case "QuartOut":
|
||||
type = QuartOut;
|
||||
case "QuartInOut":
|
||||
type = QuartInOut;
|
||||
case "QuintIn":
|
||||
type = QuintIn;
|
||||
case "QuintOut":
|
||||
type = QuintOut;
|
||||
case "QuintInOut":
|
||||
type = QuintInOut;
|
||||
case "ExpoIn":
|
||||
type = ExpoIn;
|
||||
case "ExpoOut":
|
||||
type = ExpoOut;
|
||||
case "ExpoInOut":
|
||||
type = ExpoInOut;
|
||||
case "CircIn":
|
||||
type = CircIn;
|
||||
case "CircOut":
|
||||
type = CircOut;
|
||||
case "CircInOut":
|
||||
type = CircInOut;
|
||||
case "BackIn":
|
||||
type = BackIn;
|
||||
case "BackOut":
|
||||
type = BackOut;
|
||||
case "BackInOut":
|
||||
type = BackInOut;
|
||||
}
|
||||
|
||||
anim = Tween.to({
|
||||
target: this,
|
||||
props: { fromValue: toValue },
|
||||
duration: duration,
|
||||
ease: type,
|
||||
tick: update,
|
||||
done: done
|
||||
});
|
||||
}
|
||||
else{
|
||||
if(anim != null){
|
||||
Tween.stop(anim);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
|
||||
override function get(from: Int): Dynamic {
|
||||
if(from == 3) return fromValue;
|
||||
return null;
|
||||
}
|
||||
|
||||
function update() {
|
||||
runOutput(1);
|
||||
}
|
||||
|
||||
function done() {
|
||||
runOutput(2);
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@ class VectorMixNode extends LogicNode {
|
|||
|
||||
public var property0: String; // Type
|
||||
public var property1: String; // Ease
|
||||
public var property2: String; // Clamp
|
||||
public var property2: Bool; // Clamp
|
||||
|
||||
var v = new Vec4();
|
||||
|
||||
|
@ -57,7 +57,7 @@ class VectorMixNode extends LogicNode {
|
|||
v.y = v1.y + (v2.y - v1.y) * f;
|
||||
v.z = v1.z + (v2.z - v1.z) * f;
|
||||
|
||||
if (property2 == "true") v.clamp(0, 1);
|
||||
if (property2) v.clamp(0, 1);
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,9 +10,9 @@ class VectorNode extends LogicNode {
|
|||
super(tree);
|
||||
|
||||
if (x != null) {
|
||||
addInput(new FloatNode(tree, x), 0);
|
||||
addInput(new FloatNode(tree, y), 0);
|
||||
addInput(new FloatNode(tree, z), 0);
|
||||
LogicNode.addLink(new FloatNode(tree, x), this, 0, 0);
|
||||
LogicNode.addLink(new FloatNode(tree, y), this, 0, 1);
|
||||
LogicNode.addLink(new FloatNode(tree, z), this, 0, 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,8 +3,6 @@ package armory.logicnode;
|
|||
import iron.object.Object;
|
||||
import iron.math.Vec4;
|
||||
|
||||
using armory.object.TransformExtension;
|
||||
|
||||
class VectorToObjectOrientationNode extends LogicNode {
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
|
@ -18,7 +16,7 @@ class VectorToObjectOrientationNode extends LogicNode {
|
|||
|
||||
if (object == null || vec == null) return null;
|
||||
|
||||
return object.transform.worldVecToOrientation(vec);
|
||||
return vec.applyQuat(object.transform.rot);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import iron.math.Vec4;
|
||||
import iron.math.Vec2;
|
||||
import iron.App;
|
||||
|
||||
class WorldToScreenSpaceNode extends LogicNode {
|
||||
|
||||
|
@ -19,7 +21,10 @@ class WorldToScreenSpaceNode extends LogicNode {
|
|||
v.setFrom(v1);
|
||||
v.applyproj(cam.V);
|
||||
v.applyproj(cam.P);
|
||||
|
||||
var w = App.w();
|
||||
var h = App.h();
|
||||
|
||||
return v;
|
||||
return new Vec2((v.x + 1) * 0.5 * w, (-v.y + 1) * 0.5 * h);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,8 +3,6 @@ package armory.logicnode;
|
|||
import iron.math.Vec4;
|
||||
import iron.object.Object;
|
||||
|
||||
using armory.object.TransformExtension;
|
||||
|
||||
class WorldVectorToLocalSpaceNode extends LogicNode {
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
|
@ -17,7 +15,8 @@ class WorldVectorToLocalSpaceNode extends LogicNode {
|
|||
|
||||
if (object == null || worldVec == null) return null;
|
||||
|
||||
var localVec: Vec4 = new Vec4();
|
||||
var localVec = new Vec4();
|
||||
localVec.sub(object.transform.world.getLoc());
|
||||
|
||||
localVec.x = worldVec.dot(object.transform.right());
|
||||
localVec.y = worldVec.dot(object.transform.look());
|
||||
|
|
|
@ -34,6 +34,14 @@ class Uniforms {
|
|||
return armory.data.ConstData.ltcMagTex;
|
||||
}
|
||||
#end
|
||||
#if arm_morph_target
|
||||
case "_morphDataPos": {
|
||||
return cast(object, iron.object.MeshObject).morphTarget.morphDataPos;
|
||||
}
|
||||
case "_morphDataNor": {
|
||||
return cast(object, iron.object.MeshObject).morphTarget.morphDataNor;
|
||||
}
|
||||
#end
|
||||
}
|
||||
|
||||
var target = iron.RenderPath.active.renderTargets.get(link.endsWith("_depth") ? link.substr(0, link.length - 6) : link);
|
||||
|
|
|
@ -715,7 +715,9 @@ class ShadowMapAtlas {
|
|||
|
||||
public static inline function getMaxAtlasSize(type: String): Int {
|
||||
#if arm_shadowmap_atlas_single_map
|
||||
#if (rp_shadowmap_atlas_max_size == 1024)
|
||||
#if (rp_shadowmap_atlas_max_size == 512)
|
||||
return 512;
|
||||
#elseif (rp_shadowmap_atlas_max_size == 1024)
|
||||
return 1024;
|
||||
#elseif (rp_shadowmap_atlas_max_size == 2048)
|
||||
return 2048;
|
||||
|
@ -742,7 +744,9 @@ class ShadowMapAtlas {
|
|||
#end
|
||||
}
|
||||
case "spot": {
|
||||
#if (rp_shadowmap_atlas_max_size_spot == 1024)
|
||||
#if (rp_shadowmap_atlas_max_size_spot == 512)
|
||||
return 512;
|
||||
#elseif (rp_shadowmap_atlas_max_size_spot == 1024)
|
||||
return 1024;
|
||||
#elseif (rp_shadowmap_atlas_max_size_spot == 2048)
|
||||
return 2048;
|
||||
|
@ -755,7 +759,9 @@ class ShadowMapAtlas {
|
|||
#end
|
||||
}
|
||||
case "sun": {
|
||||
#if (rp_shadowmap_atlas_max_size_sun == 1024)
|
||||
#if (rp_shadowmap_atlas_max_size_sun == 512)
|
||||
return 512;
|
||||
#elseif (rp_shadowmap_atlas_max_size_sun == 1024)
|
||||
return 1024;
|
||||
#elseif (rp_shadowmap_atlas_max_size_sun == 2048)
|
||||
return 2048;
|
||||
|
@ -768,7 +774,9 @@ class ShadowMapAtlas {
|
|||
#end
|
||||
}
|
||||
default: {
|
||||
#if (rp_shadowmap_atlas_max_size == 1024)
|
||||
#if (rp_shadowmap_atlas_max_size == 512)
|
||||
return 512;
|
||||
#elseif (rp_shadowmap_atlas_max_size == 1024)
|
||||
return 1024;
|
||||
#elseif (rp_shadowmap_atlas_max_size == 2048)
|
||||
return 2048;
|
||||
|
|
|
@ -80,11 +80,24 @@ class NishitaData {
|
|||
**/
|
||||
public static var radiusPlanet = 6360000;
|
||||
|
||||
/** Rayleigh scattering coefficient. **/
|
||||
public static var rayleighCoeff = new Vec3(5.5e-6, 13.0e-6, 22.4e-6);
|
||||
/** Rayleigh scattering scale parameter. **/
|
||||
public static var rayleighScale = 8e3;
|
||||
|
||||
/** Mie scattering coefficient. **/
|
||||
public static var mieCoeff = 2e-5;
|
||||
/** Mie scattering scale parameter. **/
|
||||
public static var mieScale = 1.2e3;
|
||||
|
||||
/** Ozone scattering coefficient. **/
|
||||
// The ozone absorption coefficients are taken from Cycles code.
|
||||
// Because Cycles calculates 21 wavelengths, we use the coefficients
|
||||
// which are closest to the RGB wavelengths (645nm, 510nm, 440nm).
|
||||
// Precalculating values by simulating Blender's spec_to_xyz() function
|
||||
// to include all 21 wavelengths gave unrealistic results.
|
||||
public static var ozoneCoeff = new Vec3(1.59051840791988e-6, 0.00000096707041180970, 0.00000007309568762914);
|
||||
|
||||
public function new() {}
|
||||
|
||||
/** Approximates the density of ozone for a given sample height. **/
|
||||
|
@ -185,6 +198,29 @@ class NishitaData {
|
|||
jTime += jStepSize;
|
||||
}
|
||||
|
||||
return jODepth.mult(jStepSize);
|
||||
jODepth.mult(jStepSize);
|
||||
|
||||
// Precalculate a part of the secondary attenuation.
|
||||
// For one variable (e.g. x) in the vector, the formula is as follows:
|
||||
//
|
||||
// attn.x = exp(-(coeffX * (firstOpticalDepth.x + secondOpticalDepth.x)))
|
||||
//
|
||||
// We can split that up via:
|
||||
//
|
||||
// attn.x = exp(-(coeffX * firstOpticalDepth.x + coeffX * secondOpticalDepth.x))
|
||||
// = exp(-(coeffX * firstOpticalDepth.x)) * exp(-(coeffX * secondOpticalDepth.x))
|
||||
//
|
||||
// The first factor of the resulting multiplication is calculated in the
|
||||
// shader, but we can already precalculate the second one. As a side
|
||||
// effect this keeps the range of the LUT values small because we don't
|
||||
// store the optical depth but the attenuation.
|
||||
var jAttenuation = new Vec3();
|
||||
var mie = mieCoeff * jODepth.y;
|
||||
jAttenuation.addf(mie, mie, mie);
|
||||
jAttenuation.add(rayleighCoeff.clone().mult(jODepth.x));
|
||||
jAttenuation.add(ozoneCoeff.clone().mult(jODepth.z));
|
||||
jAttenuation.exp(jAttenuation.mult(-1));
|
||||
|
||||
return jAttenuation;
|
||||
}
|
||||
}
|
||||
|
|
131
Sources/armory/system/Assert.hx
Normal file
131
Sources/armory/system/Assert.hx
Normal file
|
@ -0,0 +1,131 @@
|
|||
package armory.system;
|
||||
|
||||
import haxe.Exception;
|
||||
import haxe.PosInfos;
|
||||
import haxe.exceptions.PosException;
|
||||
import haxe.macro.Context;
|
||||
import haxe.macro.Expr;
|
||||
|
||||
using haxe.macro.ExprTools;
|
||||
|
||||
class Assert {
|
||||
|
||||
/**
|
||||
Checks whether the given expression evaluates to true. If this is not
|
||||
the case, an `ArmAssertionException` is thrown or a warning is printed
|
||||
(depending on the assertion level).
|
||||
|
||||
The assert level describes the severity of the assertion. If the
|
||||
severity is lower than the level stored in the `arm_assert_level` flag,
|
||||
the assertion is omitted from the code so that it doesn't decrease the
|
||||
runtime performance.
|
||||
|
||||
@param level The severity of this assertion.
|
||||
@param condition The conditional expression to test.
|
||||
@param message Optional message to display when the assertion fails.
|
||||
|
||||
@see `AssertLevel`
|
||||
**/
|
||||
macro public static function assert(level: ExprOf<AssertLevel>, condition: ExprOf<Bool>, ?message: ExprOf<String>): Expr {
|
||||
final levelVal: AssertLevel = AssertLevel.fromExpr(level);
|
||||
final assertThreshold = AssertLevel.fromString(Context.definedValue("arm_assert_level"));
|
||||
|
||||
if (levelVal < assertThreshold) {
|
||||
return macro {};
|
||||
}
|
||||
|
||||
switch (levelVal) {
|
||||
case Warning:
|
||||
return macro {
|
||||
if (!$condition) {
|
||||
@:pos(condition.pos)
|
||||
trace(@:privateAccess armory.system.Assert.ArmAssertionException.formatMessage($v{condition.toString()}, ${message}));
|
||||
}
|
||||
}
|
||||
case Error:
|
||||
return macro {
|
||||
if (!$condition) {
|
||||
#if arm_assert_quit kha.System.stop(); #end
|
||||
|
||||
@:pos(condition.pos)
|
||||
@:privateAccess armory.system.Assert.throwAssertionError($v{condition.toString()}, ${message});
|
||||
}
|
||||
}
|
||||
default:
|
||||
throw new Exception('Unsupported assert level: $levelVal');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Helper function to prevent Haxe "bug" that actually throws an error
|
||||
even when using `macro throw` (inlining this method also does not work).
|
||||
**/
|
||||
static function throwAssertionError(exprString: String, message: String, ?pos: PosInfos) {
|
||||
throw new ArmAssertionException(exprString, message, pos);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Exception that is thrown when an assertion fails.
|
||||
|
||||
@see `Assert`
|
||||
**/
|
||||
class ArmAssertionException extends PosException {
|
||||
|
||||
/**
|
||||
@param exprString The string representation of the failed assert condition.
|
||||
@param message Custom error message, use `null` to omit this.
|
||||
**/
|
||||
public inline function new(exprString: String, message: Null<String>, ?previous: Exception, ?pos: Null<PosInfos>) {
|
||||
super('\n${formatMessage(exprString, message)}', previous, pos);
|
||||
}
|
||||
|
||||
static inline function formatMessage(exprString: String, message: Null<String>): String {
|
||||
final optMsg = message != null ? '\n\tMessage: $message' : "";
|
||||
|
||||
return 'Failed assertion:$optMsg\n\tExpression: ($exprString)';
|
||||
}
|
||||
}
|
||||
|
||||
enum abstract AssertLevel(Int) from Int to Int {
|
||||
/**
|
||||
Assertions with this severity don't throw exceptions and only print to
|
||||
the console.
|
||||
**/
|
||||
var Warning: AssertLevel = 0;
|
||||
|
||||
/**
|
||||
Assertions with this severity throw an `ArmAssertionException` if they
|
||||
fail, and optionally quit the game if the `arm_assert_quit` flag is set.
|
||||
**/
|
||||
var Error: AssertLevel = 1;
|
||||
|
||||
/**
|
||||
Completely disable assertions. Don't use this level in `assert()` calls!
|
||||
**/
|
||||
var NoAssertions: AssertLevel = 2;
|
||||
|
||||
public static function fromExpr(e: ExprOf<AssertLevel>): AssertLevel {
|
||||
switch (e.expr) {
|
||||
case EConst(CIdent(v)): return fromString(v);
|
||||
default: throw new Exception('Unsupported expression: $e');
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
Converts a string into an `AssertLevel`, the string must be spelled
|
||||
exactly as the assert level. `null` defaults to
|
||||
`AssertLevel.NoAssertions`.
|
||||
**/
|
||||
public static function fromString(s: Null<String>): AssertLevel {
|
||||
return switch (s) {
|
||||
case "Warning": Warning;
|
||||
case "Error": Error;
|
||||
case "NoAssertions" | null: NoAssertions;
|
||||
default: throw new Exception('Could not convert "$s" to AssertLevel');
|
||||
}
|
||||
}
|
||||
|
||||
@:op(A < B) static function lt(a: AssertLevel, b: AssertLevel): Bool;
|
||||
@:op(A > B) static function gt(a: AssertLevel, b: AssertLevel): Bool;
|
||||
}
|
|
@ -4,347 +4,223 @@ import kha.FastFloat;
|
|||
import iron.system.Input;
|
||||
|
||||
class InputMap {
|
||||
var commands = new Map<String, Null<Array<InputCommand>>>();
|
||||
|
||||
static var inputMaps = new Map<String, InputMap>();
|
||||
|
||||
public var keys(default, null) = new Array<InputMapKey>();
|
||||
public var lastKeyPressed(default, null) = "";
|
||||
|
||||
public function new() {}
|
||||
|
||||
public function addKeyboard(config: String) {
|
||||
var command = new KeyboardCommand();
|
||||
return addCustomCommand(command, config);
|
||||
public static function getInputMap(inputMap: String): Null<InputMap> {
|
||||
if (inputMaps.exists(inputMap)) {
|
||||
return inputMaps[inputMap];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function addGamepad(config: String) {
|
||||
var command = new GamepadCommand();
|
||||
return addCustomCommand(command, config);
|
||||
public static function addInputMap(inputMap: String): InputMap {
|
||||
return inputMaps[inputMap] = new InputMap();
|
||||
}
|
||||
|
||||
public function addCustomCommand(command: InputCommand, config: String) {
|
||||
if (commands[config] == null) commands[config] = new Array<InputCommand>();
|
||||
commands[config].push(command);
|
||||
return command;
|
||||
}
|
||||
}
|
||||
|
||||
class ActionMap extends InputMap {
|
||||
|
||||
public inline function started(config: String) {
|
||||
var started = false;
|
||||
|
||||
for (c in commands[config]) {
|
||||
if (c.started()) {
|
||||
started = true;
|
||||
break;
|
||||
public static function getInputMapKey(inputMap: String, key: String): Null<InputMapKey> {
|
||||
if (inputMaps.exists(inputMap)) {
|
||||
for (k in inputMaps[inputMap].keys) {
|
||||
if (k.key == key) {
|
||||
return k;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return started;
|
||||
return null;
|
||||
}
|
||||
|
||||
public inline function released(config: String) {
|
||||
var released = false;
|
||||
public static function removeInputMapKey(inputMap: String, key: String): Bool {
|
||||
if (inputMaps.exists(inputMap)) {
|
||||
var i = inputMaps[inputMap];
|
||||
|
||||
for (c in commands[config]) {
|
||||
if (c.released()) {
|
||||
released = true;
|
||||
break;
|
||||
for (k in i.keys) {
|
||||
if (k.key == key) {
|
||||
return i.removeKey(k);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return released;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class AxisMap extends InputMap {
|
||||
var scale: FastFloat = 1.0;
|
||||
public function addKeyboard(key: String, scale: FastFloat = 1.0): InputMapKey {
|
||||
return addKey(new KeyboardKey(key, scale));
|
||||
}
|
||||
|
||||
public inline function getAxis(config: String) {
|
||||
var axis = 0.0;
|
||||
public function addMouse(key: String, scale: FastFloat = 1.0, deadzone: FastFloat = 0.0): InputMapKey {
|
||||
return addKey(new MouseKey(key, scale, deadzone));
|
||||
}
|
||||
|
||||
for (c in commands[config]) {
|
||||
var tempAxis = c.getAxis();
|
||||
public function addGamepad(key: String, scale: FastFloat = 1.0, deadzone: FastFloat = 0.0): InputMapKey {
|
||||
return addKey(new GamepadKey(key, scale, deadzone));
|
||||
}
|
||||
|
||||
if (tempAxis != 0.0 && tempAxis != axis) {
|
||||
axis += tempAxis;
|
||||
scale = c.getScale();
|
||||
}
|
||||
public function addKey(key: InputMapKey): InputMapKey {
|
||||
keys.push(key);
|
||||
return key;
|
||||
}
|
||||
|
||||
public function removeKey(key: InputMapKey): Bool {
|
||||
return keys.remove(key);
|
||||
}
|
||||
|
||||
public function value(): FastFloat {
|
||||
var v = 0.0;
|
||||
|
||||
for (k in keys) {
|
||||
v += k.value();
|
||||
}
|
||||
|
||||
return axis;
|
||||
}
|
||||
|
||||
public inline function getScale() {
|
||||
return scale;
|
||||
}
|
||||
}
|
||||
|
||||
class InputCommand {
|
||||
var keys = new Array<String>();
|
||||
var modifiers = new Array<String>();
|
||||
var displacementKeys = new Array<String>();
|
||||
var displacementModifiers = new Array<String>();
|
||||
var deadzone: FastFloat = 0.0;
|
||||
var scale: FastFloat = 1.0;
|
||||
|
||||
public function new() {}
|
||||
|
||||
public function setKeys(keys: Array<String>) {
|
||||
return this.keys = keys;
|
||||
}
|
||||
|
||||
public function setMods(modifiers: Array<String>) {
|
||||
return this.modifiers = modifiers;
|
||||
}
|
||||
|
||||
public function setDisplacementKeys(keys: Array<String>) {
|
||||
return displacementKeys = keys;
|
||||
}
|
||||
|
||||
public function setDisplacementMods(modifiers: Array<String>) {
|
||||
return displacementModifiers = modifiers;
|
||||
}
|
||||
|
||||
public function setDeadzone(deadzone: FastFloat) {
|
||||
return this.deadzone = deadzone;
|
||||
}
|
||||
|
||||
public function setScale(scale: FastFloat) {
|
||||
return this.scale = scale;
|
||||
}
|
||||
|
||||
public function getScale() {
|
||||
return scale;
|
||||
return v;
|
||||
}
|
||||
|
||||
public function started() {
|
||||
for (k in keys) {
|
||||
if (k.started()) {
|
||||
lastKeyPressed = k.key;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function released() {
|
||||
for (k in keys) {
|
||||
if (k.released()) {
|
||||
lastKeyPressed = k.key;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class InputMapKey {
|
||||
|
||||
public var key: String;
|
||||
public var scale: FastFloat;
|
||||
public var deadzone: FastFloat;
|
||||
|
||||
public function new(key: String, scale = 1.0, deadzone = 0.0) {
|
||||
this.key = key.toLowerCase();
|
||||
this.scale = scale;
|
||||
this.deadzone = deadzone;
|
||||
}
|
||||
|
||||
public function started(): Bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getAxis(): FastFloat {
|
||||
public function released(): Bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function value(): FastFloat {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
class KeyboardCommand extends InputCommand {
|
||||
var keyboard = Input.getKeyboard();
|
||||
var mouse = Input.getMouse();
|
||||
public function setIndex(index: Int) {}
|
||||
|
||||
public inline override function started() {
|
||||
for (k in keys) {
|
||||
if (keyboard.started(k)) {
|
||||
for (m in modifiers) {
|
||||
if (!keyboard.down(m)) return false;
|
||||
}
|
||||
function evalDeadzone(value: FastFloat): FastFloat {
|
||||
var v = 0.0;
|
||||
|
||||
for (m in displacementModifiers) {
|
||||
if (!mouse.down(m)) return false;
|
||||
}
|
||||
if (value > deadzone) {
|
||||
v = value - deadzone;
|
||||
|
||||
return true;
|
||||
}
|
||||
} else if (value < -deadzone) {
|
||||
v = value + deadzone;
|
||||
}
|
||||
|
||||
for (k in displacementKeys) {
|
||||
if (mouse.started(k)) {
|
||||
for (m in modifiers) {
|
||||
if (!keyboard.down(m)) return false;
|
||||
}
|
||||
|
||||
for (m in displacementModifiers) {
|
||||
if (!mouse.down(m)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return v * scale;
|
||||
}
|
||||
|
||||
public inline override function released() {
|
||||
for (k in keys) {
|
||||
if (keyboard.released(k)) {
|
||||
for (m in modifiers) {
|
||||
if (!keyboard.down(m)) return false;
|
||||
}
|
||||
function evalPressure(value: FastFloat): FastFloat {
|
||||
var v = value - deadzone;
|
||||
|
||||
for (m in displacementModifiers) {
|
||||
if (!mouse.down(m)) return false;
|
||||
}
|
||||
if (v > 0.0) {
|
||||
v /= (1.0 - deadzone);
|
||||
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
v = 0.0;
|
||||
}
|
||||
|
||||
for (k in displacementKeys) {
|
||||
if (mouse.released(k)) {
|
||||
for (m in modifiers) {
|
||||
if (!keyboard.down(m)) return false;
|
||||
}
|
||||
|
||||
for (m in displacementModifiers) {
|
||||
if (!mouse.down(m)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public inline override function getAxis() {
|
||||
var axis = 0.0;
|
||||
var movementX = mouse.movementX;
|
||||
var movementY = mouse.movementY;
|
||||
var wheelDelta = mouse.wheelDelta;
|
||||
|
||||
for (k in keys) {
|
||||
if (keyboard.down(k)) {
|
||||
axis++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (m in modifiers) {
|
||||
if (keyboard.down(m)) {
|
||||
axis --;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (k in displacementKeys) {
|
||||
switch (k) {
|
||||
case "moved x": if (movementX > deadzone) axis++;
|
||||
case "moved y": if (movementY > deadzone) axis--;
|
||||
case "wheel": if (wheelDelta < -deadzone) axis++;
|
||||
case "movement x": if (movementX > deadzone) return movementX - deadzone;
|
||||
case "movement y": if (movementY > deadzone) return movementY - deadzone;
|
||||
default: {
|
||||
if (mouse.down(k)) {
|
||||
axis ++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (m in displacementModifiers) {
|
||||
switch (m) {
|
||||
case "moved x": if (movementX < -deadzone) axis--;
|
||||
case "moved y": if (movementY < -deadzone) axis++;
|
||||
case "wheel": if (wheelDelta > deadzone) axis--;
|
||||
case "movement x": if (movementX < -deadzone) return movementX + deadzone;
|
||||
case "movement y": if (movementY < -deadzone) return movementY + deadzone;
|
||||
default: {
|
||||
if (mouse.down(m)) {
|
||||
axis --;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return axis > 1 ? 1 : axis < -1 ? -1 : axis;
|
||||
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
class GamepadCommand extends InputCommand {
|
||||
var gamepad = Input.getGamepad(0);
|
||||
class KeyboardKey extends InputMapKey {
|
||||
|
||||
var kb = Input.getKeyboard();
|
||||
|
||||
public inline override function started() {
|
||||
for (k in keys) {
|
||||
if (gamepad.started(k)) {
|
||||
for (m in modifiers) {
|
||||
if (gamepad.down(m) < deadzone) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return kb.started(key);
|
||||
}
|
||||
|
||||
public inline override function released() {
|
||||
for (k in keys) {
|
||||
if (gamepad.released(k)) {
|
||||
for (m in modifiers) {
|
||||
if (gamepad.down(m) < deadzone) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return kb.released(key);
|
||||
}
|
||||
|
||||
public inline override function getAxis() {
|
||||
var axis = 0.0;
|
||||
var rsMovementX = gamepad.rightStick.movementX;
|
||||
var rsMovementY = gamepad.rightStick.movementY;
|
||||
var lsMovementX = gamepad.leftStick.movementX;
|
||||
var lsMovementY = gamepad.leftStick.movementY;
|
||||
var rtPressure = gamepad.down("r2") > 0.0 ? (gamepad.down("r2") - deadzone) / (1 - deadzone) : 0.0;
|
||||
var ltPressure = gamepad.down("l2") > 0.0 ? (gamepad.down("r2") - deadzone) / (1 - deadzone) : 0.0;
|
||||
|
||||
for (k in keys) {
|
||||
switch(k) {
|
||||
case "rtPressure": axis += rtPressure;
|
||||
case "ltPressure": axis += ltPressure;
|
||||
default: {
|
||||
if (gamepad.down(k) > deadzone) {
|
||||
axis++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (m in modifiers) {
|
||||
switch (m) {
|
||||
case "rtPressure": axis -= rtPressure;
|
||||
case "ltPressure": axis -= ltPressure;
|
||||
default: {
|
||||
if (gamepad.down(m) > deadzone) {
|
||||
axis--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (k in displacementKeys) {
|
||||
switch(k) {
|
||||
case "rs moved x": if (rsMovementX > deadzone) axis++;
|
||||
case "rs moved y": if (rsMovementY > deadzone) axis++;
|
||||
case "ls moved x": if (lsMovementX > deadzone) axis++;
|
||||
case "ls moved y": if (lsMovementY > deadzone) axis++;
|
||||
case "rs movement x": if (rsMovementX > deadzone) return rsMovementX - deadzone;
|
||||
case "rs movement y": if (rsMovementY > deadzone) return rsMovementY - deadzone;
|
||||
case "ls movement x": if (lsMovementX > deadzone) return lsMovementX - deadzone;
|
||||
case "ls movement y": if (lsMovementY > deadzone) return lsMovementY - deadzone;
|
||||
}
|
||||
}
|
||||
|
||||
for (m in displacementModifiers) {
|
||||
switch (m) {
|
||||
case "rs moved x": if (rsMovementX < -deadzone) axis--;
|
||||
case "rs moved y": if (rsMovementY < -deadzone) axis--;
|
||||
case "ls moved x": if (lsMovementX < -deadzone) axis--;
|
||||
case "ls moved y": if (lsMovementY < -deadzone) axis--;
|
||||
case "rs movement x": if (rsMovementX < -deadzone) return rsMovementX + deadzone;
|
||||
case "rs movement y": if (rsMovementY < -deadzone) return rsMovementY + deadzone;
|
||||
case "ls movement x": if (lsMovementX < -deadzone) return lsMovementX + deadzone;
|
||||
case "ls movement y": if (lsMovementY < -deadzone) return lsMovementY + deadzone;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return axis > 1 ? 1 : axis < -1 ? -1 : axis;
|
||||
public inline override function value(): FastFloat {
|
||||
return kb.down(key) ? scale : 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MouseKey extends InputMapKey {
|
||||
|
||||
var m = Input.getMouse();
|
||||
|
||||
public inline override function started() {
|
||||
return m.started(key);
|
||||
}
|
||||
|
||||
public inline override function released() {
|
||||
return m.released(key);
|
||||
}
|
||||
|
||||
public override function value(): FastFloat {
|
||||
return switch (key) {
|
||||
case "movement x": evalDeadzone(m.movementX);
|
||||
case "movement y": evalDeadzone(m.movementY);
|
||||
case "wheel": evalDeadzone(m.wheelDelta);
|
||||
default: m.down(key) ? scale : 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class GamepadKey extends InputMapKey {
|
||||
|
||||
var g = Input.getGamepad();
|
||||
|
||||
public inline override function started() {
|
||||
return g.started(key);
|
||||
}
|
||||
|
||||
public inline override function released() {
|
||||
return g.released(key);
|
||||
}
|
||||
|
||||
public override function value(): FastFloat {
|
||||
return switch(key) {
|
||||
case "ls movement x": evalDeadzone(g.leftStick.movementX);
|
||||
case "ls movement y": evalDeadzone(g.leftStick.movementY);
|
||||
case "rs movement x": evalDeadzone(g.rightStick.movementX);
|
||||
case "rs movement y": evalDeadzone(g.rightStick.movementY);
|
||||
case "lt pressure": evalDeadzone(evalPressure(g.down("l2")));
|
||||
case "rt pressure": evalDeadzone(evalPressure(g.down("r2")));
|
||||
default: evalDeadzone(g.down(key));
|
||||
}
|
||||
}
|
||||
|
||||
public override function setIndex(index: Int) {
|
||||
g = Input.getGamepad(index);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -94,6 +94,10 @@ class Logic {
|
|||
var v = createClassInstance(node.type, [tree]);
|
||||
nodeMap.set(name, v);
|
||||
|
||||
#if arm_patch
|
||||
tree.nodes.set(name, v);
|
||||
#end
|
||||
|
||||
// Properties
|
||||
for (i in 0...5) {
|
||||
for (b in node.buttons) {
|
||||
|
@ -103,9 +107,13 @@ class Logic {
|
|||
}
|
||||
}
|
||||
|
||||
@:privateAccess v.preallocInputs(node.inputs.length);
|
||||
@:privateAccess v.preallocOutputs(node.outputs.length);
|
||||
|
||||
// Create inputs
|
||||
var inp_node: armory.logicnode.LogicNode = null;
|
||||
var inp_from = 0;
|
||||
var from_type: String;
|
||||
for (i in 0...node.inputs.length) {
|
||||
var inp = node.inputs[i];
|
||||
// Is linked - find node
|
||||
|
@ -117,6 +125,7 @@ class Logic {
|
|||
for (i in 0...n.outputs.length) {
|
||||
if (n.outputs[i] == socket) {
|
||||
inp_from = i;
|
||||
from_type = socket.type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -124,27 +133,33 @@ class Logic {
|
|||
else { // Not linked - create node with default values
|
||||
inp_node = build_default_node(inp);
|
||||
inp_from = 0;
|
||||
from_type = inp.type;
|
||||
}
|
||||
// Add input
|
||||
v.addInput(inp_node, inp_from);
|
||||
var link = LogicNode.addLink(inp_node, v, inp_from, i);
|
||||
#if arm_patch
|
||||
link.fromType = from_type;
|
||||
link.toType = inp.type;
|
||||
link.toValue = getSocketDefaultValue(inp);
|
||||
#end
|
||||
}
|
||||
|
||||
// Create outputs
|
||||
for (out in node.outputs) {
|
||||
var outNodes: Array<armory.logicnode.LogicNode> = [];
|
||||
for (i in 0...node.outputs.length) {
|
||||
var out = node.outputs[i];
|
||||
var ls = getOutputLinks(out);
|
||||
if (ls != null && ls.length > 0) {
|
||||
for (l in ls) {
|
||||
var n = getNode(l.to_id);
|
||||
var out_name = build_node(n);
|
||||
outNodes.push(nodeMap.get(out_name));
|
||||
}
|
||||
|
||||
// Linked outputs are already handled after iterating over inputs
|
||||
// above, so only unconnected outputs are handled here
|
||||
if (ls == null || ls.length == 0) {
|
||||
var link = LogicNode.addLink(v, build_default_node(out), i, 0);
|
||||
|
||||
#if arm_patch
|
||||
link.fromType = out.type;
|
||||
link.toType = out.type;
|
||||
link.toValue = getSocketDefaultValue(out);
|
||||
#end
|
||||
}
|
||||
else { // Not linked - create node with default values
|
||||
outNodes.push(build_default_node(out));
|
||||
}
|
||||
// Add outputs
|
||||
v.addOutputs(outNodes);
|
||||
}
|
||||
|
||||
return name;
|
||||
|
@ -212,6 +227,22 @@ class Logic {
|
|||
return v;
|
||||
}
|
||||
|
||||
static function getSocketDefaultValue(socket: TNodeSocket): Any {
|
||||
|
||||
var v: armory.logicnode.LogicNode = null;
|
||||
|
||||
return switch (socket.type) {
|
||||
case "OBJECT" | "VALUE" | "INT" | "BOOLEAN" | "STRING":
|
||||
socket.default_value;
|
||||
case "VECTOR" | "RGB":
|
||||
socket.default_value == null ? [0, 0, 0] : [socket.default_value[0], socket.default_value[1], socket.default_value[2]];
|
||||
case "RGBA":
|
||||
socket.default_value == null ? [0, 0, 0, 1] : [socket.default_value[0], socket.default_value[1], socket.default_value[2], socket.default_value[3]];
|
||||
default:
|
||||
null;
|
||||
}
|
||||
}
|
||||
|
||||
static function createClassInstance(className: String, args: Array<Dynamic>): Dynamic {
|
||||
var cname = Type.resolveClass(packageName + "." + className);
|
||||
if (cname == null) return null;
|
||||
|
|
|
@ -6,6 +6,9 @@ import iron.math.Vec4;
|
|||
|
||||
class ArcBall extends Trait {
|
||||
|
||||
@prop
|
||||
public var axis = new Vec4(0, 0, 1);
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
|
||||
|
@ -17,10 +20,8 @@ class ArcBall extends Trait {
|
|||
|
||||
var mouse = Input.getMouse();
|
||||
if (mouse.down()) {
|
||||
object.transform.rotate(new Vec4(0, 0, 1), -mouse.movementX / 100);
|
||||
object.transform.buildMatrix();
|
||||
object.transform.rotate(axis, -mouse.movementX / 100);
|
||||
object.transform.rotate(object.transform.world.right(), -mouse.movementY / 100);
|
||||
object.transform.buildMatrix();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ class FollowCamera extends iron.Trait {
|
|||
trace("FollowCamera error, unable to set target object");
|
||||
}
|
||||
|
||||
if (Std.is(object, iron.object.CameraObject)) {
|
||||
if (Std.isOfType(object, iron.object.CameraObject)) {
|
||||
disabled = true;
|
||||
trace("FollowCamera error, this trait should not be placed directly on a camera objet. It should be placed on another object such as an Empty. The camera should be placed as a child to the Empty object with offset, creating a camera boom.");
|
||||
}
|
||||
|
|
|
@ -8,9 +8,9 @@ import iron.system.Tween;
|
|||
class NavAgent extends Trait {
|
||||
|
||||
@prop
|
||||
var speed: Float = 5;
|
||||
public var speed: Float = 5;
|
||||
@prop
|
||||
var turnDuration: Float = 0.4;
|
||||
public var turnDuration: Float = 0.4;
|
||||
|
||||
var path: Array<Vec4> = null;
|
||||
var index = 0;
|
||||
|
|
|
@ -2,6 +2,7 @@ package armory.trait;
|
|||
|
||||
import iron.Trait;
|
||||
import iron.system.Input;
|
||||
import iron.math.Vec3;
|
||||
import iron.math.Vec4;
|
||||
import iron.math.Mat4;
|
||||
import iron.math.RayCaster;
|
||||
|
@ -14,6 +15,11 @@ class PhysicsDrag extends Trait {
|
|||
public function new() { super(); }
|
||||
#else
|
||||
|
||||
@prop public var linearLowerLimit = new Vec3(0,0,0);
|
||||
@prop public var linearUpperLimit = new Vec3(0,0,0);
|
||||
@prop public var angularLowerLimit = new Vec3(-10,-10,-10);
|
||||
@prop public var angularUpperLimit = new Vec3(10,10,10);
|
||||
|
||||
var pickConstraint: bullet.Bt.Generic6DofConstraint = null;
|
||||
var pickDist: Float;
|
||||
var pickedBody: RigidBody = null;
|
||||
|
@ -56,10 +62,10 @@ class PhysicsDrag extends Trait {
|
|||
tr.setOrigin(localPivot);
|
||||
|
||||
pickConstraint = new bullet.Bt.Generic6DofConstraint(b.body, tr, false);
|
||||
pickConstraint.setLinearLowerLimit(new bullet.Bt.Vector3(0, 0, 0));
|
||||
pickConstraint.setLinearUpperLimit(new bullet.Bt.Vector3(0, 0, 0));
|
||||
pickConstraint.setAngularLowerLimit(new bullet.Bt.Vector3(-10, -10, -10));
|
||||
pickConstraint.setAngularUpperLimit(new bullet.Bt.Vector3(10, 10, 10));
|
||||
pickConstraint.setLinearLowerLimit(new bullet.Bt.Vector3(linearLowerLimit.x, linearLowerLimit.y, linearLowerLimit.z));
|
||||
pickConstraint.setLinearUpperLimit(new bullet.Bt.Vector3(linearUpperLimit.x, linearUpperLimit.y, linearUpperLimit.z));
|
||||
pickConstraint.setAngularLowerLimit(new bullet.Bt.Vector3(angularLowerLimit.x, angularLowerLimit.y, angularLowerLimit.z));
|
||||
pickConstraint.setAngularUpperLimit(new bullet.Bt.Vector3(angularUpperLimit.x, angularUpperLimit.y, angularUpperLimit.z));
|
||||
physics.world.addConstraint(pickConstraint, false);
|
||||
|
||||
/*pickConstraint.setParam(4, 0.8, 0);
|
||||
|
|
|
@ -11,6 +11,7 @@ class Bridge {
|
|||
public static var Input = iron.system.Input;
|
||||
public static var Object = iron.object.Object;
|
||||
public static var Data = iron.data.Data;
|
||||
public static var Vec4 = iron.math.Vec4;
|
||||
public static function log(s: String) { trace(s); };
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ class CanvasScript extends Trait {
|
|||
iron.data.Data.getBlob(canvasName + ".json", function(blob: kha.Blob) {
|
||||
|
||||
iron.data.Data.getBlob("_themes.json", function(tBlob: kha.Blob) {
|
||||
if (tBlob.get_length() != 0) {
|
||||
if (@:privateAccess tBlob.get_length() != 0) {
|
||||
Canvas.themes = haxe.Json.parse(tBlob.toString());
|
||||
}
|
||||
else {
|
||||
|
@ -40,20 +40,27 @@ class CanvasScript extends Trait {
|
|||
Canvas.themes.push(armory.ui.Themes.light);
|
||||
}
|
||||
|
||||
iron.data.Data.getFont(font, function(f: kha.Font) {
|
||||
iron.data.Data.getFont(font, function(defaultFont: kha.Font) {
|
||||
var c: TCanvas = haxe.Json.parse(blob.toString());
|
||||
if (c.theme == null) c.theme = Canvas.themes[0].NAME;
|
||||
cui = new Zui({font: f, theme: Canvas.getTheme(c.theme)});
|
||||
cui = new Zui({font: defaultFont, theme: Canvas.getTheme(c.theme)});
|
||||
|
||||
if (c.assets == null || c.assets.length == 0) canvas = c;
|
||||
else { // Load canvas assets
|
||||
var loaded = 0;
|
||||
for (asset in c.assets) {
|
||||
var file = asset.name;
|
||||
iron.data.Data.getImage(file, function(image: kha.Image) {
|
||||
Canvas.assetMap.set(asset.id, image);
|
||||
if (++loaded >= c.assets.length) canvas = c;
|
||||
});
|
||||
if (Canvas.isFontAsset(file)) {
|
||||
iron.data.Data.getFont(file, function(f: kha.Font) {
|
||||
Canvas.assetMap.set(asset.id, f);
|
||||
if (++loaded >= c.assets.length) canvas = c;
|
||||
});
|
||||
} else {
|
||||
iron.data.Data.getImage(file, function(image: kha.Image) {
|
||||
Canvas.assetMap.set(asset.id, image);
|
||||
if (++loaded >= c.assets.length) canvas = c;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -107,13 +114,19 @@ class CanvasScript extends Trait {
|
|||
}
|
||||
|
||||
/**
|
||||
* Set UI scale factor.
|
||||
* @param factor Scale factor.
|
||||
*/
|
||||
public function setUiScale(factor:Float) {
|
||||
Set the UI scale factor.
|
||||
**/
|
||||
public inline function setUiScale(factor: Float) {
|
||||
cui.setScale(factor);
|
||||
}
|
||||
|
||||
/**
|
||||
Get the UI scale factor.
|
||||
**/
|
||||
public inline function getUiScale(): Float {
|
||||
return cui.ops.scaleFactor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set visibility of canvas
|
||||
* @param visible Whether canvas should be visible or not
|
||||
|
@ -137,6 +150,11 @@ class CanvasScript extends Trait {
|
|||
*/
|
||||
public function setCanvasFontSize(fontSize: Int) {
|
||||
cui.t.FONT_SIZE = fontSize;
|
||||
cui.setScale(cui.ops.scaleFactor);
|
||||
}
|
||||
|
||||
public function getCanvasFontSize(): Int {
|
||||
return cui.t.FONT_SIZE;
|
||||
}
|
||||
|
||||
// Contains data
|
||||
|
|
|
@ -25,6 +25,8 @@ class DebugConsole extends Trait {
|
|||
#else
|
||||
|
||||
public static var visible = true;
|
||||
public static var traceWithPosition = true;
|
||||
|
||||
static var ui: Zui;
|
||||
var scaleFactor = 1.0;
|
||||
|
||||
|
@ -75,16 +77,18 @@ class DebugConsole extends Trait {
|
|||
#end
|
||||
|
||||
public function new(scaleFactor = 1.0, scaleDebugConsole = 1.0, positionDebugConsole = 2, visibleDebugConsole = 1,
|
||||
keyCodeVisible = kha.input.KeyCode.Tilde, keyCodeScaleIn = kha.input.KeyCode.OpenBracket, keyCodeScaleOut = kha.input.KeyCode.CloseBracket) {
|
||||
traceWithPosition = 1, keyCodeVisible = kha.input.KeyCode.Tilde, keyCodeScaleIn = kha.input.KeyCode.OpenBracket,
|
||||
keyCodeScaleOut = kha.input.KeyCode.CloseBracket) {
|
||||
super();
|
||||
this.scaleFactor = scaleFactor;
|
||||
DebugConsole.traceWithPosition = traceWithPosition == 1;
|
||||
|
||||
iron.data.Data.getFont("font_default.ttf", function(font: kha.Font) {
|
||||
ui = new Zui({scaleFactor: scaleFactor, font: font});
|
||||
// Set settings
|
||||
setScale(scaleDebugConsole);
|
||||
setVisible(visibleDebugConsole == 1);
|
||||
switch(positionDebugConsole) {
|
||||
switch (positionDebugConsole) {
|
||||
case 0: setPosition(PositionStateEnum.LEFT);
|
||||
case 1: setPosition(PositionStateEnum.CENTER);
|
||||
case 2: setPosition(PositionStateEnum.RIGHT);
|
||||
|
@ -104,11 +108,11 @@ class DebugConsole extends Trait {
|
|||
// DebugFloat
|
||||
if (key == kha.input.KeyCode.OpenBracket) {
|
||||
debugFloat -= 0.1;
|
||||
trace("debugFloat = "+ debugFloat);
|
||||
trace("debugFloat = " + debugFloat);
|
||||
}
|
||||
else if (key == kha.input.KeyCode.CloseBracket){
|
||||
debugFloat += 0.1;
|
||||
trace("debugFloat = "+ debugFloat);
|
||||
trace("debugFloat = " + debugFloat);
|
||||
}
|
||||
// Shortcut - Visible
|
||||
if (key == shortcut_visible) visible = !visible;
|
||||
|
@ -170,7 +174,7 @@ class DebugConsole extends Trait {
|
|||
static var haxeTrace: Dynamic->haxe.PosInfos->Void = null;
|
||||
static var lastTraces: Array<String> = [""];
|
||||
static function consoleTrace(v: Dynamic, ?inf: haxe.PosInfos) {
|
||||
lastTraces.unshift(haxe.Log.formatOutput(v,inf));
|
||||
lastTraces.unshift(haxe.Log.formatOutput(v, traceWithPosition ? inf : null));
|
||||
if (lastTraces.length > 10) lastTraces.pop();
|
||||
haxeTrace(v, inf);
|
||||
}
|
||||
|
@ -186,10 +190,10 @@ class DebugConsole extends Trait {
|
|||
var wh = iron.App.h();
|
||||
// Check position
|
||||
switch (position_console) {
|
||||
case PositionStateEnum.LEFT: wx = 0;
|
||||
case PositionStateEnum.CENTER: wx = Math.round(iron.App.w() / 2 - ww / 2);
|
||||
case PositionStateEnum.RIGHT: wx = iron.App.w() - ww;
|
||||
}
|
||||
case PositionStateEnum.LEFT: wx = 0;
|
||||
case PositionStateEnum.CENTER: wx = Math.round(iron.App.w() / 2 - ww / 2);
|
||||
case PositionStateEnum.RIGHT: wx = iron.App.w() - ww;
|
||||
}
|
||||
|
||||
// var bindG = ui.windowDirty(hwin, wx, wy, ww, wh) || hwin.redraws > 0;
|
||||
var bindG = true;
|
||||
|
@ -276,7 +280,7 @@ class DebugConsole extends Trait {
|
|||
ui.indent();
|
||||
|
||||
if (selectedObject != null) {
|
||||
if (Std.is(selectedObject, iron.object.CameraObject)) {
|
||||
if (Std.isOfType(selectedObject, iron.object.CameraObject)) {
|
||||
ui.row([1/2, 1/2]);
|
||||
}
|
||||
|
||||
|
@ -284,7 +288,7 @@ class DebugConsole extends Trait {
|
|||
h.selected = selectedObject.visible;
|
||||
selectedObject.visible = ui.check(h, "Visible");
|
||||
|
||||
if (Std.is(selectedObject, iron.object.CameraObject)) {
|
||||
if (Std.isOfType(selectedObject, iron.object.CameraObject)) {
|
||||
if (ui.button("Set Active Camera")) {
|
||||
iron.Scene.active.camera = cast(selectedObject, iron.object.CameraObject);
|
||||
}
|
||||
|
@ -428,7 +432,7 @@ class DebugConsole extends Trait {
|
|||
ui.text("This scene has no world data to edit.");
|
||||
}
|
||||
}
|
||||
else if (Std.is(selectedObject, iron.object.LightObject)) {
|
||||
else if (Std.isOfType(selectedObject, iron.object.LightObject)) {
|
||||
selectedType = "(Light)";
|
||||
var light = cast(selectedObject, iron.object.LightObject);
|
||||
var lightHandle = Id.handle();
|
||||
|
@ -439,7 +443,7 @@ class DebugConsole extends Trait {
|
|||
ui.text("shadow map size: " + light.data.raw.shadowmap_size);
|
||||
#end
|
||||
}
|
||||
else if (Std.is(selectedObject, iron.object.CameraObject)) {
|
||||
else if (Std.isOfType(selectedObject, iron.object.CameraObject)) {
|
||||
selectedType = "(Camera)";
|
||||
var cam = cast(selectedObject, iron.object.CameraObject);
|
||||
var fovHandle = Id.handle();
|
||||
|
@ -594,7 +598,7 @@ class DebugConsole extends Trait {
|
|||
}
|
||||
|
||||
function drawTiles(tile: ShadowMapTile, atlas: ShadowMapAtlas, atlasVisualSize: Float) {
|
||||
var color = kha.Color.fromFloats(0.1, 0.1, 0.1);
|
||||
var color: Null<kha.Color> = kha.Color.fromFloats(0.1, 0.1, 0.1);
|
||||
var borderColor = color;
|
||||
var tileScale = (tile.size / atlas.sizew) * atlasVisualSize; //* 0.95;
|
||||
var x = (tile.coordsX / atlas.sizew) * atlasVisualSize;
|
||||
|
@ -775,11 +779,23 @@ class DebugConsole extends Trait {
|
|||
#end
|
||||
if (ui.panel(Id.handle({selected: true}), "Log")) {
|
||||
ui.indent();
|
||||
|
||||
final h = Id.handle();
|
||||
h.selected = DebugConsole.traceWithPosition;
|
||||
DebugConsole.traceWithPosition = ui.check(h, "Print With Position");
|
||||
if (ui.isHovered) ui.tooltip("Whether to prepend the position of print/trace statements to the printed text");
|
||||
|
||||
if (ui.button("Clear")) {
|
||||
lastTraces[0] = "";
|
||||
lastTraces.splice(1, lastTraces.length - 1);
|
||||
}
|
||||
if (ui.isHovered) ui.tooltip("Clear the log output");
|
||||
|
||||
final eh = ui.t.ELEMENT_H;
|
||||
ui.t.ELEMENT_H = ui.fontSize;
|
||||
for (t in lastTraces) ui.text(t);
|
||||
ui.t.ELEMENT_H = eh;
|
||||
|
||||
ui.unindent();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,17 @@
|
|||
package armory.trait.internal;
|
||||
|
||||
import armory.logicnode.LogicNode;
|
||||
import armory.logicnode.LogicTree;
|
||||
|
||||
|
||||
#if arm_patch @:expose("LivePatch") #end
|
||||
@:access(armory.logicnode.LogicNode)
|
||||
@:access(armory.logicnode.LogicNodeLink)
|
||||
class LivePatch extends iron.Trait {
|
||||
|
||||
#if arm_patch
|
||||
#if !arm_patch
|
||||
public function new() { super(); }
|
||||
#else
|
||||
|
||||
static var patchId = 0;
|
||||
|
||||
|
@ -23,9 +32,164 @@ class LivePatch extends iron.Trait {
|
|||
});
|
||||
}
|
||||
|
||||
#else
|
||||
public static function patchCreateNodeLink(treeName: String, fromNodeName: String, toNodeName: String, fromIndex: Int, toIndex: Int) {
|
||||
if (!LogicTree.nodeTrees.exists(treeName)) return;
|
||||
var trees = LogicTree.nodeTrees[treeName];
|
||||
|
||||
public function new() { super(); }
|
||||
for (tree in trees) {
|
||||
var fromNode = tree.nodes[fromNodeName];
|
||||
var toNode = tree.nodes[toNodeName];
|
||||
if (fromNode == null || toNode == null) return;
|
||||
|
||||
LogicNode.addLink(fromNode, toNode, fromIndex, toIndex);
|
||||
}
|
||||
}
|
||||
|
||||
public static function patchSetNodeLinks(treeName: String, nodeName: String, inputDatas: Array<Dynamic>, outputDatas: Array<Array<Dynamic>>) {
|
||||
if (!LogicTree.nodeTrees.exists(treeName)) return;
|
||||
var trees = LogicTree.nodeTrees[treeName];
|
||||
|
||||
for (tree in trees) {
|
||||
var node = tree.nodes[nodeName];
|
||||
if (node == null) return;
|
||||
|
||||
node.clearInputs();
|
||||
node.clearOutputs();
|
||||
|
||||
for (inputData in inputDatas) {
|
||||
var fromNode: LogicNode;
|
||||
var fromIndex: Int;
|
||||
|
||||
if (inputData.isLinked) {
|
||||
fromNode = tree.nodes[inputData.fromNode];
|
||||
if (fromNode == null) continue;
|
||||
fromIndex = inputData.fromIndex;
|
||||
}
|
||||
else {
|
||||
fromNode = LogicNode.createSocketDefaultNode(node.tree, inputData.socketType, inputData.socketValue);
|
||||
fromIndex = 0;
|
||||
}
|
||||
|
||||
LogicNode.addLink(fromNode, node, fromIndex, inputData.toIndex);
|
||||
}
|
||||
|
||||
for (outputData in outputDatas) {
|
||||
for (linkData in outputData) {
|
||||
var toNode: LogicNode;
|
||||
var toIndex: Int;
|
||||
|
||||
if (linkData.isLinked) {
|
||||
toNode = tree.nodes[linkData.toNode];
|
||||
if (toNode == null) continue;
|
||||
toIndex = linkData.toIndex;
|
||||
}
|
||||
else {
|
||||
toNode = LogicNode.createSocketDefaultNode(node.tree, linkData.socketType, linkData.socketValue);
|
||||
toIndex = 0;
|
||||
}
|
||||
|
||||
LogicNode.addLink(node, toNode, linkData.fromIndex, toIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function patchUpdateNodeProp(treeName: String, nodeName: String, propName: String, value: Dynamic) {
|
||||
if (!LogicTree.nodeTrees.exists(treeName)) return;
|
||||
var trees = LogicTree.nodeTrees[treeName];
|
||||
|
||||
for (tree in trees) {
|
||||
var node = tree.nodes[nodeName];
|
||||
if (node == null) return;
|
||||
|
||||
Reflect.setField(node, propName, value);
|
||||
}
|
||||
}
|
||||
|
||||
public static function patchUpdateNodeInputVal(treeName: String, nodeName: String, socketIndex: Int, value: Dynamic) {
|
||||
if (!LogicTree.nodeTrees.exists(treeName)) return;
|
||||
var trees = LogicTree.nodeTrees[treeName];
|
||||
|
||||
for (tree in trees) {
|
||||
var node = tree.nodes[nodeName];
|
||||
if (node == null) return;
|
||||
|
||||
node.inputs[socketIndex].set(value);
|
||||
}
|
||||
}
|
||||
|
||||
public static function patchNodeDelete(treeName: String, nodeName: String) {
|
||||
if (!LogicTree.nodeTrees.exists(treeName)) return;
|
||||
var trees = LogicTree.nodeTrees[treeName];
|
||||
|
||||
for (tree in trees) {
|
||||
var node = tree.nodes[nodeName];
|
||||
if (node == null) return;
|
||||
|
||||
node.clearOutputs();
|
||||
node.clearInputs();
|
||||
tree.nodes.remove(nodeName);
|
||||
}
|
||||
}
|
||||
|
||||
public static function patchNodeCreate(treeName: String, nodeName: String, nodeType: String, propDatas: Array<Array<Dynamic>>, inputDatas: Array<Array<Dynamic>>, outputDatas: Array<Array<Dynamic>>) {
|
||||
if (!LogicTree.nodeTrees.exists(treeName)) return;
|
||||
var trees = LogicTree.nodeTrees[treeName];
|
||||
|
||||
for (tree in trees) {
|
||||
// No further constructor parameters required here, all variable nodes
|
||||
// use optional further parameters and all values are set later in this
|
||||
// function.
|
||||
var newNode: LogicNode = Type.createInstance(Type.resolveClass(nodeType), [tree]);
|
||||
newNode.name = nodeName;
|
||||
tree.nodes[nodeName] = newNode;
|
||||
|
||||
for (propData in propDatas) {
|
||||
Reflect.setField(newNode, propData[0], propData[1]);
|
||||
}
|
||||
|
||||
var i = 0;
|
||||
for (inputData in inputDatas) {
|
||||
LogicNode.addLink(LogicNode.createSocketDefaultNode(newNode.tree, inputData[0], inputData[1]), newNode, 0, i++);
|
||||
}
|
||||
|
||||
i = 0;
|
||||
for (outputData in outputDatas) {
|
||||
LogicNode.addLink(newNode, LogicNode.createSocketDefaultNode(newNode.tree, outputData[0], outputData[1]), i++, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function patchNodeCopy(treeName: String, nodeName: String, newNodeName: String, copyProps: Array<String>, inputDatas: Array<Array<Dynamic>>, outputDatas: Array<Array<Dynamic>>) {
|
||||
if (!LogicTree.nodeTrees.exists(treeName)) return;
|
||||
var trees = LogicTree.nodeTrees[treeName];
|
||||
|
||||
for (tree in trees) {
|
||||
var node = tree.nodes[nodeName];
|
||||
if (node == null) return;
|
||||
|
||||
// No further constructor parameters required here, all variable nodes
|
||||
// use optional further parameters and all values are set later in this
|
||||
// function.
|
||||
var newNode: LogicNode = Type.createInstance(Type.getClass(node), [tree]);
|
||||
newNode.name = newNodeName;
|
||||
tree.nodes[newNodeName] = newNode;
|
||||
|
||||
for (propName in copyProps) {
|
||||
Reflect.setField(newNode, propName, Reflect.field(node, propName));
|
||||
}
|
||||
|
||||
var i = 0;
|
||||
for (inputData in inputDatas) {
|
||||
LogicNode.addLink(LogicNode.createSocketDefaultNode(newNode.tree, inputData[0], inputData[1]), newNode, 0, i++);
|
||||
}
|
||||
|
||||
i = 0;
|
||||
for (outputData in outputDatas) {
|
||||
LogicNode.addLink(newNode, LogicNode.createSocketDefaultNode(newNode.tree, outputData[0], outputData[1]), i++, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#end
|
||||
}
|
||||
|
|
|
@ -2,14 +2,29 @@ package armory.trait.internal;
|
|||
|
||||
import kha.Image;
|
||||
import kha.Video;
|
||||
|
||||
import iron.Trait;
|
||||
import iron.object.MeshObject;
|
||||
|
||||
/**
|
||||
Replaces the diffuse texture of the first material of the trait's object
|
||||
with a video texture.
|
||||
|
||||
@see https://github.com/armory3d/armory_examples/tree/master/material_movie
|
||||
**/
|
||||
class MovieTexture extends Trait {
|
||||
|
||||
/**
|
||||
Caches all render targets used by this trait for re-use when having
|
||||
multiple videos of the same size. The lookup only takes place on trait
|
||||
initialization.
|
||||
|
||||
Map layout: `[width => [height => image]]`
|
||||
**/
|
||||
static var imageCache: Map<Int, Map<Int, Image>> = new Map();
|
||||
|
||||
var video: Video;
|
||||
public static var image: Image;
|
||||
public static var created = false;
|
||||
var image: Image;
|
||||
|
||||
var videoName: String;
|
||||
|
||||
|
@ -33,10 +48,7 @@ class MovieTexture extends Trait {
|
|||
|
||||
this.videoName = videoName;
|
||||
|
||||
if (!created) {
|
||||
created = true;
|
||||
notifyOnInit(init);
|
||||
}
|
||||
notifyOnInit(init);
|
||||
}
|
||||
|
||||
function init() {
|
||||
|
@ -44,9 +56,21 @@ class MovieTexture extends Trait {
|
|||
video = vid;
|
||||
video.play(true);
|
||||
|
||||
image = Image.createRenderTarget(getPower2(video.width()), getPower2(video.height()));
|
||||
var w = getPower2(video.width());
|
||||
var h = getPower2(video.height());
|
||||
|
||||
var o = cast(object, iron.object.MeshObject);
|
||||
// Lazily fill the outer map
|
||||
var hMap: Map<Int, Image> = imageCache[w];
|
||||
if (hMap == null) {
|
||||
imageCache[w] = new Map<Int, Image>();
|
||||
}
|
||||
|
||||
image = imageCache[w][h];
|
||||
if (image == null) {
|
||||
imageCache[w][h] = image = Image.createRenderTarget(w, h);
|
||||
}
|
||||
|
||||
var o = cast(object, MeshObject);
|
||||
o.materials[0].contexts[0].textures[0] = image; // Override diffuse texture
|
||||
notifyOnRender2D(render);
|
||||
});
|
||||
|
|
328
Sources/armory/trait/internal/UniformsManager.hx
Normal file
328
Sources/armory/trait/internal/UniformsManager.hx
Normal file
|
@ -0,0 +1,328 @@
|
|||
package armory.trait.internal;
|
||||
|
||||
import iron.object.DecalObject;
|
||||
import iron.object.MeshObject;
|
||||
import iron.Trait;
|
||||
import kha.Image;
|
||||
import iron.math.Vec4;
|
||||
import iron.data.MaterialData;
|
||||
import iron.Scene;
|
||||
import iron.object.Object;
|
||||
import iron.object.Uniforms;
|
||||
|
||||
|
||||
class UniformsManager extends Trait{
|
||||
|
||||
static var floatsRegistered = false;
|
||||
static var floatsMap = new Map<Object, Map<MaterialData, Map<String, Null<kha.FastFloat>>>>();
|
||||
|
||||
static var vectorsRegistered = false;
|
||||
static var vectorsMap = new Map<Object, Map<MaterialData, Map<String, Vec4>>>();
|
||||
|
||||
static var texturesRegistered = false;
|
||||
static var texturesMap = new Map<Object, Map<MaterialData, Map<String, kha.Image>>>();
|
||||
|
||||
static var sceneRemoveInitalized = false;
|
||||
|
||||
public var uniformExists = false;
|
||||
|
||||
public function new(){
|
||||
super();
|
||||
|
||||
notifyOnInit(init);
|
||||
|
||||
notifyOnRemove(removeObject);
|
||||
|
||||
if(! sceneRemoveInitalized){
|
||||
|
||||
Scene.active.notifyOnRemove(removeScene);
|
||||
}
|
||||
}
|
||||
|
||||
function init() {
|
||||
if(Std.isOfType(object, MeshObject)){
|
||||
var materials = cast(object, MeshObject).materials;
|
||||
|
||||
for (material in materials){
|
||||
|
||||
var exists = registerShaderUniforms(material);
|
||||
if(exists) {
|
||||
uniformExists = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#if rp_decals
|
||||
if(Std.isOfType(object, DecalObject)){
|
||||
var material = cast(object, DecalObject).material;
|
||||
|
||||
var exists = registerShaderUniforms(material);
|
||||
if(exists) {
|
||||
uniformExists = true;
|
||||
}
|
||||
|
||||
}
|
||||
#end
|
||||
}
|
||||
|
||||
static function removeScene() {
|
||||
|
||||
removeObjectFromAllMaps(Scene.active.root);
|
||||
}
|
||||
|
||||
function removeObject() {
|
||||
|
||||
removeObjectFromAllMaps(object);
|
||||
}
|
||||
|
||||
// Helper method to register float, vec3 and texture getter functions
|
||||
static function register(type: UniformType){
|
||||
switch (type){
|
||||
case Float:
|
||||
if(! floatsRegistered){
|
||||
floatsRegistered = true;
|
||||
Uniforms.externalFloatLinks.push(floatLink);
|
||||
}
|
||||
case Vector:
|
||||
if(! vectorsRegistered){
|
||||
vectorsRegistered = true;
|
||||
Uniforms.externalVec3Links.push(vec3Link);
|
||||
}
|
||||
case Texture:
|
||||
if(! texturesRegistered){
|
||||
texturesRegistered = true;
|
||||
Uniforms.externalTextureLinks.push(textureLink);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Register and map shader uniforms if it is an armory shader parameter
|
||||
public static function registerShaderUniforms(material: MaterialData) : Bool {
|
||||
|
||||
var uniformExist = false;
|
||||
|
||||
if(! floatsMap.exists(Scene.active.root)) floatsMap.set(Scene.active.root, null);
|
||||
if(! vectorsMap.exists(Scene.active.root)) vectorsMap.set(Scene.active.root, null);
|
||||
if(! texturesMap.exists(Scene.active.root)) texturesMap.set(Scene.active.root, null);
|
||||
|
||||
for(context in material.shader.raw.contexts){ // For each context in shader
|
||||
for (constant in context.constants){ // For each constant in the context
|
||||
if(constant.is_arm_parameter){ // Check if armory parameter
|
||||
|
||||
uniformExist = true;
|
||||
var object = Scene.active.root; // Map default uniforms to scene root
|
||||
|
||||
switch (constant.type){
|
||||
case "float":{
|
||||
var link = constant.link;
|
||||
var value = constant.float;
|
||||
setFloatValue(material, object, link, value);
|
||||
register(Float);
|
||||
}
|
||||
|
||||
case "vec3":{
|
||||
|
||||
var vec = new Vec4();
|
||||
vec.x = constant.vec3.get(0);
|
||||
vec.y = constant.vec3.get(1);
|
||||
vec.z = constant.vec3.get(2);
|
||||
|
||||
setVec3Value(material, object, constant.link, vec);
|
||||
register(Vector);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (texture in context.texture_units){
|
||||
if(texture.is_arm_parameter){ // Check if armory parameter
|
||||
|
||||
uniformExist = true;
|
||||
var object = Scene.active.root; // Map default texture to scene root
|
||||
|
||||
if(texture.default_image_file == null){
|
||||
setTextureValue(material, object, texture.link, null);
|
||||
|
||||
}
|
||||
else{
|
||||
iron.data.Data.getImage(texture.default_image_file, function(image: kha.Image) {
|
||||
setTextureValue(material, object, texture.link, image);
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
register(Texture);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return uniformExist;
|
||||
|
||||
}
|
||||
|
||||
// Method to set map Object -> Material -> Link -> FLoat
|
||||
public static function setFloatValue(material: MaterialData, object: Object, link: String, value: Null<kha.FastFloat>){
|
||||
|
||||
if(object == null || material == null || link == null) return;
|
||||
|
||||
var map = floatsMap;
|
||||
|
||||
var matMap = map.get(object);
|
||||
if (matMap == null) {
|
||||
matMap = new Map();
|
||||
map.set(object, matMap);
|
||||
}
|
||||
|
||||
var entry = matMap.get(material);
|
||||
if (entry == null) {
|
||||
entry = new Map();
|
||||
matMap.set(material, entry);
|
||||
}
|
||||
|
||||
entry.set(link, value); // parameter name, value
|
||||
}
|
||||
|
||||
// Method to set map Object -> Material -> Link -> Vec3
|
||||
public static function setVec3Value(material: MaterialData, object: Object, link: String, value: Vec4){
|
||||
|
||||
if(object == null || material == null || link == null) return;
|
||||
|
||||
var map = vectorsMap;
|
||||
|
||||
var matMap = map.get(object);
|
||||
if (matMap == null) {
|
||||
matMap = new Map();
|
||||
map.set(object, matMap);
|
||||
}
|
||||
|
||||
var entry = matMap.get(material);
|
||||
if (entry == null) {
|
||||
entry = new Map();
|
||||
matMap.set(material, entry);
|
||||
}
|
||||
|
||||
entry.set(link, value); // parameter name, value
|
||||
}
|
||||
|
||||
// Method to set map Object -> Material -> Link -> Texture
|
||||
public static function setTextureValue(material: MaterialData, object: Object, link: String, value: kha.Image){
|
||||
|
||||
if(object == null || material == null || link == null) return;
|
||||
|
||||
var map = texturesMap;
|
||||
|
||||
var matMap = map.get(object);
|
||||
if (matMap == null) {
|
||||
matMap = new Map();
|
||||
map.set(object, matMap);
|
||||
}
|
||||
|
||||
var entry = matMap.get(material);
|
||||
if (entry == null) {
|
||||
entry = new Map();
|
||||
matMap.set(material, entry);
|
||||
}
|
||||
|
||||
entry.set(link, value); // parameter name, value
|
||||
}
|
||||
|
||||
// Mehtod to get object specific material parameter float value
|
||||
static function floatLink(object: Object, mat: MaterialData, link: String): Null<kha.FastFloat> {
|
||||
|
||||
if(object == null || mat == null) return null;
|
||||
|
||||
if(! floatsMap.exists(object)){
|
||||
object = Scene.active.root;
|
||||
}
|
||||
|
||||
var material = floatsMap.get(object);
|
||||
if (material == null) return null;
|
||||
|
||||
var entry = material.get(mat);
|
||||
if (entry == null) return null;
|
||||
|
||||
return entry.get(link);
|
||||
}
|
||||
|
||||
// Mehtod to get object specific material parameter vec3 value
|
||||
static function vec3Link(object: Object, mat: MaterialData, link: String): iron.math.Vec4 {
|
||||
|
||||
if(object == null || mat == null) return null;
|
||||
|
||||
if(! vectorsMap.exists(object)){
|
||||
object = Scene.active.root;
|
||||
}
|
||||
|
||||
var material = vectorsMap.get(object);
|
||||
if (material == null) return null;
|
||||
|
||||
var entry = material.get(mat);
|
||||
if (entry == null) return null;
|
||||
|
||||
return entry.get(link);
|
||||
}
|
||||
|
||||
// Mehtod to get object specific material parameter texture value
|
||||
static function textureLink(object: Object, mat: MaterialData, link: String): kha.Image {
|
||||
|
||||
if(object == null || mat == null) return null;
|
||||
|
||||
if(! texturesMap.exists(object)){
|
||||
object = Scene.active.root;
|
||||
}
|
||||
|
||||
var material = texturesMap.get(object);
|
||||
if (material == null) return null;
|
||||
|
||||
var entry = material.get(mat);
|
||||
if (entry == null) return null;
|
||||
|
||||
return entry.get(link);
|
||||
}
|
||||
|
||||
// Returns complete map of float value material paramets
|
||||
public static function getFloatsMap():Map<Object, Map<MaterialData, Map<String, Null<kha.FastFloat>>>>{
|
||||
|
||||
return floatsMap;
|
||||
}
|
||||
|
||||
// Returns complete map of vec3 value material paramets
|
||||
public static function getVectorsMap():Map<Object, Map<MaterialData, Map<String, Vec4>>>{
|
||||
|
||||
return vectorsMap;
|
||||
}
|
||||
|
||||
// Returns complete map of texture value material paramets
|
||||
public static function getTexturesMap():Map<Object, Map<MaterialData, Map<String, kha.Image>>>{
|
||||
|
||||
return texturesMap;
|
||||
}
|
||||
|
||||
// Remove all object specific material paramenter keys
|
||||
public static function removeObjectFromAllMaps(object: Object) {
|
||||
|
||||
floatsMap.remove(object);
|
||||
vectorsMap.remove(object);
|
||||
texturesMap.remove(object);
|
||||
|
||||
}
|
||||
|
||||
// Remove object specific material paramenter keys
|
||||
public static function removeObjectFromMap(object: Object, type: UniformType) {
|
||||
|
||||
switch (type){
|
||||
case Float: floatsMap.remove(object);
|
||||
|
||||
case Vector: vectorsMap.remove(object);
|
||||
|
||||
case Texture: texturesMap.remove(object);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@:enum abstract UniformType(Int) from Int to Int {
|
||||
var Float = 0;
|
||||
var Vector = 1;
|
||||
var Texture = 2;
|
||||
}
|
|
@ -18,8 +18,9 @@ class PhysicsConstraintExportHelper extends iron.Trait {
|
|||
var breakingThreshold: Float;
|
||||
var limits: Array<Float>;
|
||||
var constraintAdded: Bool = false;
|
||||
var relativeConstraint: Bool = false;
|
||||
|
||||
public function new(body1: String, body2: String, type: Int, disableCollisions: Bool, breakingThreshold: Float, limits: Array<Float> = null) {
|
||||
public function new(body1: String, body2: String, type: Int, disableCollisions: Bool, breakingThreshold: Float, relatieConstraint: Bool = false, limits: Array<Float> = null) {
|
||||
super();
|
||||
|
||||
this.body1 = body1;
|
||||
|
@ -27,14 +28,26 @@ class PhysicsConstraintExportHelper extends iron.Trait {
|
|||
this.type = type;
|
||||
this.disableCollisions = disableCollisions;
|
||||
this.breakingThreshold = breakingThreshold;
|
||||
this.relativeConstraint = relatieConstraint;
|
||||
this.limits = limits;
|
||||
notifyOnInit(init);
|
||||
notifyOnUpdate(update);
|
||||
}
|
||||
|
||||
function init() {
|
||||
var target1 = Scene.active.getChild(body1);
|
||||
var target2 = Scene.active.getChild(body2);
|
||||
var target1;
|
||||
var target2;
|
||||
|
||||
if(relativeConstraint) {
|
||||
|
||||
target1 = object.parent.getChild(body1);
|
||||
target2 = object.parent.getChild(body2);
|
||||
}
|
||||
else {
|
||||
|
||||
target1 = Scene.active.getChild(body1);
|
||||
target2 = Scene.active.getChild(body2);
|
||||
}
|
||||
object.addTrait(new PhysicsConstraint(target1, target2, type, disableCollisions, breakingThreshold, limits));
|
||||
constraintAdded = true;
|
||||
}
|
||||
|
|
|
@ -207,7 +207,7 @@ class PhysicsWorld extends Trait {
|
|||
/**
|
||||
Used to get intersecting rigid bodies with the passed in RigidBody as reference. Often used when checking for object collisions.
|
||||
@param body The passed in RigidBody to be checked for intersecting rigid bodies.
|
||||
@return Array<RigidBody> or null.
|
||||
@return `Array<RigidBody>`
|
||||
**/
|
||||
public function getContacts(body: RigidBody): Array<RigidBody> {
|
||||
if (contacts.length == 0) return null;
|
||||
|
|
|
@ -149,7 +149,7 @@ class RigidBody extends iron.Trait {
|
|||
if (ready) return;
|
||||
ready = true;
|
||||
|
||||
if (!Std.is(object, MeshObject)) return; // No mesh data
|
||||
if (!Std.isOfType(object, MeshObject)) return; // No mesh data
|
||||
|
||||
transform = object.transform;
|
||||
physics = armory.trait.physics.PhysicsWorld.active;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue