Compare commits

...

451 commits

Author SHA1 Message Date
Lubos Lenco 9220e6b57e
Merge pull request #2381 from Skehmatics/fix/abc_deprication
Correct depricated (and now removed) import
2021-11-08 10:14:09 +01:00
Lubos Lenco 15ec53830f
Merge pull request #2379 from MoritzBrueckner/fix-cpu-count
Fix cpu_count() for incomplete PATH var on Windows and improve error handling
2021-11-08 10:13:36 +01:00
Lubos Lenco 946610c793
Merge pull request #2382 from Skehmatics/fix/morph_targets_linux
Fix morph target exporting on Unix-based systems
2021-11-08 09:07:13 +01:00
Moritz Brückner 1430e22a90 Make utils.cpu_count() even more failsafe on Windows 2021-11-07 16:50:20 +01:00
Derek Schmidt 07f4bea206 Fix morph target exporting on Unix-based systems
Also fixes some extra space issues since my editor auto-fixed them
2021-11-06 17:18:36 -07:00
Derek Schmidt 8581a75f9c Correct depricated (and now removed) import 2021-11-06 14:52:05 -07:00
Moritz Brückner 6bb2513001 Fix cpu_count() for incomplete PATH var on Windows and improve error handling 2021-11-06 22:36:04 +01:00
Lubos Lenco f581e91ba9 Move in morph target texture links 2021-11-06 12:34:03 +01:00
Lubos Lenco 263d5853a5
Merge pull request #2375 from QuantumCoderQC/shape-keys
Implementing Shape keys
2021-11-06 12:31:23 +01:00
QuantumCoderQC 1cec287891 Conditional compilation for shape key node 2021-11-02 15:59:40 +01:00
QuantumCoderQC 83a60e7462 Implement shape key conditions 2021-11-02 15:59:15 +01:00
QuantumCoderQC 603d23fbfd Add shape key export option 2021-11-02 15:58:38 +01:00
QuantumCoderQC 03090cafa2 remove shape key textures on clean 2021-11-02 15:56:46 +01:00
QuantumCoderQC a1951bb66e clean up export 2021-11-02 15:56:24 +01:00
QuantumCoderQC 3c0f580f69 fix morph weights lookup 2021-11-02 13:42:09 +01:00
QuantumCoderQC 8116729822 fix pixel count for images, fix max shape keys 2021-11-02 13:42:09 +01:00
QuantumCoderQC 6c0d4bdead fix error when all shape keys muted 2021-11-02 13:42:09 +01:00
QuantumCoderQC 8f733222a9 fix shape keys and multiple uv 2021-11-02 13:42:09 +01:00
QuantumCoderQC 4b65d8d68c do not export muted shape keys 2021-11-02 13:42:09 +01:00
QuantumCoderQC 13a2f4538a move shape key textures to dedicated directory 2021-11-02 13:42:09 +01:00
QuantumCoderQC b7cafbb4e3 add node to set shape key value 2021-11-02 13:42:08 +01:00
QuantumCoderQC d4f9982768 documentation 1 2021-11-02 13:42:08 +01:00
QuantumCoderQC 8e69bea14e appy position scale 2021-11-02 13:42:08 +01:00
QuantumCoderQC 669898fae1 fix normals with shape key and skin 2021-11-02 13:42:08 +01:00
QuantumCoderQC 8df6fc9176 fix shape key with skinning 2021-11-02 13:42:08 +01:00
QuantumCoderQC edeaf488b9 remove debug prints 2021-11-02 13:42:08 +01:00
QuantumCoderQC cb2cf0c9b4 keep both vert colors and shape keys 2021-11-02 13:42:07 +01:00
QuantumCoderQC 4522055fac use vec4 uniform array instead of float array 2021-11-02 13:42:07 +01:00
QuantumCoderQC 1d0eaf9371 debug prints 2021-11-02 13:42:07 +01:00
QuantumCoderQC e562d2515e export with optimized texture size 2021-11-02 13:42:07 +01:00
QuantumCoderQC 8e7d8a4f56 additional uniforms 2021-11-02 13:42:06 +01:00
QuantumCoderQC 6e153569dc make attrib skin fix 2021-11-02 13:42:06 +01:00
QuantumCoderQC d01c55fcd4 mordify to export shape keys 2021-11-02 13:42:06 +01:00
QuantumCoderQC 3814cd9da7 methods to get if vertex colors and if shapekey present 2021-11-02 13:42:06 +01:00
QuantumCoderQC 0636eb85c6 add morph attribute to shaders 2021-11-02 13:42:06 +01:00
QuantumCoderQC 2f77c5b060 modify normals calculation in skinning for morphing 2021-11-02 13:42:06 +01:00
QuantumCoderQC 26a0fb8c5a add morph target to make_shader.py 2021-11-02 13:42:05 +01:00
QuantumCoderQC 8c034655be implement morph_target.glsl 2021-11-02 13:42:05 +01:00
QuantumCoderQC 6f9b51a57a move make_morph_target 2021-11-02 13:42:05 +01:00
QuantumCoderQC 34243ed74c implement make_morph_target 2021-11-02 13:42:05 +01:00
QuantumCoderQC fb004f5dcc make attributes for shadow maps and depth 2021-11-02 13:42:05 +01:00
QuantumCoderQC 867100d151 make shader attribute for morph targets 2021-11-02 13:42:05 +01:00
QuantumCoderQC 09433f2a19 init morph target glsl 2021-11-02 13:42:05 +01:00
QuantumCoderQC 10d41e5eca init make morph target 2021-11-02 13:42:05 +01:00
QuantumCoderQC b7941d2fa8 export shape keys as texture 2021-11-02 13:42:04 +01:00
Lubos Lenco 93563dbba5 Bump version 2021-11-02 10:29:01 +01:00
Lubos Lenco 9094154440
Merge pull request #2367 from MoritzBrueckner/fix-library-textures
Fix exporting textures from linked libraries
2021-11-01 21:51:20 +01:00
Lubos Lenco 6ad9941d43
Merge pull request #2374 from tong/fix-uniformsmanager-register
Fix switch expression
2021-11-01 20:53:23 +01:00
Lubos Lenco 326d3bbf0d
Merge pull request #2373 from QuantumCoderQC/pick-rb-imp
add normal output for pick rb node
2021-11-01 20:52:23 +01:00
Lubos Lenco b2566a8249
Merge pull request #2372 from QuantumCoderQC/decal-fix
Decal fix
2021-11-01 20:51:37 +01:00
tong 18c5636d03 Fix switch expression 2021-11-01 02:44:56 +01:00
QuantumCoderQC 07cfa40727 add normal output for pick rb node 2021-10-31 23:06:11 +01:00
QuantumCoderQC e06ca4b9e7 get material from decal object too 2021-10-31 23:03:25 +01:00
QuantumCoderQC ec1f25cfec add support for decal object uniforms 2021-10-31 23:02:45 +01:00
QuantumCoderQC 1dc733ca88 dont cast decal objects to mesh objects 2021-10-31 20:58:27 +01:00
Lubos Lenco f22542a0b4
Merge pull request #2369 from t3du/master
add Between and Not Equal to Compare Logic
2021-10-28 11:40:37 +02:00
t3du c97c738870
add Between and Not Equal to Compare Logic 2021-10-27 10:35:58 -03:00
t3du 130e470290
add Between and Not Equal to Compare Logic 2021-10-27 10:32:58 -03:00
Lubos Lenco fabb4c0c3c
Merge pull request #2368 from t3du/master
add Not Equal to Gate Node
2021-10-26 16:50:04 +02:00
t3du ca03897811
Update LN_gate.py 2021-10-26 10:08:46 -03:00
t3du 6e255bcb05
add Not Equal to Gate node logic 2021-10-26 10:05:11 -03:00
t3du f6dfc43dde
add Not Equal to Gate Node 2021-10-26 10:04:31 -03:00
Moritz Brückner 36e42ad736 Fix exporting textures from linked libraries 2021-10-25 19:43:13 +02:00
Lubos Lenco 3df2916f5b
Merge pull request #2366 from MoritzBrueckner/fix-collection-export
Fix exporting collections with parent object in another collection
2021-10-25 10:00:41 +02:00
Moritz Brückner 59aca7ea41 Fix exporting collections with parent object in another collection 2021-10-23 17:12:22 +02:00
Lubos Lenco 297f7cdfca
Merge pull request #2363 from t3du/master
add get object uid nodes / agg args to call haxe static function / add Between to gate node
2021-10-22 09:18:51 +02:00
t3du 176ab43fd0
fix return with correct screen cords
solution from:

https://forums.armory3d.org/t/worldtoscreencoord-draw-debug-lines-with-2d-api/3467/9
2021-10-20 16:51:11 -03:00
t3du 6b1333902c
change version and add NodeReplacement 2021-10-20 11:15:06 -03:00
t3du 89ff1c29fc
change node version and add NodeReplacement 2021-10-20 11:12:01 -03:00
t3du 086c05eba2
change node version and add NodeReplacement 2021-10-20 11:11:44 -03:00
t3du 3e6e1e4bd1
change info 2021-10-20 09:49:00 -03:00
t3du 977b2db376
change info 2021-10-20 09:48:17 -03:00
t3du ebb3076431
add between logic condition 2021-10-19 21:19:16 -03:00
t3du 826dbd786d
add property0 between 2021-10-19 21:18:02 -03:00
t3du 4fe8f683dc
add args to the call of haxe static function 2021-10-19 19:11:10 -03:00
t3du b9b5c65141
add args to the haxe static function 2021-10-19 19:07:49 -03:00
t3du ec3054cdeb
add uid nodes 2021-10-18 17:55:44 -03:00
t3du d3b006c873
add nodes for uid 2021-10-18 17:53:09 -03:00
Lubos Lenco 9c931aff56
Merge pull request #2362 from tong/fix-doc-generation
Fix dox when using special characters
2021-10-15 16:02:15 +02:00
tong 622b8a275f Fix dox when using special characters 2021-10-14 17:35:23 +02:00
Lubos Lenco ea9b01e733
Merge pull request #2361 from SaxonGao-SZ/master
Use project name for web title
2021-10-14 12:35:03 +02:00
SaxonGao-SZ 34897c9747
feature: Use project name for web title
feature: Use project name for web title
2021-10-13 20:52:36 +08:00
Lubos Lenco c1f98dc668
Merge pull request #2359 from t3du/master
add logic nodes: set/get canvas font size and set progress bar color
2021-10-12 16:20:55 +02:00
t3du 67d511568f
add new nodes 2021-10-11 17:41:03 -03:00
t3du b8319fe28b
add new nodes 2021-10-11 17:38:18 -03:00
t3du d5e0208fd6
add getCanvasFontSize and fix setCanvasFontSize 2021-10-11 17:35:56 -03:00
Lubos Lenco 0fadefab69
Merge pull request #2357 from QuantumCoderQC/fix-random-color
random color node fix
2021-10-08 10:27:07 +02:00
QuantumCoderQC 50a1994867 random color node fix 2021-10-07 19:18:43 +02:00
Lubos Lenco b9a220fbcb
Merge pull request #2356 from MoritzBrueckner/fix-world-geometry
Fix Geometry and Texture Coordinate nodes for world shaders
2021-10-06 10:17:43 +02:00
Moritz Brückner 5e1105f51d Fix some Texture Coordinate node outputs for world shaders 2021-10-05 19:03:08 +02:00
Moritz Brückner b060953a7e Further fixes for the geometry node on world shaders 2021-10-05 18:41:45 +02:00
Moritz Brückner a4d09936d6 Fix world normals and position (adjust to Blender) 2021-10-05 18:40:39 +02:00
Lubos Lenco 786e68e475
Merge pull request #2355 from MoritzBrueckner/fix-deprecated-nodes
Fix deprecated nodes and improve deprecation handling
2021-10-05 11:02:00 +02:00
Lubos Lenco c7cba9d792
Merge pull request #2353 from MoritzBrueckner/debug-renderpath
Allow to set default renderpath for debugging
2021-10-05 11:01:00 +02:00
Lubos Lenco d9ddb5f4a3
Merge pull request #2352 from MoritzBrueckner/fix-cmft-cpu-count
Fix CPU count parameter for cmft
2021-10-05 09:39:18 +02:00
Moritz Brückner 8e8e8f586d Assert correct category for deprecated nodes 2021-10-05 00:03:48 +02:00
Moritz Brückner e8fa3b1b9a Whitespace cleanup 2021-10-04 23:57:15 +02:00
Moritz Brückner 7289b95a48 Don't show empty "Deprecated" node category menu 2021-10-04 23:56:35 +02:00
Moritz Brückner 7f5d382131 Allow to set default renderpath for debugging 2021-10-03 22:40:29 +02:00
Lubos Lenco ea02600d14 Bump version 2021-10-03 20:15:36 +02:00
Lubos Lenco a2c33b2f6a
Merge pull request #2351 from MoritzBrueckner/debug-console-trace
Debug console: make log output more readable
2021-09-28 13:00:51 +02:00
Moritz Brückner c40fd26c20 Fix CPU count parameter for cmft 2021-09-27 23:13:30 +02:00
Moritz Brückner 308ab2d77b Add some tooltips to the debug console 2021-09-27 16:02:29 +02:00
Moritz Brückner d979e4fde9 Debug console: make spacing between log lines smaller 2021-09-27 15:53:08 +02:00
Moritz Brückner 1c237dd6c3 Make printing with PosInfos configurable in the debug console UI 2021-09-27 15:46:35 +02:00
Moritz Brückner 152959699a Debug console: optionally omit PosInfos when printing 2021-09-27 15:43:03 +02:00
Moritz Brückner 259c375fda Whitespace cleanup 2021-09-27 15:41:53 +02:00
Lubos Lenco b579c8a15d
Merge pull request #2350 from MoritzBrueckner/fix-nodes-reload
Fix add-on reloading when there are new unimported node files
2021-09-27 11:03:02 +02:00
Lubos Lenco 73a352b76e
Merge pull request #2349 from MoritzBrueckner/global-canvas-scale-nodes
Add nodes to get/set global canvas scale
2021-09-27 11:02:16 +02:00
Moritz Brückner 957c5371c8 Fix add-on reloading when there are new unimported node files 2021-09-26 22:34:09 +02:00
Moritz Brückner 962f8a79a5 Add nodes to get/set global canvas scale 2021-09-26 22:31:56 +02:00
Lubos Lenco 8604e670c3
Merge pull request #2342 from tong/log-message-improvements
Improve log messages
2021-09-26 09:51:06 +02:00
tong d1d266a0f0 Improve log messages 2021-09-23 11:30:46 +02:00
Lubos Lenco 62d399e01a
Merge pull request #2338 from tong/no-haxe-times-param
Remove haxe --times param per default
2021-09-22 19:21:52 +02:00
tong 128efcc0ef Use haxe_times prefs field 2021-09-21 14:56:12 +02:00
tong 3920c475be No haxe times param 2021-09-21 14:43:47 +02:00
Lubos Lenco e3a55db813
Merge pull request #2339 from tong/fix-local-sdk-path
Fix invalid fp when using local sdk
2021-09-21 11:42:22 +02:00
Lubos Lenco 597c291da7
Merge pull request #2336 from QuantumCoderQC/tweenNodes
Introducing Tween nodes
2021-09-19 10:25:45 +02:00
Lubos Lenco 16976cdc5b
Merge pull request #2335 from MoritzBrueckner/fix-trait-fakeuser
Fix fake user export for traits
2021-09-18 11:05:19 +02:00
tong d1fe4d6686 Fix invalid fp when using local sdk 2021-09-17 13:21:36 +02:00
QuantumCoderQC ca966588ff add documentation 2021-09-13 23:10:31 +02:00
QuantumCoderQC 0ce0c5c115 change socket order 2021-09-13 22:48:32 +02:00
QuantumCoderQC 05465bcea1 minor clean-up 2021-09-13 22:30:39 +02:00
Moritz Brückner 77815d95ed Fix fake user export for traits 2021-09-13 21:29:21 +02:00
Lubos Lenco 156f1f433a
Merge pull request #2334 from tong/fix-throw-assert-error
Fix assert throw error
2021-09-13 10:03:11 +02:00
Lubos Lenco 5b4d24f067
Merge pull request #2332 from MoritzBrueckner/fix-realtime-postprocess
Fix realtime postprocess & cleanup arm.lib.make_datas
2021-09-12 08:05:29 +02:00
tong c24389813f Fix assert throw error 2021-09-12 00:03:57 +02:00
Lubos Lenco c398c1181e
Merge pull request #2331 from tong/fix-background-mode-open-build-dir
Do not open build directory in background mode
2021-09-11 13:49:20 +02:00
Lubos Lenco 7d9d5ac50f
Merge pull request #2329 from MoritzBrueckner/fix-ArmNodeAddInputOutputButton
Fix ArmNodeAddInputOutputButton
2021-09-10 09:12:59 +02:00
QuantumCoderQC eb5ef99309 create tween vector node 2021-09-10 01:08:31 +02:00
QuantumCoderQC 62294c8bb4 create tween rotation node 2021-09-10 01:08:12 +02:00
QuantumCoderQC ed6aa96fb0 create tween float node 2021-09-10 01:07:52 +02:00
Lubos Lenco f3fcb2846e
Merge pull request #2326 from onelsonic/patch-2
Update props_ui.py
2021-09-08 08:51:07 +02:00
Lubos Lenco afeecd4df1
Merge pull request #2325 from onelsonic/patch-1
Update props.py
2021-09-08 08:49:39 +02:00
Moritz Brückner de72bbf3a4 Cleanup arm.lib.make_datas 2021-09-07 23:40:52 +02:00
Moritz Brückner ecc4317919 Fix realtime postprocess: use compositor defines also for non-compositor pass shaders 2021-09-07 22:19:12 +02:00
tong 667e73c867 Do not open build directory in background mode 2021-09-07 10:15:11 +02:00
Moritz Brückner 56d84b08f4 Cleanup 2021-09-06 18:23:21 +02:00
Moritz Brückner adb2468245 Fix ArmNodeAddInputOutputButton 2021-09-06 18:22:38 +02:00
onelsonic abc52627a3
Update props_ui.py
change the UI to reflect common order to setup Android SDK values
https://developer.android.com/guide/topics/manifest/uses-sdk-element.html
android:minSdkVersion="integer"
then
android:targetSdkVersion="integer"
then
android:maxSdkVersion="integer"
2021-09-06 15:33:16 +02:00
onelsonic 68ef00b668
Update props.py
proposed UI descriptions changes to reflect current Android SDK
https://developer.android.com/guide/topics/manifest/uses-sdk-element.html
and updating default SDK values to Android Oreo
2021-09-06 15:26:13 +02:00
Lubos Lenco 55cfead084 Bump version 2021-09-06 09:22:25 +02:00
Lubos Lenco fe6d1fa372
Merge pull request #2320 from QuantumCoderQC/AddTraitFix
Add trait fix
2021-09-06 09:02:22 +02:00
Lubos Lenco 974181e75e
Merge pull request #2319 from MoritzBrueckner/assert-string-expr
Allow to use more complex string expressions as assert() messages
2021-09-05 11:55:28 +02:00
Lubos Lenco a4ab1dcc98
Merge pull request #2318 from QuantumCoderQC/navMeshImprove
Small improvement to Navigation nodes
2021-09-04 15:15:44 +02:00
QuantumCoderQC ccbc946bf1 Add warning if trait is already applied on the object 2021-09-03 23:42:43 +02:00
QuantumCoderQC fddef0983c Modify Add Trait Node To Accept String Trait 2021-09-03 23:37:13 +02:00
Moritz Brückner e715bf0108 Allow to use more complex string expressions as assert() messages 2021-09-03 22:21:57 +02:00
QuantumCoderQC 214b84fcf7 Modify NavAgent Trait 2021-09-03 21:00:58 +02:00
QuantumCoderQC 32b745f829 Modify Navigation Go To Location Node 2021-09-03 21:00:33 +02:00
QuantumCoderQC 8caf859db9 Create and implement Get Nav Agent Data Node 2021-09-03 20:59:49 +02:00
Lubos Lenco d6692efbdc
Merge pull request #2316 from onelsonic/patch-1
correcting Haxe Warnings : Std.is is deprecated. Use Std.isOfType ins…
2021-09-03 12:37:23 +02:00
onelsonic c77eea93fa
correcting Haxe Warnings : Std.is is deprecated. Use Std.isOfType instead.
correcting Warning : Std.is is deprecated. Use Std.isOfType instead.
2021-09-03 08:36:13 +02:00
Lubos Lenco e0cbf1b332
Merge pull request #2315 from MoritzBrueckner/fix-ppcomp-warnings
Fix "Uniform PPCompXX not found" warnings
2021-09-02 20:05:11 +02:00
Moritz Brückner b7024a5854 Whitespace cleanup 2021-09-02 17:18:59 +02:00
Moritz Brückner 44d8325001 Fix "Uniform PPCompXX not found" warnings 2021-09-02 17:14:18 +02:00
Lubos Lenco 052c7b00c5
Merge pull request #2309 from MoritzBrueckner/assert
Add assert() macro
2021-09-01 09:16:46 +02:00
Lubos Lenco 675618e529
Merge pull request #2308 from tong/html5-server-settings
HTML5 webserver log, port prefs
2021-08-30 09:10:26 +02:00
Moritz Brückner a6b67e4e00 Improve assert() docstring 2021-08-27 14:34:59 +02:00
Moritz Brückner 4b75a896d6 Auto-import assert() macro 2021-08-27 01:32:38 +02:00
Moritz Brückner ecddc0af92 Add assert() macro 2021-08-27 01:26:00 +02:00
tong e05d556552 Webserver log, port prefs 2021-08-26 10:01:35 +02:00
Lubos Lenco 85edde6d24
Merge pull request #2305 from niacdoial/newrotation
Added a rotation node-socket
2021-08-26 09:53:25 +02:00
niacdoial 703c618c7d
Misc. patches before merge [watch for amends]
- fixed type/import bugs in RotationNode.hx and SeparateRotationNode.hx
2021-08-21 16:07:34 +02:00
Lubos Lenco df715db381
Merge pull request #2307 from MoritzBrueckner/krom-es6
Switch to ES6 on krom target and fix 'armory' define
2021-08-20 10:35:19 +02:00
Lubos Lenco a8a44df249
Merge pull request #2306 from MoritzBrueckner/various-node-fixes
Various node fixes
2021-08-20 10:34:22 +02:00
Moritz Brückner 1eb087125f Fix 'armory' define 2021-08-19 22:27:09 +02:00
Moritz Brückner 2347348504 Switch to ES6 on krom target
See https://github.com/armory3d/armorcore/issues/32
2021-08-19 22:26:30 +02:00
Moritz Brückner 3e22cb3375 Update ArmOpenNodeWikiEntry to new wiki page structure 2021-08-19 22:02:01 +02:00
Moritz Brückner 4e526a6dd3 Various smaller node fixes 2021-08-19 21:59:52 +02:00
Moritz Brückner 2630c159d8 Align new custom sockets to Blender UI 2021-08-19 21:58:43 +02:00
niacdoial a67452802d
React to commit 14d33ee0530e5db640e0fafb8604662333c1b066 in iron. 2021-08-19 11:31:12 +02:00
niacdoial f892fdfd8a
Merge months of changes into 'newrotation' branch
(and homogeneised the contents of said branch in the process)
(plus a couple bugfixes, because what else)
2021-08-18 17:04:00 +02:00
Lubos Lenco 29785172f4
Merge pull request #2304 from tong/just-run
Shift click play just run
2021-08-18 11:03:21 +02:00
niacdoial 1d0a6d7955
Did the haxe part of the ongoing update.
Also fixed a ton of bugs in the python part.
NOTE: this requires a yet-to-be-done commit to Iron to work.
2021-08-17 19:29:35 +02:00
tong 7b6d3536e3 Shift click play just run 2021-08-17 17:47:04 +02:00
Lubos Lenco f017d68ed7
Merge pull request #2303 from MoritzBrueckner/fix-nishita-LUT
Fix nishita artifacts and improve LUT value range
2021-08-17 09:30:22 +02:00
Moritz Brückner 1de97e1898 Minor cleanup 2021-08-15 00:30:41 +02:00
Moritz Brückner ca96174b6b Fix nishita sky artifacts on some GPUs
It could happen that values returned by dot() were slightly larger than 1 or less than -1 due to precision errors, but acos() is undefined outside of [-1, 1]. This would lead to NaN values on some GPUs, causing visible artifacts.
2021-08-14 23:45:33 +02:00
niacdoial bd67667a6e Added node replacement routines for previous commits
(and fixed a couple bugs along the way)
2021-08-12 20:58:35 +02:00
Lubos Lenco 2910fcf1a8
Merge pull request #2302 from MoritzBrueckner/fix-addon-reload
Fix accidental module reloading caused by name conflicts of global vars
2021-08-11 18:25:44 +02:00
Moritz Brückner c56a0c3a72 Fix accidental module reloading caused by name conflicts of global vars 2021-08-11 14:32:21 +02:00
Moritz Brückner d610cc6a2f Fix value range in Nishita LUT 2021-08-09 16:51:26 +02:00
Lubos Lenco 34f6e0fc7c Kha update 2021-08-08 13:02:19 +02:00
Lubos Lenco 45e3c1c138
Merge pull request #2298 from MoritzBrueckner/reload-addon
Implement basic addon reloading
2021-08-07 19:06:44 +02:00
Lubos Lenco c49bece460
Merge pull request #2299 from MoritzBrueckner/fix-armsdk-ci
Fix armsdk CI
2021-08-07 19:03:57 +02:00
Lubos Lenco 2ef4f19eb7
Merge pull request #2300 from N8n5h/volumetric-light
fix volumetric lights not working when shadow map atlas is enabled
2021-08-07 16:54:08 +02:00
N8n5h 5509096158 fix volumetric lights not working with shadow map atlas enabled
Added missing code so the shader refers to the correct variable when
using shadow map atlasing.
2021-08-06 18:34:39 -03:00
Moritz Brückner 2d3e15064a Fix armsdk CI
Updated Logic.hx with changes made in make_logic.py. Is this file even used somewhere?
2021-08-06 22:33:20 +02:00
Lubos Lenco 386d2a3bf4 Bump version 2021-08-06 11:10:28 +02:00
Lubos Lenco 7607cc8ccd
Merge pull request #2296 from tong/physics-drag-limit-props
PhysicsDrag trait limit props
2021-08-05 22:13:58 +02:00
Lubos Lenco 52a594c910
Merge pull request #2297 from MoritzBrueckner/ui-font-fix
Canvas: fix using non-default fonts
2021-08-05 22:13:30 +02:00
Moritz Brückner 4c4bebcf4f Canvas: fix using non-default fonts 2021-08-04 23:35:54 +02:00
Moritz Brückner ea8c13686c Implement basic addon reloading 2021-08-04 22:56:11 +02:00
tong 4c34c2a5ce PhysicsDrag trait limit props 2021-08-04 22:09:54 +02:00
Lubos Lenco b664e3a010
Merge pull request #2287 from MoritzBrueckner/fix-thread-polling
Continue thread polling after an exception in the done callback
2021-08-02 08:23:37 +02:00
Lubos Lenco 60d0f443f8
Merge pull request #2286 from MoritzBrueckner/fix-getfp-drive-root
Windows: fix arm.utils.get_fp() if the project path is a drive root
2021-08-01 16:50:22 +02:00
Lubos Lenco aeffd76b75
Merge pull request #2285 from tong/arcball-improvements
ArcBall axis trait prop
2021-07-31 20:07:16 +02:00
Lubos Lenco 1532a332ff
Merge pull request #2284 from QuantumCoderQC/TerrainTextureFix
Fix terrain export for Krom
2021-07-30 08:25:01 +02:00
Moritz Brückner 4fc1f38b3b Continue thread polling after an exception in the done callback 2021-07-27 00:21:27 +02:00
Moritz Brückner 5f2dce140e Windows: fix arm.utils.get_fp() if the project path is a drive root 2021-07-26 23:40:47 +02:00
tong 13cf22ecc2 ArcBall axis trait prop 2021-07-26 19:26:17 +02:00
QuantumCoderQC 9f7af6a1cd Change terrain material bump output to normal 2021-07-26 18:02:23 +02:00
QuantumCoderQC 9ec425f6ae get file name only if specifiedin node 2021-07-26 13:50:52 +02:00
QuantumCoderQC 3bad878650 Add exception for null data 2021-07-26 13:48:44 +02:00
Lubos Lenco ce75516c59
Merge pull request #2283 from MoritzBrueckner/live-patch
Live patch: refactor and logic nodes support
2021-07-26 09:00:31 +02:00
Moritz Brückner bce14549ac Fix LN live patch when using multiple instances of the same logic tree 2021-07-26 00:02:54 +02:00
Moritz Brückner ee208ece18 Live patch: ignore two more operators 2021-07-25 20:20:43 +02:00
Moritz Brückner 549040fc09 Fix publishing with live patch enabled 2021-07-25 20:13:47 +02:00
Moritz Brückner 62ff11747b Update nodes for live patch support (merge conflict cleanup) 2021-07-25 19:50:51 +02:00
Moritz Brückner 6a3045477f Fix physics node if arm_physics is false + cleanup 2021-07-25 18:36:36 +02:00
Moritz Brückner 8a758bbe26 Only stop live patch session if live patch was active 2021-07-25 17:07:51 +02:00
Moritz Brückner ffee6dc521 Fix error caused by resolving merge conflict 2021-07-25 17:02:29 +02:00
Moritz Brückner cca82a69bf
Merge branch 'master' into live-patch 2021-07-25 16:47:32 +02:00
Moritz Brückner c52d25e471 arm_props.py: cleanup and fix docstrings 2021-07-25 00:15:32 +02:00
Moritz Brückner cf1dd0ac71 Live patch: fix creation of node outputs 2021-07-24 23:07:22 +02:00
Moritz Brückner 8e1aa2fb0d Live patch: fix creation of nodes without properties 2021-07-24 23:06:53 +02:00
Moritz Brückner 6d2b825dd5 Fix LN replacement and take arm_watch and arm_logic_id properties into account 2021-07-24 20:24:04 +02:00
Moritz Brückner 6050bceaf1 Fix nodes with "..._get" property names 2021-07-24 20:17:29 +02:00
Moritz Brückner dbb0764ca7 Fix typo 2021-07-24 20:16:54 +02:00
Moritz Brückner 568f4f3a6d Remove unnecessary privateAccess metadata 2021-07-24 19:51:01 +02:00
Moritz Brückner 0a58279756 Live patch: add more ignored operators 2021-07-24 19:49:35 +02:00
Moritz Brückner ff5fd9c7ed Fix generator usage 2021-07-24 19:49:19 +02:00
Moritz Brückner 0456d5f080 Remove legacy code stub 2021-07-24 18:21:06 +02:00
Moritz Brückner af520b518e Fix compatibility for frames and reroutes 2021-07-24 13:54:48 +02:00
Moritz Brückner 82c7302dd9 Live patch: simplify node deletion code 2021-07-24 13:54:31 +02:00
Moritz Brückner 2b6a7a4f78 Live patch: add another ignored operator 2021-07-24 13:37:13 +02:00
Moritz Brückner 7eced3b4f5 Live patch: don't try to re-export if live patch is not active 2021-07-24 13:36:55 +02:00
Moritz Brückner aa21402221 Live patch: handle deletion of node links 2021-07-24 13:36:16 +02:00
Lubos Lenco 97cc737aff
Merge pull request #2280 from MoritzBrueckner/fix-multi-uv
Fix usage of multiple UV maps on mobile render path
2021-07-22 09:28:00 +02:00
Moritz Brückner 256d27e289 Fix vector/color handling for logic node live patching 2021-07-21 22:58:21 +02:00
Moritz Brückner 9ff726bac1 Fix usage of multiple UV maps on mobile render path 2021-07-21 00:01:27 +02:00
Moritz Brückner 5276711094 Live patch: add more ignored operators 2021-07-20 23:34:06 +02:00
Moritz Brückner 4f13ebc439 Live patch: fix updates of object sockets 2021-07-20 23:33:47 +02:00
Moritz Brückner 1edc7a9469 Live patch: support for adding nodes 2021-07-20 20:53:37 +02:00
Moritz Brückner 3ed915b654 Cleanup LivePatch.hx 2021-07-20 14:28:42 +02:00
Moritz Brückner e930da7388 Live patch: support for node deletion 2021-07-20 14:25:35 +02:00
Moritz Brückner c65764be99 Cleanup LivePatch.hx 2021-07-20 14:24:00 +02:00
Moritz Brückner bdee03873b Live patch: support for node duplication 2021-07-18 22:29:18 +02:00
Lubos Lenco 1b758ec32c
Merge pull request #2276 from tong/fix-fetch-prop-type
Fix fetch trait prop type
2021-07-18 09:12:44 +02:00
tong cfa941eab4 Fix fetch trait prop type 2021-07-17 18:49:37 +02:00
niacdoial 9b1393ea41
Make rotation its own socket in logic nodes, add rotation-specific math node
(part 1: conversion code not developed)
2021-07-11 11:28:00 +02:00
Lubos Lenco bfde181da6
Merge pull request #2268 from MoritzBrueckner/fix-gbuffer2-overlay
Fix visual artifacts caused by invalid gbuffer2 on OpenGL
2021-07-11 10:48:00 +02:00
Lubos Lenco a59c789528
Merge pull request #2266 from QuantumCoderQC/staticTargetFix
Static target fix
2021-07-11 10:46:52 +02:00
Lubos Lenco caa03b59c5
Merge pull request #2263 from knowledgenude/master
Fix nullability
2021-07-11 10:42:12 +02:00
Lubos Lenco ff93e5f824
Merge pull request #2262 from tong/replace-deprecated-std-is
Replace deprecated Std.is with Std.isOfType
2021-07-11 10:41:53 +02:00
Moritz Brückner b3162d8f6e Fix visual artifacts caused by invalid gbuffer2 on OpenGL 2021-07-10 22:41:19 +02:00
Moritz Brückner 823cc379b6 Live patch: ignore more operators & fix code style 2021-07-10 22:08:19 +02:00
Moritz Brückner ee194a1806 Live patch: support for socket default values 2021-07-10 21:50:30 +02:00
Moritz Brückner 96aa0ee890 Use custom sockets for default data types
This allows to listen for socket updates for the live patch system
2021-07-10 21:46:44 +02:00
QuantumCoderQC c0333db44f Fix typos. Fix fast float 2021-07-10 19:22:26 +02:00
QuantumCoderQC e0ff256f40 make boolean objects nullable for static targets 2021-07-10 19:20:56 +02:00
Henrique 28d21bf35f Fix nullability 2021-07-09 21:42:12 -03:00
tong b452acaebb Replace deprecated Std.is with Std.isOfType 2021-07-09 22:04:50 +02:00
Lubos Lenco 3c88ddcb23
Merge pull request #2260 from knowledgenude/master
Improved Input Map and added nodes to it
2021-07-09 07:52:24 +02:00
Henrique db5aed465e Add static method to remove keys 2021-07-08 16:10:45 -03:00
Henrique 55cf2896a2 Cleanup 2021-07-07 17:11:56 -03:00
Henrique daee309ad8 Add Remove Input Map Key node 2021-07-07 17:08:01 -03:00
Henrique 43a574eb15 Remove unnecessary read access 2021-07-07 16:51:07 -03:00
Henrique 919512fad0 Improve InputMap and add nodes to it 2021-07-07 16:33:20 -03:00
Lubos Lenco 14b18408aa
Merge pull request #2254 from N8n5h/fix-atlas-ui
Fix compiling error with shadow map atlas shadow size option
2021-07-06 23:35:35 +02:00
N8n5h 801668a0c2 Fix compiling error with shadow map atlas shadow size option
Added 512 option to Inc so it doesn't fails compilation because of
missing option as explained here
https://github.com/armory3d/armory/issues/2252#issue-937328497
2021-07-06 10:39:07 -03:00
Lubos Lenco dc6753c2ca Bump version 2021-07-06 10:46:44 +02:00
Lubos Lenco 6dd27bfeed
Merge pull request #2251 from MoritzBrueckner/ui-canvas-font
UI Canvas: use font from asset for all element types
2021-07-06 09:20:43 +02:00
Moritz Brückner e7da337530 UI Canvas: use font from asset for all element types 2021-07-05 19:25:47 +02:00
Lubos Lenco 50c8ceec1e
Merge pull request #2247 from QuantumCoderQC/LogicNodeFix
Add check to LogicNode run
2021-07-04 23:19:57 +02:00
Moritz Brückner a6ec652d5f Fix identity node replacement for Blender 2.93 2021-07-03 22:49:19 +02:00
QuantumCoderQC cb800729d2 Add check
Add a check to see if input socket is linked to correct output socket
2021-07-03 20:12:10 +02:00
Moritz Brückner 4e19ddfeb0 Do not send live patch events if live patch isn't running 2021-07-03 19:47:09 +02:00
Moritz Brückner b2153dbcd2 Cleanup 2021-07-03 19:45:35 +02:00
Moritz Brückner 4387d774cc Live patch: add support for node property updates 2021-07-03 19:45:05 +02:00
Lubos Lenco 738a217001
Merge pull request #2245 from QuantumCoderQC/NavMeshNodeFix
A few small fixes to UniformsManager calss and go to location node
2021-07-02 19:24:34 +02:00
QuantumCoderQC 9e493f6e79 do not remove trait at init 2021-07-01 15:33:28 +02:00
QuantumCoderQC 7504d5d92b Change input type from shader to vector 2021-07-01 15:32:53 +02:00
Lubos Lenco e308d9058b
Merge pull request #2242 from knowledgenude/master
Add "Parent Relative" option to location nodes
2021-06-29 08:44:17 +02:00
Henrique c7e1f5d0a9 Fix nodes 2021-06-28 16:12:05 -03:00
Moritz Brückner 202138304a Live patch: add support for creating connections between nodes 2021-06-28 12:17:13 +02:00
Lubos Lenco 8c0b6ba13e
Merge pull request #2240 from QuantumCoderQC/RelativePhysConstraint
Add option for relative physics constraint
2021-06-28 11:44:39 +02:00
Henrique 7515a20d93 Keep compatibility 2021-06-27 20:47:55 -03:00
Henrique 3d49edee71 Add Subtract option to World Vector to Local Space node 2021-06-27 19:13:00 -03:00
Henrique 34b816b4d9 Remove default value 2021-06-27 18:27:16 -03:00
Henrique 13c1e0508d Fix for null parent 2021-06-27 18:26:13 -03:00
Henrique f940e8566e Remove unused quat 2021-06-27 18:21:59 -03:00
Henrique dfad6902af Add Relative Parent option to location nodes 2021-06-27 18:18:04 -03:00
Moritz Brückner 441f42383e Correctly stop live patching after player terminates 2021-06-27 22:35:37 +02:00
Lubos Lenco 616a0e230d
Merge pull request #2239 from QuantumCoderQC/MatParamPerObject
Set material parameter on per object basis
2021-06-26 12:17:40 +02:00
Lubos Lenco 20540ccb11
Merge pull request #2238 from MoritzBrueckner/background-mode
Fix threading and publishing in background mode
2021-06-25 08:57:16 +02:00
QuantumCoderQC 31a2c9c4d3 Modify export of physics constraint 2021-06-24 23:13:29 +02:00
QuantumCoderQC ac48fd0bc9 Implement adding of relative physics constraint 2021-06-24 23:12:51 +02:00
QuantumCoderQC f2cf3bdeda Add new property to set if constraint is relative 2021-06-24 23:12:15 +02:00
QuantumCoderQC 112c00a649 Modify unifroms manager 2021-06-24 21:33:53 +02:00
QuantumCoderQC ee43724b97 Change imports 2021-06-24 21:33:21 +02:00
QuantumCoderQC 5a2f952f89 Add uniforms manager to mesh objects 2021-06-24 21:32:48 +02:00
QuantumCoderQC 936f11ed8e Move uniforms manager back to armory 2021-06-24 18:19:33 +02:00
QuantumCoderQC eab7fcbbe6 update node implementations 2021-06-24 18:13:13 +02:00
QuantumCoderQC 5a591fa15a set default vector and float parameter 2021-06-24 18:13:13 +02:00
QuantumCoderQC 975ec76f38 Set default image file 2021-06-24 18:13:13 +02:00
QuantumCoderQC 340f7e8af4 Pass default image file name when adding uniform 2021-06-24 18:13:13 +02:00
QuantumCoderQC fa44147ee6 Pass default float value when adding uniform 2021-06-24 18:13:13 +02:00
QuantumCoderQC c44e2cf555 Pass default vector value when adding uniform 2021-06-24 18:13:13 +02:00
QuantumCoderQC 15da6ccf58 Upgrade nodes to include object. Add documnetation 2021-06-24 18:13:12 +02:00
QuantumCoderQC 39922bc0f3 move uniforms manager to iron 2021-06-24 18:13:12 +02:00
QuantumCoderQC ea4f88aca8 remove debug trace 2021-06-24 18:13:12 +02:00
QuantumCoderQC 39bd32f9d3 get image from node 2021-06-24 18:13:12 +02:00
QuantumCoderQC e744fd901c create and implement uniforms manager
remove node mapping

Revert "remove node mapping"

This reverts commit e70aa60e120e71236cba885bd7e0e5f1b6acf39d.
2021-06-24 18:13:12 +02:00
QuantumCoderQC dbd348ad5d update node scripts 2021-06-24 18:13:12 +02:00
QuantumCoderQC f542dc00ca update similar nodes 2021-06-24 18:13:12 +02:00
QuantumCoderQC aaa21bc019 implement per object option 2021-06-24 18:13:12 +02:00
QuantumCoderQC a9f430c374 Add per object option 2021-06-24 18:13:12 +02:00
QuantumCoderQC 6cf3299ffe Implement and upgrade set material value parameter node 2021-06-24 18:13:12 +02:00
QuantumCoderQC a588396dea Update set material value param node 2021-06-24 18:13:12 +02:00
Moritz Brückner dc34e48c52 Unregister timers on exit/disabling addon 2021-06-24 17:26:21 +02:00
Moritz Brückner fce97a5ddf Cleanup 2021-06-24 15:03:30 +02:00
Moritz Brückner d18aede964 run_proc: no thread in background mode and call done in main thread 2021-06-24 14:59:32 +02:00
Moritz Brückner 66856e7ecc Build/publish: add poll() function to prevent exception when executing from outside of UI
If there was no exporter, calling `bpy.ops.arm.publish_project()` would result in an exception before. Now the call is simply ignored and a "poll failed" message is emitted instead.
2021-06-23 20:19:08 +02:00
Lubos Lenco ebfbb68bb4
Merge pull request #2235 from knowledgenude/master
Cleanup in ui Ext
2021-06-20 20:53:48 +02:00
Henrique 3c1264378b Cleanup in ui Ext 2021-06-19 13:39:18 -03:00
Lubos Lenco cbcc3e4e04
Merge pull request #2233 from MoritzBrueckner/fix-compilation
Fix compilation of some nodes
2021-06-16 08:10:03 +02:00
Moritz Brückner f45304ea10 Fix compilation of some nodes 2021-06-15 15:24:58 +02:00
Lubos Lenco dd13cc31b7
Merge pull request #2231 from knowledgenude/master
Fix GetBoneFkIkOnly node & add new input nodes
2021-06-14 10:41:51 +02:00
Henrique a5fa3445d9 Add new input nodes 2021-06-13 22:43:13 -03:00
Henrique 1ece052aee Fix GetBoneFkIkOnly node 2021-06-13 21:38:15 -03:00
Lubos Lenco 24d917ae6a
Merge pull request #2228 from MoritzBrueckner/fix-movie-texture
Fix rendering multiple movie textures
2021-06-10 21:12:32 +02:00
Moritz Brückner 3288c3dcf5 MovieTexture: add documentation 2021-06-10 20:28:30 +02:00
Moritz Brückner 251ad8e47e Cache and reuse movietexture render targets with same size 2021-06-10 20:27:23 +02:00
Moritz Brückner b2619828eb Fix rendering multiple movie textures
Fixes https://github.com/armory3d/armory/issues/1562
2021-06-09 23:11:22 +02:00
Lubos Lenco 6c6d7c1419
Merge pull request #2221 from QuantumCoderQC/ExtraLogicNodes
Extra logic nodes
2021-06-09 07:38:28 +02:00
QuantumCoderQC 0e6ba5b0b0 reverse call order 2021-06-07 13:49:12 +02:00
QuantumCoderQC 107dc730f4 Create and implement once per frame node 2021-06-07 13:41:24 +02:00
Lubos Lenco b72e85894a
Merge pull request #2220 from MoritzBrueckner/select-node
Add Select node
2021-06-07 11:03:42 +02:00
Moritz Brückner 20f9f8a5f4 Add Select node
Implements feature requests #2200 and #2201
2021-06-05 20:35:21 +02:00
Lubos Lenco 5eb8fc781f Bump version 2021-06-02 21:18:47 +02:00
Lubos Lenco 70cb5ea421
Merge pull request #2216 from MoritzBrueckner/shader-fixes
Fix Layer Weight node and multiple cycles shaders in one material
2021-05-28 12:06:04 +02:00
Moritz Brückner ccc427c04a Cleanup 2021-05-27 22:57:53 +02:00
Moritz Brückner 6d37095014 Fix usage of layer weight node in shadowmap shaders 2021-05-27 22:56:07 +02:00
Moritz Brückner 7057ec4ba6 Fix mixing multiple cycles shaders in one material 2021-05-27 22:41:27 +02:00
Lubos Lenco 138386f02a
Merge pull request #2213 from MoritzBrueckner/fix-instancing-mobile
Fix instancing on mobile and solid renderpaths
2021-05-26 12:46:52 +02:00
Moritz Brückner bdc2d91c1e Fix instancing on mobile and solid renderpaths
`gl_Position` was set before the instancing code in the vertex shader, this was the same issue as already fixed for desktop renderpaths in https://github.com/armory3d/armory/pull/2141
2021-05-26 12:42:11 +02:00
Lubos Lenco 7b5294121d is_IK_FK_only -> is_ik_fk_only 2021-05-23 22:19:48 +02:00
Lubos Lenco 9330090179
Merge pull request #2206 from QuantumCoderQC/IKfix29_FK
Improve bone IK. Add new nodes for better animation control
2021-05-23 22:15:26 +02:00
Lubos Lenco 88f522c27b
Merge pull request #2210 from MoritzBrueckner/merge-node
Merge node: add execution mode and output for input index
2021-05-23 16:32:27 +02:00
Moritz Brückner 11da953407 Merge node: add update routine 2021-05-22 12:30:38 +02:00
Moritz Brückner 494e2336ac Node replacement: write original traceback to file also in case of update failures 2021-05-22 12:28:57 +02:00
Moritz Brückner 20c6c52ae6 Merge node: add execution mode and output for input index 2021-05-22 00:36:58 +02:00
Moritz Brückner 088bc0f666 Exporter: remove no longer used Blender version checks 2021-05-20 20:38:43 +02:00
QuantumCoderQC a35cab5482 Implement node to set bone animated by FK or IK only 2021-05-20 18:24:32 +02:00
QuantumCoderQC 03baa49ecd Implement node to get bone transform in world space 2021-05-20 18:24:32 +02:00
QuantumCoderQC c53d04374d Implement node to get if controlled by FK or IK 2021-05-20 18:24:32 +02:00
QuantumCoderQC 43e145c3da Add comments to bone IK node 2021-05-20 18:24:32 +02:00
QuantumCoderQC 6ded7e61f4 Improve bone FK node to accept transform in world space 2021-05-20 18:24:32 +02:00
QuantumCoderQC e7c1855b81 Create new node to set if bones are FK IK only 2021-05-20 18:24:32 +02:00
QuantumCoderQC 86316a10bd Create new node to get world transforms of bones 2021-05-20 18:24:32 +02:00
QuantumCoderQC 646d3a74cf Create new node to get if bones are FK IK 2021-05-20 18:24:32 +02:00
QuantumCoderQC 5ed5b8d6a7 Nodes for IK and FK fix
Edit logic node code

fkcommit30_04

Upgrade bone IK node. Add comments
2021-05-20 18:24:31 +02:00
Moritz Brückner 9fbc3d6cd4 Small cleanup 2021-05-19 21:17:57 +02:00
Moritz Brückner 7b2961459c Live patch support for light strength and color 2021-05-19 21:17:38 +02:00
Moritz Brückner 3d46910530 Live patch: don't re-export on trackball rotation (double 'r' key) 2021-05-18 21:34:46 +02:00
Moritz Brückner 68825516c9 Live patch: more robust shader paths 2021-05-18 21:31:02 +02:00
Moritz Brückner 07ffe06c1d Live patch: move to dedicated module and use msgbus 2021-05-18 21:24:45 +02:00
Lubos Lenco 3b72fff76d
Merge pull request #2196 from N8n5h/light-fix-2
Small improvements for the Shadow Map Atlas Blender UI
2021-05-16 12:29:31 +02:00
N8n5h 1945439cd1 Small improvements for the Shadow Map Atlas Blender UI
* Made shadow map atlas sizes enum's values dynamic:
This allows reducing issues related to picking a "wrong" size for the atlases.
* Added a legend below shadow map sizes to have an idea of how much lights can an option fit.
* Separated listing of subdivisions to include point lights.
* Disable cubemap size if single map is enabled to show that cascade size option is only used.
2021-05-14 11:22:11 -03:00
Lubos Lenco 98eeccd71d
Merge pull request #2082 from armory3d/blender2.9
Blender 2.9 LTS support
2021-05-10 11:14:39 +02:00
Lubos Lenco d31303391f
Merge pull request #2185 from MoritzBrueckner/fix-linked-objects-export
Fix double-export of linked objects (#2175)
2021-05-09 15:50:57 +02:00
Moritz Brückner 590afcc573 Fix double-export of linked objects (#2175) 2021-05-08 23:09:45 +02:00
Lubos Lenco 30b2093b94 Move game theme to armory.ui 2021-05-07 17:02:31 +02:00
Lubos Lenco 2f1fe4ef0b Move Canvas and game ui to armory.ui package 2021-05-07 15:24:03 +02:00
Lubos Lenco 57093c34cd
Merge pull request #2184 from MoritzBrueckner/debug-console-panel
[Blender 2.9] Slightly improve debug console panel UI
2021-05-07 10:29:09 +02:00
Moritz Brückner 2c761b2ff6 Slightly improve debug console panel UI 2021-05-06 21:29:59 +02:00
Lubos Lenco 4db37ea1c1
Merge pull request #2177 from QuantumCoderQC/get-object-node-fix
Get object by name node fix
2021-05-02 11:16:12 +02:00
QuantumCoderQC df372e9523 Spelling correction 2021-05-02 01:37:00 +02:00
QuantumCoderQC 5b6875947c New logic node to spawn objects not in current active scene 2021-05-02 01:33:38 +02:00
QuantumCoderQC badc8853b4 Make description more accurate 2021-05-02 01:31:44 +02:00
QuantumCoderQC 1ebe528417 Remove scene port from logic node 2021-05-02 01:30:34 +02:00
QuantumCoderQC c185882db8 Revert commit that creates an object if not in scene.
Returns object only if present in active scene
2021-05-01 22:19:29 +02:00
Lubos Lenco 04909603ec
Merge pull request #2176 from MoritzBrueckner/2.9-version-info
Update Blender version information to 2.93 LTS
2021-05-01 11:15:54 +02:00
Moritz Brückner 22a557162f Update Blender version information to 2.93 LTS 2021-05-01 00:04:25 +02:00
Lubos Lenco bb5ff191b7
Merge pull request #2163 from MoritzBrueckner/fix-attribute-node
Fix export of attribute node if no UV map exists
2021-04-20 09:36:37 +02:00
Moritz Brückner 97b578d0ed Fix export of attribute node if no UV map exists 2021-04-19 22:21:23 +02:00
Lubos Lenco 316eafd286
Merge pull request #2150 from MoritzBrueckner/blender2.9
[Blender 2.9] Resolve merge conflicts
2021-04-03 14:21:41 +02:00
Moritz Brückner f64419dd06 Merge branch 'master' into blender2.9
# Conflicts:
#	blender/arm/material/shader.py
#	blender/arm/props_collision_filter_mask.py
#	blender/arm/props_ui.py
2021-04-03 14:12:54 +02:00
Lubos Lenco c9182cc152
Merge pull request #2149 from MoritzBrueckner/2.9-NishitaSky
[Blender 2.9] Nishita sky model & (ir)radiance support for all world shaders
2021-04-03 10:07:25 +02:00
Moritz Brückner 899411dea4 Cleanup write_probes.py 2021-04-02 14:57:11 +02:00
Moritz Brückner 34f08e6922 Fix irradiance brightness
See write_sky_irradiance() for reference
2021-04-02 01:59:55 +02:00
Moritz Brückner 656b018e5f Render (ir)radiance probes if no other probes are set 2021-04-02 01:59:28 +02:00
Moritz Brückner c5be90d0b0 Cleanup 2021-03-31 20:33:52 +02:00
Moritz Brückner ffcc5fcceb Make clouds work with Nishita sky model 2021-03-31 20:31:31 +02:00
Moritz Brückner 420033c86d Add API to set Nishita density parameters 2021-03-26 20:59:26 +01:00
Moritz Brückner 845d2aff93 Use switch/case for uniform links 2021-03-26 15:39:18 +01:00
Moritz Brückner 8d812548c4 Use 2D LUT for Nishita skies 2021-03-25 23:29:34 +01:00
Moritz Brückner 05c14238f2 shader.py: add API to set texture params 2021-03-25 23:03:08 +01:00
Lubos Lenco fb56d85d02
Merge pull request #2138 from Naxela/blender2.9
[Blender 2.9] Fix material translucency in Blender 2.9+
2021-03-23 12:30:34 +01:00
Alexander Kleemann eb6d23fab3 Fix material translucency in Blender 2.9+
The extra input node in the principled is now taken into consideration
2021-03-22 20:26:01 +01:00
Lubos Lenco 451e3484f0
Merge pull request #2133 from Naxela/blender2.9
[Blender 2.9] Ready lightmapper for the transition to the next Blender LTS
2021-03-20 09:58:04 +01:00
Alexander Kleemann 5fe816d16a Add in-menu option for OpenCV installation 2021-03-18 19:25:02 +01:00
Alexander Kleemann ef8fb21536 Update lightmapper to Blender 2.9+
Finalized update to support Blender 2.9+ as well as new features, fixes and more stability
2021-03-18 18:49:30 +01:00
Moritz Brückner 5f55b00710 Begin with Nishita LUT implementation for better performance 2021-03-11 23:16:44 +01:00
Moritz Brückner 742b9ce1e1 Nishita sky: add support for ozone density 2021-02-22 18:52:56 +01:00
Moritz Brückner 92554876f1 Fix nishita sky altitude
The scale was changed in recent Blender builds
2021-02-21 01:12:15 +01:00
Moritz Brückner 702436e2a1 Add artistic option for darkening clouds at night 2021-02-13 19:01:14 +01:00
Moritz Brückner 28011bcc00 Nishita sky: add sun disk drawing 2021-02-13 18:23:37 +01:00
Lubos Lenco cbb8ee4bae
Merge pull request #2099 from MoritzBrueckner/2.9-LodOperators
Fix lod operator polling and add some bl_options
2021-02-01 09:55:22 +01:00
Moritz Brückner f2c16097d4 Fix lod operator polling and add some bl_options 2021-01-30 20:21:31 +01:00
Lubos Lenco d0e92b927b
Merge pull request #2097 from armory3d/2.9-AttributeNode
[Blender 2.9] Update attribute node
2021-01-30 19:57:17 +01:00
Moritz Brückner 121d449c35 Blender 2.9: Cycles attribute node - support object/custom properties 2021-01-30 14:19:46 +01:00
Moritz Brückner 75bb88831c Blender 2.9: Cycles attribute node - support alpha output and new attribute_type prop 2021-01-30 14:19:46 +01:00
Lubos Lenco 0fdb516083
Merge pull request #2093 from MoritzBrueckner/2.9-UI
[Blender 2.9] Various UI improvements & redesigns
2021-01-25 17:24:19 +01:00
Moritz Brückner a1bbd76de7 Fix: Remove unused/non-existing armory icon 2021-01-25 16:51:28 +01:00
Moritz Brückner e3f992b1f3 Whitespace cleanup 2021-01-25 16:48:03 +01:00
Moritz Brückner 05307817ee Fix grammar in warnings report 2021-01-25 16:47:51 +01:00
Moritz Brückner d55f889a84 Another small compositor panel UI improvement 2021-01-25 16:45:30 +01:00
Moritz Brückner 1d79708b22 Fix trait type backward compatibility with pre-Blender2.9 files 2021-01-25 16:23:03 +01:00
Moritz Brückner ba62ba0285 Blender 2.9: Fix/Improve collision filter mask UI 2021-01-25 14:01:53 +01:00
Moritz Brückner d7e70c4c0a Blender 2.9: Improve project flags panel UI 2021-01-25 13:58:47 +01:00
Moritz Brückner 6ae76bfdf6 Blender 2.9: Improve exporter panel UI 2021-01-25 13:53:28 +01:00
Moritz Brückner 6b6dc6264f Blender 2.9: Improve exporter settings UI 2021-01-24 20:42:18 +01:00
Moritz Brückner 288ead64dc Nishita sky: implement air and dust density 2021-01-21 21:14:05 +01:00
Moritz Brückner 396e60574a Optimize Nishita sky shader 2021-01-21 20:36:03 +01:00
Moritz Brückner 22d3530863 Blender 2.9: Add Nishita sky model implementation 2021-01-21 16:12:32 +01:00
Moritz Brückner 562d39c203 Blender 2.9: Improve Armory player panel UI 2021-01-17 20:24:43 +01:00
Moritz Brückner ffd3d6e824 Show is_object property when Add Trait is not invoked from the UI 2021-01-17 16:54:08 +01:00
Moritz Brückner 7b55f3d8f5 Blender 2.9: Improve Add Trait operator UI 2021-01-17 16:53:17 +01:00
Moritz Brückner ee1b55184c Move icon code into module
This, combined with lazy loading, has the advantage of using icons in property definitions before the actual registration code runs
2021-01-15 19:26:31 +01:00
Moritz Brückner fa7f58e4dd Ensure that only logic node trees show up as node traits 2021-01-14 22:46:22 +01:00
Moritz Brückner 04fdcc5500 Cleanup 2021-01-14 22:28:58 +01:00
Moritz Brückner 820de42e83 Blender 2.9: Fix lod list layout 2021-01-14 22:17:42 +01:00
Moritz Brückner fb88361c5b Blender 2.9: Simplify and improve trait panel UI 2021-01-14 22:14:50 +01:00
Moritz Brückner b7903dbef1 Change canvas icon according to the canvas node category 2021-01-14 22:14:10 +01:00
Moritz Brückner 40efd58214 Blender 2.9: Improve trait list UI and fix checkbox position 2021-01-14 21:24:42 +01:00
Moritz Brückner b4f0df6367 Blender 2.9: Redesign renderpath compositor panel UI 2021-01-14 21:21:01 +01:00
Moritz Brückner 133777f7e5 Blender 2.9: Improve renderpath postprocess panel UI 2021-01-14 21:18:46 +01:00
Moritz Brückner 406d48eb7c Blender 2.9: Improve renderpath world panel UI 2021-01-14 21:13:02 +01:00
Moritz Brückner 4c0f0f4161 Blender 2.9: slightly improve renderpath "Renderer" panel UI 2021-01-14 21:06:37 +01:00
Moritz Brückner a98559ea7f Blender 2.9: Improve material blending panel UI 2021-01-14 20:57:44 +01:00
Moritz Brückner 1b9f010c57 Blender 2.9: Improve project window panel UI 2021-01-14 20:56:04 +01:00
Lubos Lenco 9bab721f5f
Merge pull request #2086 from MoritzBrueckner/2.9-Search-Fixes
[Blender 2.9] Search menu fixes
2021-01-11 21:57:11 +01:00
Moritz Brückner 4920098831 Blender 2.9: Fix another exception when using the search menu 2021-01-11 19:57:29 +01:00
Moritz Brückner 4f25af45ba Cleanup 2021-01-11 19:56:40 +01:00
Moritz Brückner c69774402c Blender 2.9: Fix tilesheet operator exceptions when using the search menu 2021-01-11 19:51:15 +01:00
Lubos Lenco 833b513969
Merge pull request #2084 from QuantumCoderQC/29RBFix
Blender 2.9 Fix Exporter and conversions for Physics World
2021-01-07 11:49:58 +01:00
Lubos Lenco ad12af6933
Merge pull request #2083 from MoritzBrueckner/2.9-Operators
Blender 2.9: Update operator options
2021-01-07 11:49:15 +01:00
QuantumCoderQC 80ea09671c Fix Exporter and conversions for Physics World in Blender 2.9.X 2021-01-06 20:26:43 +01:00
Moritz Brückner c5e9522442 Blender 2.9: Update operator options 2021-01-06 17:23:21 +01:00
Lubos Lenco bf7592ae32
Merge pull request #2081 from MoritzBrueckner/2.9-PrincipledBSDF
[Blender 2.9] Principled BSDF: update input socket indices
2021-01-05 13:12:30 +01:00
Moritz Brückner cab20d0a64 Principled BSDF: update input socket indices to Blender 2.9 2021-01-04 19:34:42 +01:00
Lubos Lenco 5838401cd9
Merge pull request #2077 from MoritzBrueckner/2.9-UI-ObjectPanel
[Blender 2.9] Object panel UI
2021-01-01 12:58:31 +01:00
Moritz Brückner 14bca0ec80 Shorten too long node trait operator labels 2020-12-30 17:57:23 +01:00
Moritz Brückner 4862054bcf Reorder trait type selection 2020-12-30 17:56:58 +01:00
Moritz Brückner 52cee7f0ce Update "Armory Traits" object panel to Blender 2.9 layouts 2020-12-30 17:56:34 +01:00
Moritz Brückner 257f295b27 Update "Armory Lod" object panel to Blender 2.9 layouts 2020-12-30 17:54:44 +01:00
Moritz Brückner a647263d1a Update "Armory Proxy" object panel to Blender 2.9 layouts 2020-12-30 17:53:35 +01:00
Moritz Brückner 6a6d383970 Update "Armory Props" object panel to Blender 2.9 layouts 2020-12-30 17:52:27 +01:00
573 changed files with 15369 additions and 5071 deletions

View file

@ -4,7 +4,9 @@
uniform sampler2D tex;
#ifdef _CPostprocess
uniform vec3 PPComp10;
#endif
in vec2 texCoord;
out vec4 fragColor;

View file

@ -8,7 +8,8 @@
"links": [
{
"name": "PPComp10",
"link": "_PPComp10"
"link": "_PPComp10",
"ifdef": ["_CPostprocess"]
}
],
"texture_params": [],

View file

@ -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

View file

@ -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": [],

View file

@ -3,7 +3,10 @@
#include "compiled.inc"
uniform sampler2D tex;
#ifdef _CPostprocess
uniform vec3 PPComp13;
#endif
in vec2 texCoord;
out vec4 fragColor;

View file

@ -9,7 +9,8 @@
"links": [
{
"name": "PPComp13",
"link": "_PPComp13"
"link": "_PPComp13",
"ifdef": ["_CPostprocess"]
}
],
"texture_params": [],

View file

@ -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);

View file

@ -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

View file

@ -28,11 +28,13 @@
},
{
"name": "PPComp11",
"link": "_PPComp11"
"link": "_PPComp11",
"ifdef": ["_CPostprocess"]
},
{
"name": "PPComp12",
"link": "_PPComp12"
"link": "_PPComp12",
"ifdef": ["_CPostprocess"]
}
],
"texture_params": [],

View file

@ -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;

View file

@ -24,11 +24,13 @@
},
{
"name": "PPComp9",
"link": "_PPComp9"
"link": "_PPComp9",
"ifdef": ["_CPostprocess"]
},
{
"name": "PPComp10",
"link": "_PPComp10"
"link": "_PPComp10",
"ifdef": ["_CPostprocess"]
}
],
"texture_params": [],

View file

@ -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

View 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);
}

155
Shaders/std/sky.glsl Normal file
View file

@ -0,0 +1,155 @@
/* Various sky functions
* =====================
*
* Nishita model is based on https://github.com/wwwtyro/glsl-atmosphere (Unlicense License)
*
* Changes to the original implementation:
* - r and pSun parameters of nishita_atmosphere() are already normalized
* - Some original parameters of nishita_atmosphere() are replaced with pre-defined values
* - Implemented air, dust and ozone density node parameters (see Blender source)
* - Replaced the inner integral calculation with a LUT lookup
*
* Reference for the sun's limb darkening and ozone calculations:
* [Hill] Sebastien Hillaire. Physically Based Sky, Atmosphere and Cloud Rendering in Frostbite
* (https://media.contentapi.ea.com/content/dam/eacom/frostbite/files/s2016-pbs-frostbite-sky-clouds-new.pdf)
*
* Cycles code used for reference: blender/intern/sky/source/sky_nishita.cpp
* (https://github.com/blender/blender/blob/4429b4b77ef6754739a3c2b4fabd0537999e9bdc/intern/sky/source/sky_nishita.cpp)
*/
#ifndef _SKY_GLSL_
#define _SKY_GLSL_
#include "std/math.glsl"
uniform sampler2D nishitaLUT;
uniform vec2 nishitaDensity;
#ifndef PI
#define PI 3.141592
#endif
#ifndef HALF_PI
#define HALF_PI 1.570796
#endif
#define nishita_iSteps 16
// These values are taken from Cycles code if they
// exist there, otherwise they are taken from the example
// in the glsl-atmosphere repo
#define nishita_sun_intensity 22.0
#define nishita_atmo_radius 6420e3
#define nishita_rayleigh_scale 8e3
#define nishita_rayleigh_coeff vec3(5.5e-6, 13.0e-6, 22.4e-6)
#define nishita_mie_scale 1.2e3
#define nishita_mie_coeff 2e-5
#define nishita_mie_dir 0.76 // Aerosols anisotropy ("direction")
#define nishita_mie_dir_sq 0.5776 // Squared aerosols anisotropy
// Values from [Hill: 60]
#define sun_limb_darkening_col vec3(0.397, 0.503, 0.652)
vec3 nishita_lookupLUT(const float height, const float sunTheta) {
vec2 coords = vec2(
sqrt(height * (1 / nishita_atmo_radius)),
0.5 + 0.5 * sign(sunTheta - HALF_PI) * sqrt(abs(sunTheta * (1 / HALF_PI) - 1))
);
return textureLod(nishitaLUT, coords, 0.0).rgb;
}
/* See raySphereIntersection() in armory/Sources/renderpath/Nishita.hx */
vec2 nishita_rsi(const vec3 r0, const vec3 rd, const float sr) {
float a = dot(rd, rd);
float b = 2.0 * dot(rd, r0);
float c = dot(r0, r0) - (sr * sr);
float d = (b*b) - 4.0*a*c;
// If d < 0.0 the ray does not intersect the sphere
return (d < 0.0) ? vec2(1e5,-1e5) : vec2((-b - sqrt(d))/(2.0*a), (-b + sqrt(d))/(2.0*a));
}
/*
* r: normalized ray direction
* r0: ray origin
* pSun: normalized sun direction
* rPlanet: planet radius
*/
vec3 nishita_atmosphere(const vec3 r, const vec3 r0, const vec3 pSun, const float rPlanet) {
// Calculate the step size of the primary ray
vec2 p = nishita_rsi(r0, r, nishita_atmo_radius);
if (p.x > p.y) return vec3(0.0);
p.y = min(p.y, nishita_rsi(r0, r, rPlanet).x);
float iStepSize = (p.y - p.x) / float(nishita_iSteps);
// Primary ray time
float iTime = 0.0;
// Accumulators for Rayleigh and Mie scattering.
vec3 totalRlh = vec3(0,0,0);
vec3 totalMie = vec3(0,0,0);
// Optical depth accumulators for the primary ray
float iOdRlh = 0.0;
float iOdMie = 0.0;
// Calculate the Rayleigh and Mie phases
float mu = dot(r, pSun);
float mumu = mu * mu;
float pRlh = 3.0 / (16.0 * PI) * (1.0 + mumu);
float pMie = 3.0 / (8.0 * PI) * ((1.0 - nishita_mie_dir_sq) * (mumu + 1.0)) / (pow(1.0 + nishita_mie_dir_sq - 2.0 * mu * nishita_mie_dir, 1.5) * (2.0 + nishita_mie_dir_sq));
// Sample the primary ray
for (int i = 0; i < nishita_iSteps; i++) {
// Calculate the primary ray sample position and height
vec3 iPos = r0 + r * (iTime + iStepSize * 0.5);
float iHeight = length(iPos) - rPlanet;
// Calculate the optical depth of the Rayleigh and Mie scattering for this step
float odStepRlh = exp(-iHeight / nishita_rayleigh_scale) * nishitaDensity.x * iStepSize;
float odStepMie = exp(-iHeight / nishita_mie_scale) * nishitaDensity.y * iStepSize;
// Accumulate optical depth
iOdRlh += odStepRlh;
iOdMie += odStepMie;
// 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 = safe_acos(dot(normalize(iPos), normalize(pSun)));
vec3 jAttn = nishita_lookupLUT(iHeight, sunTheta);
// Calculate attenuation
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;
totalMie += odStepMie * attn;
iTime += iStepSize;
}
return nishita_sun_intensity * (pRlh * nishita_rayleigh_coeff * totalRlh + pMie * nishita_mie_coeff * totalMie);
}
vec3 sun_disk(const vec3 n, const vec3 light_dir, const float disk_size, const float intensity) {
// Normalized SDF
float dist = distance(n, light_dir) / disk_size;
// Darken the edges of the sun
// [Hill: 28, 60] (according to [Nec96])
float invDist = 1.0 - dist;
float mu = sqrt(invDist * invDist);
vec3 limb_darkening = 1.0 - (1.0 - pow(vec3(mu), sun_limb_darkening_col));
return 1 + (1.0 - step(1.0, dist)) * nishita_sun_intensity * intensity * limb_darkening;
}
#endif

View file

@ -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
View file

@ -0,0 +1 @@
import armory.system.Assert.*;

View file

@ -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);
}
}

View file

@ -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);

View file

@ -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);

View file

@ -1,5 +1,7 @@
package armory.logicnode;
import iron.math.Quat;
import iron.math.Vec4;
import iron.object.Object;
import iron.object.BoneAnimation;
import iron.math.Mat4;
@ -26,19 +28,28 @@ class BoneFKNode extends LogicNode {
var anim = object.animation != null ? cast(object.animation, BoneAnimation) : null;
if (anim == null) anim = object.getParentArmature(object.name);
// Manipulating bone in world space
// Get bone in armature
var bone = anim.getBone(boneName);
m = anim.getBoneMat(bone);
w = anim.getAbsMat(bone);
function moveBone() {
m.setFrom(w);
m.multmat(transform);
iw.getInverse(w);
m.multmat(iw);
var t2 = Mat4.identity();
var loc= new Vec4();
var rot = new Quat();
var scl = new Vec4();
// anim.removeUpdate(moveBone);
// notified = false;
//Set scale to Armature scale. Bone scaling not yet implemented
t2.setFrom(transform);
t2.decompose(loc, rot, scl);
scl = object.transform.world.getScale();
t2.compose(loc, rot, scl);
//Set the bone local transform from world transform
anim.setBoneMatFromWorldMat(t2, bone);
//Remove this method from animation loop after FK
anim.removeUpdate(moveBone);
notified = false;
}
if (!notified) {

View file

@ -7,6 +7,13 @@ import iron.math.Vec4;
class BoneIKNode extends LogicNode {
var goal: Vec4;
var pole: Vec4;
var poleEnabled: Bool;
var chainLength: Int;
var maxIterartions: Int;
var precision: Float;
var rollAngle: Float;
var notified = false;
public function new(tree: LogicTree) {
@ -19,6 +26,12 @@ class BoneIKNode extends LogicNode {
var object: Object = inputs[1].get();
var boneName: String = inputs[2].get();
goal = inputs[3].get();
poleEnabled = inputs[4].get();
pole = inputs[5].get();
chainLength = inputs[6].get();
maxIterartions = inputs[7].get();
precision = inputs[8].get();
rollAngle = inputs[9].get();
if (object == null || goal == null) return;
var anim = object.animation != null ? cast(object.animation, BoneAnimation) : null;
@ -26,11 +39,15 @@ class BoneIKNode extends LogicNode {
var bone = anim.getBone(boneName);
function solveBone() {
anim.solveIK(bone, goal);
if(! poleEnabled) pole = null;
// anim.removeUpdate(solveBone);
// notified = false;
function solveBone() {
//Solve IK
anim.solveIK(bone, goal, precision, maxIterartions, chainLength, pole, rollAngle);
//Remove this method from animation loop after IK
anim.removeUpdate(solveBone);
notified = false;
}
if (!notified) {

View file

@ -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);

View 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
}

View file

@ -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()) {

View file

@ -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()) {

View 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
}
}

View file

@ -0,0 +1,31 @@
package armory.logicnode;
import iron.object.Object;
import iron.object.BoneAnimation;
class GetBoneFkIkOnlyNode extends LogicNode {
public function new(tree: LogicTree) {
super(tree);
}
override function get(from: Int): Bool {
#if arm_skin
var object: Object = inputs[0].get();
var boneName: String = inputs[1].get();
if (object == null) return null;
var anim = object.animation != null ? cast(object.animation, BoneAnimation) : null;
if (anim == null) anim = object.getParentArmature(object.name);
// Get bone in armature
var bone = anim.getBone(boneName);
//Get bone transform in world coordinates
return bone.is_ik_fk_only;
#end
}
}

View file

@ -0,0 +1,30 @@
package armory.logicnode;
import iron.object.Object;
import iron.object.BoneAnimation;
import iron.math.Mat4;
class GetBoneTransformNode extends LogicNode {
public function new(tree: LogicTree) {
super(tree);
}
override function get(from: Int): Mat4 {
#if arm_skin
var object: Object = inputs[0].get();
var boneName: String = inputs[1].get();
if (object == null) return null;
var anim = object.animation != null ? cast(object.animation, BoneAnimation) : null;
if (anim == null) anim = object.getParentArmature(object.name);
// Get bone in armature
var bone = anim.getBone(boneName);
return anim.getAbsWorldMat(bone);
#end
}
}

View 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;
}
}

View 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
}

View 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
}

View 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;
}
}

View 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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View 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;
}
}

View 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;
}
}

View file

@ -14,36 +14,7 @@ class GetObjectNode extends LogicNode {
override function get(from: Int): Dynamic {
var objectName: String = inputs[0].get();
if (property0 == null || property0 == iron.Scene.active.raw.name) {
return iron.Scene.active.getChild(objectName);
}
#if arm_json
property0 += ".json";
#elseif arm_compress
property0 += ".lz4";
#end
var outObj: Null<Object> = null;
// Create the object in the active scene if it is from an inactive scene
iron.data.Data.getSceneRaw(property0, (rawScene: TSceneFormat) -> {
var objData: Null<TObj> = null;
for (o in rawScene.objects) {
if (o.name == objectName) {
objData = o;
break;
}
}
if (objData == null) return;
iron.Scene.active.createObject(objData, rawScene, null, null, (newObj: Object) -> {
outObj = newObj;
});
});
return outObj;
return iron.Scene.active.getChild(objectName);
}
}

View file

@ -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;
}
}

View file

@ -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

View 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;
}
}

View file

@ -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

View file

@ -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);
}
}

View file

@ -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() {}

View file

@ -37,6 +37,6 @@ class LookAtNode extends LogicNode {
v2.setFrom(vto).sub(vfrom).normalize();
q.fromTo(v1, v2);
return q.getEuler();
return q;
}
}

View file

@ -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;
}
}
}

View file

@ -2,11 +2,31 @@ package armory.logicnode;
class MergeNode extends LogicNode {
/** Execution mode. **/
public var property0: String;
var lastInputIndex = -1;
public function new(tree: LogicTree) {
super(tree);
tree.notifyOnLateUpdate(lateUpdate);
}
override function run(from: Int) {
// Check if there already were executions on the same frame
if (lastInputIndex != -1 && property0 == "once_per_frame") {
return;
}
lastInputIndex = from;
runOutput(0);
}
override function get(from: Int): Dynamic {
return lastInputIndex;
}
function lateUpdate() {
lastInputIndex = -1;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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 {

View 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;
}
}

View 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;
}
}

View file

@ -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();

View file

@ -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;
}
}

View file

@ -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;
}

View file

@ -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;
}
}

View file

@ -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;
}

View file

@ -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;
}
}

View 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);
}
}
}

View file

@ -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();

View file

@ -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

View 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;
}
}

View 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;
}
}

View 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;
}
}

View 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;
}
}

View file

@ -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;
}
}

View file

@ -0,0 +1,35 @@
package armory.logicnode;
import iron.math.Quat;
import iron.math.Vec4;
import iron.object.Object;
import iron.object.BoneAnimation;
class SetBoneFkIkOnlyNode extends LogicNode {
public function new(tree: LogicTree) {
super(tree);
}
override function run(from: Int) {
#if arm_skin
var object: Object = inputs[1].get();
var boneName: String = inputs[2].get();
var fk_ik_only: Bool = inputs[3].get();
if (object == null) return;
var anim = object.animation != null ? cast(object.animation, BoneAnimation) : null;
if (anim == null) anim = object.getParentArmature(object.name);
// Get bone in armature
var bone = anim.getBone(boneName);
//Set bone animated by FK or IK only
bone.is_ik_fk_only = fk_ik_only;
runOutput(0);
#end
}
}

View 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
}

View 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
}

View 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);
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View 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);
}
}

View file

@ -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);

View file

@ -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) {

View file

@ -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();

View file

@ -0,0 +1,72 @@
package armory.logicnode;
import iron.data.SceneFormat.TSceneFormat;
import iron.data.Data;
import iron.object.Object;
import iron.math.Mat4;
import armory.trait.physics.RigidBody;
class SpawnObjectByNameNode extends LogicNode {
var object: Object;
var matrices: Array<Mat4> = [];
/** Scene from which to take the object **/
public var property0: Null<String>;
public function new(tree: LogicTree) {
super(tree);
}
override function run(from: Int) {
var objectName = inputs[1].get();
if (objectName == null) return;
#if arm_json
property0 += ".json";
#elseif arm_compress
property0 += ".lz4";
#end
var m: Mat4 = inputs[2].get();
matrices.push(m != null ? m.clone() : null);
var spawnChildren: Bool = inputs.length > 3 ? inputs[3].get() : true; // TODO
Data.getSceneRaw(property0, (rawScene: TSceneFormat) -> {
//Check if object with given name present in the specified scene
var objPresent: Bool = false;
for (o in rawScene.objects) {
if (o.name == objectName) {
objPresent = true;
break;
}
}
if (! objPresent) return;
//Spawn object if present
iron.Scene.active.spawnObject(objectName, null, function(o: Object) {
object = o;
var matrix = matrices.pop(); // Async spawn in a loop, order is non-stable
if (matrix != null) {
object.transform.setMatrix(matrix);
#if arm_physics
var rigidBody = object.getTrait(RigidBody);
if (rigidBody != null) {
object.transform.buildMatrix();
rigidBody.syncTransform();
}
#end
}
object.visible = true;
runOutput(0);
}, spawnChildren, rawScene);
});
}
override function get(from: Int): Dynamic {
return object;
}
}

View file

@ -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;
}
}

View 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);
}
}

View 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);
}
}

View 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);
}
}

View file

@ -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;
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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());

View file

@ -72,4 +72,13 @@ class Helper {
if (value <= leftMin) return rightMin;
return map(value, leftMin, leftMax, rightMin, rightMax);
}
/**
Return the sign of the given value represented as `1.0` (positive value)
or `-1.0` (negative value). The sign of `0` is `0`.
**/
public static inline function sign(value: Float): Float {
if (value == 0) return 0;
return (value < 0) ? -1.0 : 1.0;
}
}

View file

@ -11,176 +11,212 @@ class Uniforms {
public static function register() {
iron.object.Uniforms.externalTextureLinks = [textureLink];
iron.object.Uniforms.externalVec2Links = [];
iron.object.Uniforms.externalVec2Links = [vec2Link];
iron.object.Uniforms.externalVec3Links = [vec3Link];
iron.object.Uniforms.externalVec4Links = [];
iron.object.Uniforms.externalFloatLinks = [floatLink];
iron.object.Uniforms.externalIntLinks = [];
}
public static function textureLink(object: Object, mat: MaterialData, link: String): kha.Image {
#if arm_ltc
if (link == "_ltcMat") {
if (armory.data.ConstData.ltcMatTex == null) armory.data.ConstData.initLTC();
return armory.data.ConstData.ltcMatTex;
public static function textureLink(object: Object, mat: MaterialData, link: String): Null<kha.Image> {
switch (link) {
case "_nishitaLUT": {
if (armory.renderpath.Nishita.data == null) armory.renderpath.Nishita.recompute(Scene.active.world);
return armory.renderpath.Nishita.data.lut;
}
#if arm_ltc
case "_ltcMat": {
if (armory.data.ConstData.ltcMatTex == null) armory.data.ConstData.initLTC();
return armory.data.ConstData.ltcMatTex;
}
case "_ltcMag": {
if (armory.data.ConstData.ltcMagTex == null) armory.data.ConstData.initLTC();
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
}
else if (link == "_ltcMag") {
if (armory.data.ConstData.ltcMagTex == null) armory.data.ConstData.initLTC();
return armory.data.ConstData.ltcMagTex;
}
#end
var target = iron.RenderPath.active.renderTargets.get(link.endsWith("_depth") ? link.substr(0, link.length - 6) : link);
return target != null ? target.image : null;
}
public static function vec3Link(object: Object, mat: MaterialData, link: String): iron.math.Vec4 {
public static function vec3Link(object: Object, mat: MaterialData, link: String): Null<iron.math.Vec4> {
var v: Vec4 = null;
#if arm_hosek
if (link == "_hosekA") {
if (armory.renderpath.HosekWilkie.data == null) {
armory.renderpath.HosekWilkie.recompute(Scene.active.world);
switch (link) {
#if arm_hosek
case "_hosekA": {
if (armory.renderpath.HosekWilkie.data == null) {
armory.renderpath.HosekWilkie.recompute(Scene.active.world);
}
if (armory.renderpath.HosekWilkie.data != null) {
v = iron.object.Uniforms.helpVec;
v.x = armory.renderpath.HosekWilkie.data.A.x;
v.y = armory.renderpath.HosekWilkie.data.A.y;
v.z = armory.renderpath.HosekWilkie.data.A.z;
}
}
if (armory.renderpath.HosekWilkie.data != null) {
case "_hosekB": {
if (armory.renderpath.HosekWilkie.data == null) {
armory.renderpath.HosekWilkie.recompute(Scene.active.world);
}
if (armory.renderpath.HosekWilkie.data != null) {
v = iron.object.Uniforms.helpVec;
v.x = armory.renderpath.HosekWilkie.data.B.x;
v.y = armory.renderpath.HosekWilkie.data.B.y;
v.z = armory.renderpath.HosekWilkie.data.B.z;
}
}
case "_hosekC": {
if (armory.renderpath.HosekWilkie.data == null) {
armory.renderpath.HosekWilkie.recompute(Scene.active.world);
}
if (armory.renderpath.HosekWilkie.data != null) {
v = iron.object.Uniforms.helpVec;
v.x = armory.renderpath.HosekWilkie.data.C.x;
v.y = armory.renderpath.HosekWilkie.data.C.y;
v.z = armory.renderpath.HosekWilkie.data.C.z;
}
}
case "_hosekD": {
if (armory.renderpath.HosekWilkie.data == null) {
armory.renderpath.HosekWilkie.recompute(Scene.active.world);
}
if (armory.renderpath.HosekWilkie.data != null) {
v = iron.object.Uniforms.helpVec;
v.x = armory.renderpath.HosekWilkie.data.D.x;
v.y = armory.renderpath.HosekWilkie.data.D.y;
v.z = armory.renderpath.HosekWilkie.data.D.z;
}
}
case "_hosekE": {
if (armory.renderpath.HosekWilkie.data == null) {
armory.renderpath.HosekWilkie.recompute(Scene.active.world);
}
if (armory.renderpath.HosekWilkie.data != null) {
v = iron.object.Uniforms.helpVec;
v.x = armory.renderpath.HosekWilkie.data.E.x;
v.y = armory.renderpath.HosekWilkie.data.E.y;
v.z = armory.renderpath.HosekWilkie.data.E.z;
}
}
case "_hosekF": {
if (armory.renderpath.HosekWilkie.data == null) {
armory.renderpath.HosekWilkie.recompute(Scene.active.world);
}
if (armory.renderpath.HosekWilkie.data != null) {
v = iron.object.Uniforms.helpVec;
v.x = armory.renderpath.HosekWilkie.data.F.x;
v.y = armory.renderpath.HosekWilkie.data.F.y;
v.z = armory.renderpath.HosekWilkie.data.F.z;
}
}
case "_hosekG": {
if (armory.renderpath.HosekWilkie.data == null) {
armory.renderpath.HosekWilkie.recompute(Scene.active.world);
}
if (armory.renderpath.HosekWilkie.data != null) {
v = iron.object.Uniforms.helpVec;
v.x = armory.renderpath.HosekWilkie.data.G.x;
v.y = armory.renderpath.HosekWilkie.data.G.y;
v.z = armory.renderpath.HosekWilkie.data.G.z;
}
}
case "_hosekH": {
if (armory.renderpath.HosekWilkie.data == null) {
armory.renderpath.HosekWilkie.recompute(Scene.active.world);
}
if (armory.renderpath.HosekWilkie.data != null) {
v = iron.object.Uniforms.helpVec;
v.x = armory.renderpath.HosekWilkie.data.H.x;
v.y = armory.renderpath.HosekWilkie.data.H.y;
v.z = armory.renderpath.HosekWilkie.data.H.z;
}
}
case "_hosekI": {
if (armory.renderpath.HosekWilkie.data == null) {
armory.renderpath.HosekWilkie.recompute(Scene.active.world);
}
if (armory.renderpath.HosekWilkie.data != null) {
v = iron.object.Uniforms.helpVec;
v.x = armory.renderpath.HosekWilkie.data.I.x;
v.y = armory.renderpath.HosekWilkie.data.I.y;
v.z = armory.renderpath.HosekWilkie.data.I.z;
}
}
case "_hosekZ": {
if (armory.renderpath.HosekWilkie.data == null) {
armory.renderpath.HosekWilkie.recompute(Scene.active.world);
}
if (armory.renderpath.HosekWilkie.data != null) {
v = iron.object.Uniforms.helpVec;
v.x = armory.renderpath.HosekWilkie.data.Z.x;
v.y = armory.renderpath.HosekWilkie.data.Z.y;
v.z = armory.renderpath.HosekWilkie.data.Z.z;
}
}
#end
#if rp_voxelao
case "_cameraPositionSnap": {
v = iron.object.Uniforms.helpVec;
v.x = armory.renderpath.HosekWilkie.data.A.x;
v.y = armory.renderpath.HosekWilkie.data.A.y;
v.z = armory.renderpath.HosekWilkie.data.A.z;
var camera = iron.Scene.active.camera;
v.set(camera.transform.worldx(), camera.transform.worldy(), camera.transform.worldz());
var l = camera.lookWorld();
var e = Main.voxelgiHalfExtents;
v.x += l.x * e * 0.9;
v.y += l.y * e * 0.9;
var f = Main.voxelgiVoxelSize * 8; // Snaps to 3 mip-maps range
v.set(Math.floor(v.x / f) * f, Math.floor(v.y / f) * f, Math.floor(v.z / f) * f);
}
#end
}
return v;
}
public static function vec2Link(object: Object, mat: MaterialData, link: String): Null<iron.math.Vec4> {
var v: Vec4 = null;
switch (link) {
case "_nishitaDensity": {
var w = Scene.active.world;
if (w != null) {
v = iron.object.Uniforms.helpVec;
// We only need Rayleigh and Mie density in the sky shader -> Vec2
v.x = w.raw.nishita_density[0];
v.y = w.raw.nishita_density[1];
}
}
}
else if (link == "_hosekB") {
if (armory.renderpath.HosekWilkie.data == null) {
armory.renderpath.HosekWilkie.recompute(Scene.active.world);
}
if (armory.renderpath.HosekWilkie.data != null) {
v = iron.object.Uniforms.helpVec;
v.x = armory.renderpath.HosekWilkie.data.B.x;
v.y = armory.renderpath.HosekWilkie.data.B.y;
v.z = armory.renderpath.HosekWilkie.data.B.z;
}
}
else if (link == "_hosekC") {
if (armory.renderpath.HosekWilkie.data == null) {
armory.renderpath.HosekWilkie.recompute(Scene.active.world);
}
if (armory.renderpath.HosekWilkie.data != null) {
v = iron.object.Uniforms.helpVec;
v.x = armory.renderpath.HosekWilkie.data.C.x;
v.y = armory.renderpath.HosekWilkie.data.C.y;
v.z = armory.renderpath.HosekWilkie.data.C.z;
}
}
else if (link == "_hosekD") {
if (armory.renderpath.HosekWilkie.data == null) {
armory.renderpath.HosekWilkie.recompute(Scene.active.world);
}
if (armory.renderpath.HosekWilkie.data != null) {
v = iron.object.Uniforms.helpVec;
v.x = armory.renderpath.HosekWilkie.data.D.x;
v.y = armory.renderpath.HosekWilkie.data.D.y;
v.z = armory.renderpath.HosekWilkie.data.D.z;
}
}
else if (link == "_hosekE") {
if (armory.renderpath.HosekWilkie.data == null) {
armory.renderpath.HosekWilkie.recompute(Scene.active.world);
}
if (armory.renderpath.HosekWilkie.data != null) {
v = iron.object.Uniforms.helpVec;
v.x = armory.renderpath.HosekWilkie.data.E.x;
v.y = armory.renderpath.HosekWilkie.data.E.y;
v.z = armory.renderpath.HosekWilkie.data.E.z;
}
}
else if (link == "_hosekF") {
if (armory.renderpath.HosekWilkie.data == null) {
armory.renderpath.HosekWilkie.recompute(Scene.active.world);
}
if (armory.renderpath.HosekWilkie.data != null) {
v = iron.object.Uniforms.helpVec;
v.x = armory.renderpath.HosekWilkie.data.F.x;
v.y = armory.renderpath.HosekWilkie.data.F.y;
v.z = armory.renderpath.HosekWilkie.data.F.z;
}
}
else if (link == "_hosekG") {
if (armory.renderpath.HosekWilkie.data == null) {
armory.renderpath.HosekWilkie.recompute(Scene.active.world);
}
if (armory.renderpath.HosekWilkie.data != null) {
v = iron.object.Uniforms.helpVec;
v.x = armory.renderpath.HosekWilkie.data.G.x;
v.y = armory.renderpath.HosekWilkie.data.G.y;
v.z = armory.renderpath.HosekWilkie.data.G.z;
}
}
else if (link == "_hosekH") {
if (armory.renderpath.HosekWilkie.data == null) {
armory.renderpath.HosekWilkie.recompute(Scene.active.world);
}
if (armory.renderpath.HosekWilkie.data != null) {
v = iron.object.Uniforms.helpVec;
v.x = armory.renderpath.HosekWilkie.data.H.x;
v.y = armory.renderpath.HosekWilkie.data.H.y;
v.z = armory.renderpath.HosekWilkie.data.H.z;
}
}
else if (link == "_hosekI") {
if (armory.renderpath.HosekWilkie.data == null) {
armory.renderpath.HosekWilkie.recompute(Scene.active.world);
}
if (armory.renderpath.HosekWilkie.data != null) {
v = iron.object.Uniforms.helpVec;
v.x = armory.renderpath.HosekWilkie.data.I.x;
v.y = armory.renderpath.HosekWilkie.data.I.y;
v.z = armory.renderpath.HosekWilkie.data.I.z;
}
}
else if (link == "_hosekZ") {
if (armory.renderpath.HosekWilkie.data == null) {
armory.renderpath.HosekWilkie.recompute(Scene.active.world);
}
if (armory.renderpath.HosekWilkie.data != null) {
v = iron.object.Uniforms.helpVec;
v.x = armory.renderpath.HosekWilkie.data.Z.x;
v.y = armory.renderpath.HosekWilkie.data.Z.y;
v.z = armory.renderpath.HosekWilkie.data.Z.z;
}
}
#end
#if rp_voxelao
if (link == "_cameraPositionSnap") {
v = iron.object.Uniforms.helpVec;
var camera = iron.Scene.active.camera;
v.set(camera.transform.worldx(), camera.transform.worldy(), camera.transform.worldz());
var l = camera.lookWorld();
var e = Main.voxelgiHalfExtents;
v.x += l.x * e * 0.9;
v.y += l.y * e * 0.9;
var f = Main.voxelgiVoxelSize * 8; // Snaps to 3 mip-maps range
v.set(Math.floor(v.x / f) * f, Math.floor(v.y / f) * f, Math.floor(v.z / f) * f);
}
#end
return v;
}
public static function floatLink(object: Object, mat: MaterialData, link: String): Null<kha.FastFloat> {
#if rp_dynres
if (link == "_dynamicScale") {
return armory.renderpath.DynamicResolutionScale.dynamicScale;
switch (link) {
#if rp_dynres
case "_dynamicScale": {
return armory.renderpath.DynamicResolutionScale.dynamicScale;
}
#end
#if arm_debug
case "_debugFloat": {
return armory.trait.internal.DebugConsole.debugFloat;
}
#end
#if rp_voxelao
case "_voxelBlend": { // Blend current and last voxels
var freq = armory.renderpath.RenderPathCreator.voxelFreq;
return (armory.renderpath.RenderPathCreator.voxelFrame % freq) / freq;
}
#end
}
#end
#if arm_debug
if (link == "_debugFloat") {
return armory.trait.internal.DebugConsole.debugFloat;
}
#end
#if rp_voxelao
if (link == "_voxelBlend") { // Blend current and last voxels
var freq = armory.renderpath.RenderPathCreator.voxelFreq;
return (armory.renderpath.RenderPathCreator.voxelFrame % freq) / freq;
}
#end
return null;
}
}

View file

@ -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;

View file

@ -0,0 +1,226 @@
package armory.renderpath;
import kha.FastFloat;
import kha.arrays.Float32Array;
import kha.graphics4.TextureFormat;
import kha.graphics4.Usage;
import iron.data.WorldData;
import iron.math.Vec2;
import iron.math.Vec3;
import armory.math.Helper;
/**
Utility class to control the Nishita sky model.
**/
class Nishita {
public static var data: NishitaData = null;
/**
Recomputes the nishita lookup table after the density settings changed.
Do not call this method on every frame (it's slow)!
**/
public static function recompute(world: WorldData) {
if (world == null || world.raw.nishita_density == null) return;
if (data == null) data = new NishitaData();
var density = world.raw.nishita_density;
data.computeLUT(new Vec3(density[0], density[1], density[2]));
}
/** Sets the sky's density parameters and calls `recompute()` afterwards. **/
public static function setDensity(world: WorldData, densityAir: FastFloat, densityDust: FastFloat, densityOzone: FastFloat) {
if (world == null) return;
if (world.raw.nishita_density == null) world.raw.nishita_density = new Float32Array(3);
var density = world.raw.nishita_density;
density[0] = Helper.clamp(densityAir, 0, 10);
density[1] = Helper.clamp(densityDust, 0, 10);
density[2] = Helper.clamp(densityOzone, 0, 10);
recompute(world);
}
}
/**
This class holds the precalculated result of the inner scattering integral
of the Nishita sky model. The outer integral is calculated in
[`armory/Shaders/std/sky.glsl`](https://github.com/armory3d/armory/blob/master/Shaders/std/sky.glsl).
@see `armory.renderpath.Nishita`
**/
class NishitaData {
public var lut: kha.Image;
/**
The amount of individual sample heights stored in the LUT (and the width
of the LUT image).
**/
public static var lutHeightSteps = 128;
/**
The amount of individual sun angle steps stored in the LUT (and the
height of the LUT image).
**/
public static var lutAngleSteps = 128;
/**
Amount of steps for calculating the inner scattering integral. Heigher
values are more precise but take longer to compute.
**/
public static var jSteps = 8;
/** Radius of the atmosphere in meters. **/
public static var radiusAtmo = 6420000;
/**
Radius of the planet in meters. The default value is the earth radius as
defined in Cycles.
**/
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. **/
function getOzoneDensity(height: FastFloat): FastFloat {
// Values are taken from Cycles code
if (height < 10000.0 || height >= 40000.0) {
return 0.0;
}
if (height < 25000.0) {
return (height - 10000.0) / 15000.0;
}
return -((height - 40000.0) / 15000.0);
}
/**
Ray-sphere intersection test that assumes the sphere is centered at the
origin. There is no intersection when result.x > result.y. Otherwise
this function returns the distances to the two intersection points,
which might be equal.
**/
function raySphereIntersection(rayOrigin: Vec3, rayDirection: Vec3, sphereRadius: Int): Vec2 {
// Algorithm is described here: https://en.wikipedia.org/wiki/Line%E2%80%93sphere_intersection
var a = rayDirection.dot(rayDirection);
var b = 2.0 * rayDirection.dot(rayOrigin);
var c = rayOrigin.dot(rayOrigin) - (sphereRadius * sphereRadius);
var d = (b * b) - 4.0 * a * c;
// Ray does not intersect the sphere
if (d < 0.0) return new Vec2(1e5, -1e5);
return new Vec2(
(-b - Math.sqrt(d)) / (2.0 * a),
(-b + Math.sqrt(d)) / (2.0 * a)
);
}
/**
Computes the LUT texture for the given density values.
@param density 3D vector of air density, dust density, ozone density
**/
public function computeLUT(density: Vec3) {
var imageData = new haxe.io.Float32Array(lutHeightSteps * lutAngleSteps * 4);
for (x in 0...lutHeightSteps) {
var height = (x / (lutHeightSteps - 1));
// Use quadratic height for better horizon precision
height *= height;
height *= radiusAtmo; // Denormalize
for (y in 0...lutAngleSteps) {
var sunTheta = y / (lutAngleSteps - 1) * 2 - 1;
// Improve horizon precision
// See https://sebh.github.io/publications/egsr2020.pdf (5.3)
sunTheta = Helper.sign(sunTheta) * sunTheta * sunTheta;
sunTheta = sunTheta * Math.PI / 2 + Math.PI / 2; // Denormalize
var jODepth = sampleSecondaryRay(height, sunTheta, density);
var pixelIndex = (x + y * lutHeightSteps) * 4;
imageData[pixelIndex + 0] = jODepth.x;
imageData[pixelIndex + 1] = jODepth.y;
imageData[pixelIndex + 2] = jODepth.z;
imageData[pixelIndex + 3] = 1.0; // Unused
}
}
lut = kha.Image.fromBytes(imageData.view.buffer, lutHeightSteps, lutAngleSteps, TextureFormat.RGBA128, Usage.StaticUsage);
}
/**
Calculates the integral for the secondary ray.
**/
public function sampleSecondaryRay(height: FastFloat, sunTheta: FastFloat, density: Vec3): Vec3 {
// Reconstruct values from the shader
var iPos = new Vec3(0, 0, height + radiusPlanet);
var pSun = new Vec3(0.0, Math.sin(sunTheta), Math.cos(sunTheta)).normalize();
var jTime: FastFloat = 0.0;
var jStepSize: FastFloat = raySphereIntersection(iPos, pSun, radiusAtmo).y / jSteps;
// Optical depth accumulators for the secondary ray (Rayleigh, Mie, ozone)
var jODepth = new Vec3();
for (i in 0...jSteps) {
// Calculate the secondary ray sample position and height
var jPos = iPos.clone().add(pSun.clone().mult(jTime + jStepSize * 0.5));
var jHeight = jPos.length() - radiusPlanet;
// Accumulate optical depth
var optDepthRayleigh = Math.exp(-jHeight / rayleighScale) * density.x;
var optDepthMie = Math.exp(-jHeight / mieScale) * density.y;
var optDepthOzone = getOzoneDensity(jHeight) * density.z;
jODepth.addf(optDepthRayleigh, optDepthMie, optDepthOzone);
jTime += 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;
}
}

View 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;
}

View file

@ -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);
}
}

View file

@ -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;

View file

@ -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();
}
}
}

View file

@ -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.");
}

View file

@ -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;

View file

@ -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);

View file

@ -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); };
}

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