forked from LeenkxTeam/LNXSDK
		
	Compare commits
	
		
			504 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| f5fa754e17 | |||
| 48f5575e4e | |||
| f2c4be6336 | |||
| 2ddc938db8 | |||
| 5eb735ada2 | |||
| 9894cc20f2 | |||
| dbe6d0829a | |||
| 6f383e2ab2 | |||
| 5c2d29d7ce | |||
| 28579e14d7 | |||
| 2ec6f43cc5 | |||
| 027021815a | |||
| b9b387803f | |||
| e05d9d0237 | |||
| c908e6cad2 | |||
| 506a0a0245 | |||
| 5cf33724e4 | |||
| ac5aa3d19c | |||
| 0c534ee632 | |||
| 69a2bb1e7e | |||
| e3e7855d26 | |||
| f7917974f8 | |||
| fa2d8f05d5 | |||
| 5b86f32b51 | |||
| 73fcb55acc | |||
| c24baa3364 | |||
| 4517c4863f | |||
| 1299306e09 | |||
| f97d8fd846 | |||
| 8f8d4b1376 | |||
| a926fa8dbb | |||
| 6c3efa6c83 | |||
| 21afad6d09 | |||
| 04c6983a09 | |||
| 45966ef0bb | |||
| a72edc6203 | |||
| 6af1ef2df1 | |||
| 46e3047877 | |||
| de74af215a | |||
| b6e96553c2 | |||
| 58e009f709 | |||
| e88f101ca6 | |||
| d28d59b9e6 | |||
| a4398c7279 | |||
| abedfd799e | |||
| 4520422f6b | |||
| 88418c06c3 | |||
| aedc2783ab | |||
| 1505414c4c | |||
| fa818602c4 | |||
| 79dc458671 | |||
| 8e635fb1e9 | |||
| 4c2e6ab26a | |||
| 2371e3777e | |||
| b458b77e5c | |||
| 9b76f8cca9 | |||
| 5f2acb209e | |||
| 6fc446e7a9 | |||
| 71e57026e1 | |||
| 5288a98440 | |||
| 35e346be39 | |||
| 843ef0b058 | |||
| 177890bf39 | |||
| 9ac37e6dc7 | |||
| e697437778 | |||
| c94fc0fd97 | |||
| cd0a6f6788 | |||
| 4400e0e9c8 | |||
| 20cf07cfc3 | |||
| 1939f19c05 | |||
| 0d2b152ccb | |||
| 7f58e0fc85 | |||
| 0e4a6575c7 | |||
| 024676f43a | |||
| 8fe758862c | |||
| 1f3d1b47ae | |||
| f659a3c2be | |||
| 6eeb9017d4 | |||
| afe89c3834 | |||
| 8b695f72bb | |||
| 3d99fa60c0 | |||
| 43be7729ba | |||
| de0b1075c2 | |||
| c7aba23fa4 | |||
| 881f3267cc | |||
| 19b79d61c7 | |||
| fcbab54a0c | |||
| 8fd05d5514 | |||
| ad4013ed75 | |||
| 590e6219d5 | |||
| 8ac567b57b | |||
| 43b7ae7060 | |||
| 662981fa03 | |||
| a3866fb604 | |||
| 29e9e71a6a | |||
| bfb85b0a3b | |||
| ef99b800e0 | |||
| 7cca955fc5 | |||
| 7e7bbd5eae | |||
| c31b2a18ad | |||
| fb47bf2564 | |||
| 7ae6750620 | |||
| 5b87010f76 | |||
| 97e952fc15 | |||
| b440539d65 | |||
| fbf63e4f17 | |||
| a318e08072 | |||
| 7ae458a9dd | |||
| 60a9db6459 | |||
| 3b5a93c92a | |||
| 4af990796e | |||
| 9fb4916c3c | |||
| f61d5833bb | |||
| 40b52be713 | |||
| 07d8422f22 | |||
| 7179d42b27 | |||
| 9984615f8c | |||
| 99a5d7d445 | |||
| 5e0acd3d5d | |||
| 0430e06acd | |||
| f4077e461b | |||
| 28943f1522 | |||
| df4feac132 | |||
| 82412dbf81 | |||
| 6afc209db7 | |||
| e9aae53be9 | |||
| a65675ef75 | |||
| 8f073c5ae1 | |||
| 08d08e42d9 | |||
| a1ee335c68 | |||
| de6bf8a08a | |||
| 9622f35b73 | |||
| da666e6d23 | |||
| 6ff7804ec1 | |||
| 0265ef5b64 | |||
| 53c5000975 | |||
| 7647231696 | |||
| 1e583a795d | |||
| da25d8c313 | |||
| 70695b3b31 | |||
| 858537d54c | |||
| 2998a5585e | |||
| c35c59e6a9 | |||
| 15ac833f2c | |||
| 8077f00ada | |||
| b9848cd2dc | |||
| 58140ad583 | |||
| e922cc38e6 | |||
| 9e2b601445 | |||
| 0439dde4a8 | |||
| 57f0e937d0 | |||
| e234c8615c | |||
| 2e7ccb5151 | |||
| e594518e57 | |||
| a41be0f436 | |||
| 1306033b36 | |||
| eee0011cdd | |||
| 315ac0bd16 | |||
| f289e6f89c | |||
| b89ebfd9c6 | |||
| a142b248ef | |||
| 700d236bf1 | |||
| f228eab8d3 | |||
| 863d884b76 | |||
| 34e0f5a282 | |||
| 45e2e52008 | |||
| 444a215e63 | |||
| fb2d2a1a7c | |||
| f88c04abea | |||
| 6fdd4b3f70 | |||
| a389c27d75 | |||
| 1909c3da9f | |||
| 1c648b0433 | |||
| 5824bd91aa | |||
| 43fe559eef | |||
| 12c09545ce | |||
| 0e60951ec9 | |||
| ccb8b358d3 | |||
| 3103a976a6 | |||
| 1a8586777b | |||
| 3721c774a1 | |||
| a58fba408d | |||
| 82fa7bcfe3 | |||
| 268fba6cd5 | |||
| 4ab14ce6c8 | |||
| 9023e8d1da | |||
| b58c7a9632 | |||
| 99b70622f5 | |||
| 647b73b746 | |||
| 935c30ec08 | |||
| 0b0d597f89 | |||
| d5878afb30 | |||
| 96b55a1a56 | |||
| 91b3072305 | |||
| 1d0b338d92 | |||
| 8e83c0d0d0 | |||
| 927baec4df | |||
| f5c9e70d1a | |||
| 709e0ed9cb | |||
| 0423a735fc | |||
| 7bcf985023 | |||
| bd413917fc | |||
| 852377f60d | |||
| e17e9a8e35 | |||
| 4055c979a1 | |||
| 06b003ecdb | |||
| fd7f215bb2 | |||
| 6a1df9ec46 | |||
| deccac3c46 | |||
| 432b0210b2 | |||
| 14cf5cebed | |||
| d23232205b | |||
| 2307e1504f | |||
| 1ebfecb644 | |||
| 175b575b23 | |||
| 63943a9cbf | |||
| 224d9be76f | |||
| 62d3c8757b | |||
| 3785f93573 | |||
| ffb276745f | |||
| d1c9258da5 | |||
| 3e0cd2be35 | |||
| 1fd1973470 | |||
| a01c72ef76 | |||
| 4b01a562c9 | |||
| 88c7c5b99e | |||
| 6972d9abc4 | |||
| 63c6b9d98b | |||
| 313d24bbc8 | |||
| 6d2812306d | |||
| e84d6ada84 | |||
| 5057f2b946 | |||
| 2715fe3398 | |||
| 7cb8b8a2d2 | |||
| cd606009e0 | |||
| 965162b101 | |||
| c61a57bfb3 | |||
| 2434ad07f2 | |||
| cdc425fbcb | |||
| 846bb28c86 | |||
| 7fabd77ef8 | |||
| fb1a5c88bf | |||
| e05c83a8bb | |||
| ee4f62e881 | |||
| 59f8dff22f | |||
| 5572226ac5 | |||
| d04874e0b3 | |||
| ef8b3a99ab | |||
| 1d3254a237 | |||
| 188af4a50f | |||
| c45baaf396 | |||
| 4b1da08819 | |||
| aeb353fb20 | |||
| 65961b1593 | |||
| 1c472155e2 | |||
| 4238f0b2a0 | |||
| b40aadf76c | |||
| 00493bed9c | |||
| 7277987335 | |||
| a48ec4d034 | |||
| 7f0153f816 | |||
| 40d893e139 | |||
| 9b9289d27d | |||
| 8786798edd | |||
| fa425a98a5 | |||
| 7b17633c28 | |||
| 1ef805eb0b | |||
| cb7b041fea | |||
| 5165769088 | |||
| feabf446db | |||
| e770120f7d | |||
| a0e8e1a1a6 | |||
| 7c1b1f2dd9 | |||
| 88a4f0e76a | |||
| d9e613b3eb | |||
| a0c84dc807 | |||
| 5a92920b1f | |||
| 30a624c857 | |||
| 8153d67eac | |||
| 9963a42c76 | |||
| 885385d7cb | |||
| c433a7f09e | |||
| c7e2c7d452 | |||
| 2a1235b3d8 | |||
| 074962d158 | |||
| 846c3b2c11 | |||
| b5af208766 | |||
| 63565052e3 | |||
| 38eb66a0b5 | |||
| 908efdd554 | |||
| e014484d27 | |||
| 3ea0d7da9d | |||
| 00b580a4fa | |||
| f779462f36 | |||
| 2c7343aa31 | |||
| 85912d84fb | |||
| ad0d750dd0 | |||
| 9914d53045 | |||
| 9daf6c15ab | |||
| 9ac3de67aa | |||
| fd02f6bca3 | |||
| 2cc0d3db3b | |||
| fe730a65ee | |||
| 18ec9712fd | |||
| 0d80f3fb6d | |||
| be06b222cb | |||
| 3f0984e227 | |||
| 15a10ea3aa | |||
| 012abfeaf6 | |||
| dd6cd16661 | |||
| d8b37efe1b | |||
| a40a035c03 | |||
| a318758cbf | |||
| 7c13a25caf | |||
| 141567467f | |||
| 047983a280 | |||
| 48ad4322cf | |||
| eaa34308d0 | |||
| 741a12de78 | |||
| 9749467cd7 | |||
| 91ae053346 | |||
| b7b7edb5e2 | |||
| dfa99fcb14 | |||
| bc0bf41b91 | |||
| 535e69dcd0 | |||
| 2eaf83d89c | |||
| 6e62917819 | |||
| 03106eff02 | |||
| 0c5d71ecd2 | |||
| d6a7b7e305 | |||
| 3d91f2f1e7 | |||
| d76c295786 | |||
| 79422337ae | |||
| b0e624ef75 | |||
| 9d78aabf35 | |||
| a3930d7761 | |||
| c958113c94 | |||
| 385c683fe3 | |||
| 1050337751 | |||
| 114bf7544a | |||
| 0199ee9877 | |||
| 6e02aeee53 | |||
| 6c3d71c4c9 | |||
| 78592b245f | |||
| 80d4422c90 | |||
| 32df55d636 | |||
| eede86e278 | |||
| 1b855f953f | |||
| 59df400b0d | |||
| 4af244e3e2 | |||
| ae91f8801f | |||
| 7f5786d47c | |||
| ea12d5b951 | |||
| d37468a6ab | |||
| d0b3dc2ff8 | |||
| 85bbc10d06 | |||
| 2fca73aebd | |||
| 8b187940ee | |||
| 00369aa90b | |||
| 26a10020ac | |||
| 421463a642 | |||
| 8d9f248d2f | |||
| ed72206a26 | |||
| 6b7460dd4c | |||
| 447af740be | |||
| 3ff6c32ac9 | |||
| b752d70109 | |||
| a6f83e2d37 | |||
| 016e223fb8 | |||
| 502601e684 | |||
| 29a4bb6803 | |||
| cfbe7c83cb | |||
| a6d9cb9201 | |||
| 32cdbd8c54 | |||
| 1a17b646e4 | |||
| cdf79de36b | |||
| 2aa6be6496 | |||
| 25c391d244 | |||
| a3c2be4e79 | |||
| 3413e10134 | |||
| fa91348428 | |||
| d40d3eb96e | |||
| 16e019be26 | |||
| 2e77f67683 | |||
| 9824dc5a44 | |||
| 872433cafb | |||
| 74bbb6ca87 | |||
| cbbd6fe495 | |||
| 45a48acf8a | |||
| 1c20e03e0c | |||
| c769b3ca26 | |||
| 98f334c883 | |||
| 8ac8a780e1 | |||
| 25e5700084 | |||
| c4378be891 | |||
| 6ad615a961 | |||
| 1e4510ba56 | |||
| a2714bf101 | |||
| 5639234eb9 | |||
| 1591ccdae5 | |||
| 9cb5232187 | |||
| 28d60a652b | |||
| 778be03472 | |||
| fff8b5c29e | |||
| a70d0bd601 | |||
| 8fc14ac793 | |||
| 13add8f60b | |||
| 2c1605c855 | |||
| 3524676fcc | |||
| a577d57263 | |||
| 58440bb347 | |||
| f3808c4251 | |||
| 95c08e3424 | |||
| ce762b3cfa | |||
| 15bcf4a374 | |||
| 634aaa0b6a | |||
| 69fc090f55 | |||
| f42041ccb6 | |||
| a8787bd315 | |||
| b5e77aeef8 | |||
| f379685fdd | |||
| 32ff286691 | |||
| 38ab682978 | |||
| 8efe115698 | |||
| 38f72101eb | |||
| f6d03b060c | |||
| f450c00ff1 | |||
| 6b25d8c8ad | |||
| 13ca31f480 | |||
| d102e59040 | |||
| df0e24c307 | |||
| 2df86850f8 | |||
| 02ff259860 | |||
| 2e6de515ef | |||
| 41b840212c | |||
| 751f960b82 | |||
| 9558ded5c4 | |||
| 8066756605 | |||
| ac2507e0ae | |||
| 205d4ccc41 | |||
| 7565818d0e | |||
| fc093eca3e | |||
| 61b8f21037 | |||
| d988ce8c99 | |||
| 727d82f268 | |||
| c3c89c320b | |||
| 0b5bb877fb | |||
| 429e6d6768 | |||
| 2d8bfbf181 | |||
| 1ad7e0eaf4 | |||
| ae72401657 | |||
| 58b9000305 | |||
| 0cc86c41b8 | |||
| 25f8c5f64c | |||
| 109544cea9 | |||
| 4c92c4bcc9 | |||
| 3433afb1c3 | |||
| e22b522059 | |||
| 200af34740 | |||
| 6d7b0078b4 | |||
| fa501cb09b | |||
| 62a4bbb714 | |||
| eab3e3b30c | |||
| 3be7528a6c | |||
| c9dd46c5e3 | |||
| 99806b8069 | |||
| e98bfb125d | |||
| c4c0e2beaa | |||
| 36cbc934ba | |||
| 210d5ea532 | |||
| dab9a38424 | |||
| b7bbe40348 | |||
| 8b084156ff | |||
| 538c364f33 | |||
| 09eee93ac9 | |||
| 8b5a77c001 | |||
| 436b7fac02 | |||
| 9ef9f5a637 | |||
| b8ca4be56a | |||
| 29e4993f06 | |||
| 4134352688 | |||
| 25cf758a33 | |||
| 23af038a16 | |||
| 7f7878aaa6 | |||
| d7e076fb56 | |||
| dab915b60d | |||
| 74389ba76a | |||
| bd5afc797d | |||
| 27b4ec42a8 | |||
| ab7edaa9e3 | |||
| 27540ac7e9 | |||
| a5b512f20b | |||
| f8d0e67f33 | |||
| 915118617d | |||
| ea69511e67 | |||
| 3926a7f83e | |||
| 0eafd14ae2 | |||
| 08614512d7 | |||
| 08261a9335 | |||
| ce3c1cea6a | |||
| 392d12a816 | |||
| 6b423038d4 | |||
| 76628fc010 | |||
| 99f687b10c | 
							
								
								
									
										2
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					*.hdr binary
 | 
				
			||||||
 | 
					blender/lnx/props.py ident
 | 
				
			||||||
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					__pycache__/
 | 
				
			||||||
 | 
					*.pyc
 | 
				
			||||||
 | 
					*.DS_Store
 | 
				
			||||||
@ -2,10 +2,12 @@
 | 
				
			|||||||
-cp ../Kha/Backends/Krom
 | 
					-cp ../Kha/Backends/Krom
 | 
				
			||||||
-cp ../leenkx/Sources
 | 
					-cp ../leenkx/Sources
 | 
				
			||||||
-cp ../iron/Sources
 | 
					-cp ../iron/Sources
 | 
				
			||||||
 | 
					-cp ../lib/aura/Sources
 | 
				
			||||||
-cp ../lib/haxebullet/Sources
 | 
					-cp ../lib/haxebullet/Sources
 | 
				
			||||||
-cp ../lib/haxerecast/Sources
 | 
					-cp ../lib/haxerecast/Sources
 | 
				
			||||||
-cp ../lib/zui/Sources
 | 
					-cp ../lib/zui/Sources
 | 
				
			||||||
--macro include('iron', true, null, ['../iron/Sources'])
 | 
					--macro include('iron', true, null, ['../iron/Sources'])
 | 
				
			||||||
 | 
					--macro include('aura', true, null, ['../lib/aura/Sources'])
 | 
				
			||||||
--macro include('haxebullet', true, null, ['../lib/haxebullet/Sources'])
 | 
					--macro include('haxebullet', true, null, ['../lib/haxebullet/Sources'])
 | 
				
			||||||
--macro include('haxerecast', true, null, ['../lib/haxerecast/Sources'])
 | 
					--macro include('haxerecast', true, null, ['../lib/haxerecast/Sources'])
 | 
				
			||||||
--macro include('leenkx', true, ['leenkx.network'], ['../leenkx/Sources','../iron/Sources'])
 | 
					--macro include('leenkx', true, ['leenkx.network'], ['../leenkx/Sources','../iron/Sources'])
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										18
									
								
								leenkx.py
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								leenkx.py
									
									
									
									
									
								
							@ -24,7 +24,7 @@ import textwrap
 | 
				
			|||||||
import threading
 | 
					import threading
 | 
				
			||||||
import traceback
 | 
					import traceback
 | 
				
			||||||
import typing
 | 
					import typing
 | 
				
			||||||
from typing import Callable, Optional
 | 
					from typing import Callable, Optional, List
 | 
				
			||||||
import webbrowser
 | 
					import webbrowser
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import bpy
 | 
					import bpy
 | 
				
			||||||
@ -33,6 +33,12 @@ from bpy.props import *
 | 
				
			|||||||
from bpy.types import Operator, AddonPreferences
 | 
					from bpy.types import Operator, AddonPreferences
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if bpy.app.version < (2, 90, 0):  
 | 
				
			||||||
 | 
					    ListType = List
 | 
				
			||||||
 | 
					else:
 | 
				
			||||||
 | 
					    ListType = list
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class SDKSource(IntEnum):
 | 
					class SDKSource(IntEnum):
 | 
				
			||||||
    PREFS = 0
 | 
					    PREFS = 0
 | 
				
			||||||
    LOCAL = 1
 | 
					    LOCAL = 1
 | 
				
			||||||
@ -73,6 +79,7 @@ def detect_sdk_path():
 | 
				
			|||||||
    area = win.screen.areas[0]
 | 
					    area = win.screen.areas[0]
 | 
				
			||||||
    area_type = area.type
 | 
					    area_type = area.type
 | 
				
			||||||
    area.type = "INFO"
 | 
					    area.type = "INFO"
 | 
				
			||||||
 | 
					    if bpy.app.version >= (2, 92, 0):
 | 
				
			||||||
        with bpy.context.temp_override(window=win, screen=win.screen, area=area):
 | 
					        with bpy.context.temp_override(window=win, screen=win.screen, area=area):
 | 
				
			||||||
            bpy.ops.info.select_all(action='SELECT')
 | 
					            bpy.ops.info.select_all(action='SELECT')
 | 
				
			||||||
            bpy.ops.info.report_copy()
 | 
					            bpy.ops.info.report_copy()
 | 
				
			||||||
@ -85,6 +92,7 @@ def detect_sdk_path():
 | 
				
			|||||||
    if match:
 | 
					    if match:
 | 
				
			||||||
        addon_prefs.sdk_path = os.path.dirname(match[-1])
 | 
					        addon_prefs.sdk_path = os.path.dirname(match[-1])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_link_web_server(self):
 | 
					def get_link_web_server(self):
 | 
				
			||||||
    return self.get('link_web_server', 'http://localhost/')
 | 
					    return self.get('link_web_server', 'http://localhost/')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -558,7 +566,7 @@ def remove_readonly(func, path, excinfo):
 | 
				
			|||||||
    func(path)
 | 
					    func(path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def run_proc(cmd: list[str], done: Optional[Callable[[bool], None]] = None):
 | 
					def run_proc(cmd: ListType[str], done: Optional[Callable[[bool], None]] = None):
 | 
				
			||||||
    def fn(p, done):
 | 
					    def fn(p, done):
 | 
				
			||||||
        p.wait()
 | 
					        p.wait()
 | 
				
			||||||
        if done is not None:
 | 
					        if done is not None:
 | 
				
			||||||
@ -839,6 +847,12 @@ def update_leenkx_py(sdk_path: str, force_relink=False):
 | 
				
			|||||||
                        raise err
 | 
					                        raise err
 | 
				
			||||||
                else:
 | 
					                else:
 | 
				
			||||||
                    raise err
 | 
					                    raise err
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        if bpy.app.version < (2, 92, 0):
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                lnx_module_file.unlink()
 | 
				
			||||||
 | 
					            except FileNotFoundError:
 | 
				
			||||||
 | 
					                pass 
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            lnx_module_file.unlink(missing_ok=True)
 | 
					            lnx_module_file.unlink(missing_ok=True)
 | 
				
			||||||
        shutil.copy(Path(sdk_path) / 'leenkx.py', lnx_module_file)
 | 
					        shutil.copy(Path(sdk_path) / 'leenkx.py', lnx_module_file)
 | 
				
			||||||
 | 
				
			|||||||
@ -3,6 +3,10 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "compiled.inc"
 | 
					#include "compiled.inc"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef _CPostprocess
 | 
				
			||||||
 | 
					uniform vec4 PPComp17;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uniform sampler2D tex;
 | 
					uniform sampler2D tex;
 | 
				
			||||||
uniform vec2 dir;
 | 
					uniform vec2 dir;
 | 
				
			||||||
uniform vec2 screenSize;
 | 
					uniform vec2 screenSize;
 | 
				
			||||||
@ -45,6 +49,12 @@ void main() {
 | 
				
			|||||||
		res += factor * col;
 | 
							res += factor * col;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#ifdef _CPostprocess
 | 
				
			||||||
 | 
							vec3 AirColor = vec3(PPComp17.x, PPComp17.y, PPComp17.z);
 | 
				
			||||||
 | 
						#else
 | 
				
			||||||
 | 
							vec3 AirColor = volumAirColor;
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
						
 | 
				
			||||||
	res /= sumfactor;
 | 
						res /= sumfactor;
 | 
				
			||||||
	fragColor = vec4(volumAirColor * res, 1.0);
 | 
						fragColor = vec4(AirColor * res, 1.0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -19,6 +19,11 @@
 | 
				
			|||||||
				{
 | 
									{
 | 
				
			||||||
					"name": "screenSize",
 | 
										"name": "screenSize",
 | 
				
			||||||
					"link": "_screenSize"
 | 
										"link": "_screenSize"
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										"name": "PPComp17",
 | 
				
			||||||
 | 
										"link": "_PPComp17",
 | 
				
			||||||
 | 
										"ifdef": ["_CPostprocess"]
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			],
 | 
								],
 | 
				
			||||||
			"texture_params": [],
 | 
								"texture_params": [],
 | 
				
			||||||
 | 
				
			|||||||
@ -5,7 +5,7 @@
 | 
				
			|||||||
uniform sampler2D tex;
 | 
					uniform sampler2D tex;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _CPostprocess
 | 
					#ifdef _CPostprocess
 | 
				
			||||||
uniform vec3 PPComp13;
 | 
					uniform vec4 PPComp13;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
in vec2 texCoord;
 | 
					in vec2 texCoord;
 | 
				
			||||||
@ -43,13 +43,17 @@ void main() {
 | 
				
			|||||||
	#ifdef _CPostprocess
 | 
						#ifdef _CPostprocess
 | 
				
			||||||
		float max_distort = PPComp13.x;
 | 
							float max_distort = PPComp13.x;
 | 
				
			||||||
		int num_iter = int(PPComp13.y);
 | 
							int num_iter = int(PPComp13.y);
 | 
				
			||||||
 | 
							int CAType = int(PPComp13.z);
 | 
				
			||||||
 | 
							int on = int(PPComp13.w);
 | 
				
			||||||
	#else
 | 
						#else
 | 
				
			||||||
		float max_distort = compoChromaticStrength;
 | 
							float max_distort = compoChromaticStrength;
 | 
				
			||||||
		int num_iter = compoChromaticSamples;
 | 
							int num_iter = compoChromaticSamples;
 | 
				
			||||||
 | 
							int CAType = compoChromaticType;
 | 
				
			||||||
 | 
							int on = 1;
 | 
				
			||||||
	#endif
 | 
						#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Spectral
 | 
						// Spectral
 | 
				
			||||||
	if (compoChromaticType == 1) {
 | 
						if (CAType == 1) {
 | 
				
			||||||
		float reci_num_iter_f = 1.0 / float(num_iter);
 | 
							float reci_num_iter_f = 1.0 / float(num_iter);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		vec2 resolution = vec2(1,1);
 | 
							vec2 resolution = vec2(1,1);
 | 
				
			||||||
@ -64,7 +68,7 @@ void main() {
 | 
				
			|||||||
			sumcol += w * texture(tex, barrelDistortion(uv, 0.6 * max_distort * t));
 | 
								sumcol += w * texture(tex, barrelDistortion(uv, 0.6 * max_distort * t));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		fragColor = sumcol / sumw;
 | 
							if (on == 1) fragColor = sumcol / sumw; else fragColor = texture(tex, texCoord);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Simple
 | 
						// Simple
 | 
				
			||||||
@ -73,6 +77,7 @@ void main() {
 | 
				
			|||||||
		col.x = texture(tex, texCoord + ((vec2(0.0, 1.0) * max_distort) / vec2(1000.0))).x;
 | 
							col.x = texture(tex, texCoord + ((vec2(0.0, 1.0) * max_distort) / vec2(1000.0))).x;
 | 
				
			||||||
		col.y = texture(tex, texCoord + ((vec2(-0.85, -0.5) * max_distort) / vec2(1000.0))).y;
 | 
							col.y = texture(tex, texCoord + ((vec2(-0.85, -0.5) * max_distort) / vec2(1000.0))).y;
 | 
				
			||||||
		col.z = texture(tex, texCoord + ((vec2(0.85, -0.5) * max_distort) / vec2(1000.0))).z;
 | 
							col.z = texture(tex, texCoord + ((vec2(0.85, -0.5) * max_distort) / vec2(1000.0))).z;
 | 
				
			||||||
		fragColor = vec4(col.x, col.y, col.z, fragColor.w);
 | 
							if (on == 1) fragColor = vec4(col.x, col.y, col.z, fragColor.w); 
 | 
				
			||||||
 | 
							else fragColor = texture(tex, texCoord);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -62,8 +62,11 @@ uniform vec3 PPComp5;
 | 
				
			|||||||
uniform vec3 PPComp6;
 | 
					uniform vec3 PPComp6;
 | 
				
			||||||
uniform vec3 PPComp7;
 | 
					uniform vec3 PPComp7;
 | 
				
			||||||
uniform vec3 PPComp8;
 | 
					uniform vec3 PPComp8;
 | 
				
			||||||
 | 
					uniform vec3 PPComp11;
 | 
				
			||||||
uniform vec3 PPComp14;
 | 
					uniform vec3 PPComp14;
 | 
				
			||||||
uniform vec4 PPComp15;
 | 
					uniform vec4 PPComp15;
 | 
				
			||||||
 | 
					uniform vec4 PPComp16;
 | 
				
			||||||
 | 
					uniform vec4 PPComp18;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// #ifdef _CPos
 | 
					// #ifdef _CPos
 | 
				
			||||||
@ -106,6 +109,16 @@ in vec2 texCoord;
 | 
				
			|||||||
out vec4 fragColor;
 | 
					out vec4 fragColor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _CFog
 | 
					#ifdef _CFog
 | 
				
			||||||
 | 
						#ifdef _CPostprocess
 | 
				
			||||||
 | 
							vec3 FogColor = vec3(PPComp18.x, PPComp18.y, PPComp18.z);
 | 
				
			||||||
 | 
							float FogAmountA = PPComp18.w;
 | 
				
			||||||
 | 
							float FogAmountB = PPComp11.z;
 | 
				
			||||||
 | 
						#else
 | 
				
			||||||
 | 
							vec3 FogColor = compoFogColor;
 | 
				
			||||||
 | 
							float FogAmountA = compoFogAmountA;
 | 
				
			||||||
 | 
							float FogAmountB = compoFogAmountB;
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
						
 | 
				
			||||||
// const vec3 compoFogColor = vec3(0.5, 0.6, 0.7);
 | 
					// const vec3 compoFogColor = vec3(0.5, 0.6, 0.7);
 | 
				
			||||||
// const float compoFogAmountA = 1.0; // b = 0.01
 | 
					// const float compoFogAmountA = 1.0; // b = 0.01
 | 
				
			||||||
// const float compoFogAmountB = 1.0; // c = 0.1
 | 
					// const float compoFogAmountB = 1.0; // c = 0.1
 | 
				
			||||||
@ -118,8 +131,8 @@ out vec4 fragColor;
 | 
				
			|||||||
// }
 | 
					// }
 | 
				
			||||||
vec3 applyFog(vec3 rgb, float distance) {
 | 
					vec3 applyFog(vec3 rgb, float distance) {
 | 
				
			||||||
	// float fogAmount = 1.0 - exp(-distance * compoFogAmountA);
 | 
						// float fogAmount = 1.0 - exp(-distance * compoFogAmountA);
 | 
				
			||||||
	float fogAmount = 1.0 - exp(-distance * (compoFogAmountA / 100));
 | 
						float fogAmount = 1.0 - exp(-distance * (FogAmountA / 100));
 | 
				
			||||||
	return mix(rgb, compoFogColor, fogAmount);
 | 
						return mix(rgb, FogColor, fogAmount);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -131,7 +144,7 @@ float ConvertEV100ToExposure(float EV100) {
 | 
				
			|||||||
    return 1/0.8 * exp2(-EV100);
 | 
					    return 1/0.8 * exp2(-EV100);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
float ComputeEV(float avgLuminance) {
 | 
					float ComputeEV(float avgLuminance) {
 | 
				
			||||||
    const float sqAperture = PPComp1[0].x * PPComp1.x;
 | 
					    const float sqAperture = PPComp1.x * PPComp1.x;
 | 
				
			||||||
    const float shutterTime = 1.0 / PPComp1.y;
 | 
					    const float shutterTime = 1.0 / PPComp1.y;
 | 
				
			||||||
    const float ISO = PPComp1.z;
 | 
					    const float ISO = PPComp1.z;
 | 
				
			||||||
    const float EC = PPComp2.x;
 | 
					    const float EC = PPComp2.x;
 | 
				
			||||||
@ -350,15 +363,21 @@ void main() {
 | 
				
			|||||||
#ifdef _CSharpen
 | 
					#ifdef _CSharpen
 | 
				
			||||||
	#ifdef _CPostprocess
 | 
						#ifdef _CPostprocess
 | 
				
			||||||
		float strengthSharpen = PPComp14.y;	
 | 
							float strengthSharpen = PPComp14.y;	
 | 
				
			||||||
 | 
							vec3 SharpenColor = vec3(PPComp16.x, PPComp16.y, PPComp16.z); 
 | 
				
			||||||
 | 
							float SharpenSize = PPComp16.w;
 | 
				
			||||||
	#else
 | 
						#else
 | 
				
			||||||
		float strengthSharpen = compoSharpenStrength;
 | 
							float strengthSharpen = compoSharpenStrength;
 | 
				
			||||||
 | 
							vec3 SharpenColor = compoSharpenColor;
 | 
				
			||||||
 | 
							float SharpenSize = compoSharpenSize;
 | 
				
			||||||
	#endif
 | 
						#endif
 | 
				
			||||||
	vec3 col1 = textureLod(tex, texCo + vec2(-texStep.x, -texStep.y) * 1.5, 0.0).rgb;
 | 
						vec3 col1 = textureLod(tex, texCo + vec2(-texStep.x, -texStep.y) * SharpenSize, 0.0).rgb;
 | 
				
			||||||
	vec3 col2 = textureLod(tex, texCo + vec2(texStep.x, -texStep.y) * 1.5, 0.0).rgb;
 | 
						vec3 col2 = textureLod(tex, texCo + vec2(texStep.x, -texStep.y) * SharpenSize, 0.0).rgb;
 | 
				
			||||||
	vec3 col3 = textureLod(tex, texCo + vec2(-texStep.x, texStep.y) * 1.5, 0.0).rgb;
 | 
						vec3 col3 = textureLod(tex, texCo + vec2(-texStep.x, texStep.y) * SharpenSize, 0.0).rgb;
 | 
				
			||||||
	vec3 col4 = textureLod(tex, texCo + vec2(texStep.x, texStep.y) * 1.5, 0.0).rgb;
 | 
						vec3 col4 = textureLod(tex, texCo + vec2(texStep.x, texStep.y) * SharpenSize, 0.0).rgb;
 | 
				
			||||||
	vec3 colavg = (col1 + col2 + col3 + col4) * 0.25;
 | 
						vec3 colavg = (col1 + col2 + col3 + col4) * 0.25;
 | 
				
			||||||
	fragColor.rgb += (fragColor.rgb - colavg) * strengthSharpen;
 | 
						
 | 
				
			||||||
 | 
						float edgeMagnitude = length(fragColor.rgb - colavg); 
 | 
				
			||||||
 | 
						fragColor.rgb = mix(fragColor.rgb, SharpenColor, min(edgeMagnitude * strengthSharpen * 2.0, 1.0));
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _CFog
 | 
					#ifdef _CFog
 | 
				
			||||||
@ -407,7 +426,11 @@ void main() {
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _CExposure
 | 
					#ifdef _CExposure
 | 
				
			||||||
	fragColor.rgb += fragColor.rgb * compoExposureStrength;
 | 
						#ifdef _CPostprocess
 | 
				
			||||||
 | 
							fragColor.rgb+=fragColor.rgb*PPComp8.x;
 | 
				
			||||||
 | 
						#else
 | 
				
			||||||
 | 
							fragColor.rgb+= fragColor.rgb*compoExposureStrength;
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _CPostprocess
 | 
					#ifdef _CPostprocess
 | 
				
			||||||
@ -415,8 +438,13 @@ void main() {
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _AutoExposure
 | 
					#ifdef _AutoExposure
 | 
				
			||||||
 | 
						#ifdef _CPostprocess
 | 
				
			||||||
 | 
							float AEStrength = PPComp8.y;
 | 
				
			||||||
 | 
						#else
 | 
				
			||||||
 | 
							float AEStrength = autoExposureStrength;
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
	float expo = 2.0 - clamp(length(textureLod(histogram, vec2(0.5, 0.5), 0).rgb), 0.0, 1.0);
 | 
						float expo = 2.0 - clamp(length(textureLod(histogram, vec2(0.5, 0.5), 0).rgb), 0.0, 1.0);
 | 
				
			||||||
	fragColor.rgb *= pow(expo, autoExposureStrength * 2.0);
 | 
						fragColor.rgb *= pow(expo, AEStrength * 2.0);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Clamp color to get rid of INF values that don't work for the tone mapping below
 | 
					// Clamp color to get rid of INF values that don't work for the tone mapping below
 | 
				
			||||||
@ -480,9 +508,7 @@ fragColor.rgb = min(fragColor.rgb, 65504 * 0.5);
 | 
				
			|||||||
			fragColor.rgb = pow(fragColor.rgb, vec3(1.0 / 2.2)); // To gamma
 | 
								fragColor.rgb = pow(fragColor.rgb, vec3(1.0 / 2.2)); // To gamma
 | 
				
			||||||
		} else if (PPComp4.x == 10){
 | 
							} else if (PPComp4.x == 10){
 | 
				
			||||||
			fragColor.rgb = tonemapAgXFull(fragColor.rgb);
 | 
								fragColor.rgb = tonemapAgXFull(fragColor.rgb);
 | 
				
			||||||
		} else {
 | 
							} //else { fragColor.rgb = vec3(0,1,0); //ERROR}
 | 
				
			||||||
			fragColor.rgb = vec3(0,1,0); //ERROR
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	#endif
 | 
						#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
 | 
				
			|||||||
@ -235,6 +235,16 @@
 | 
				
			|||||||
					"name": "PPComp15",
 | 
										"name": "PPComp15",
 | 
				
			||||||
					"link": "_PPComp15",
 | 
										"link": "_PPComp15",
 | 
				
			||||||
					"ifdef": ["_CPostprocess"]
 | 
										"ifdef": ["_CPostprocess"]
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										"name": "PPComp16",
 | 
				
			||||||
 | 
										"link": "_PPComp16",
 | 
				
			||||||
 | 
										"ifdef": ["_CPostprocess"]
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										"name": "PPComp18",
 | 
				
			||||||
 | 
										"link": "_PPComp18",
 | 
				
			||||||
 | 
										"ifdef": ["_CPostprocess"]
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			],
 | 
								],
 | 
				
			||||||
			"texture_params": [],
 | 
								"texture_params": [],
 | 
				
			||||||
 | 
				
			|||||||
@ -20,7 +20,7 @@ uniform sampler2D gbuffer0;
 | 
				
			|||||||
uniform sampler2D gbuffer1;
 | 
					uniform sampler2D gbuffer1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _gbuffer2
 | 
					#ifdef _gbuffer2
 | 
				
			||||||
	//!uniform sampler2D gbuffer2;
 | 
						uniform sampler2D gbuffer2;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
#ifdef _EmissionShaded
 | 
					#ifdef _EmissionShaded
 | 
				
			||||||
	uniform sampler2D gbufferEmission;
 | 
						uniform sampler2D gbufferEmission;
 | 
				
			||||||
@ -29,10 +29,11 @@ uniform sampler2D gbuffer1;
 | 
				
			|||||||
#ifdef _VoxelGI
 | 
					#ifdef _VoxelGI
 | 
				
			||||||
uniform sampler2D voxels_diffuse;
 | 
					uniform sampler2D voxels_diffuse;
 | 
				
			||||||
uniform sampler2D voxels_specular;
 | 
					uniform sampler2D voxels_specular;
 | 
				
			||||||
#endif
 | 
					#else
 | 
				
			||||||
#ifdef _VoxelAOvar
 | 
					#ifdef _VoxelAOvar
 | 
				
			||||||
uniform sampler2D voxels_ao;
 | 
					uniform sampler2D voxels_ao;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
#ifdef _VoxelShadow
 | 
					#ifdef _VoxelShadow
 | 
				
			||||||
uniform sampler3D voxels;
 | 
					uniform sampler3D voxels;
 | 
				
			||||||
uniform sampler3D voxelsSDF;
 | 
					uniform sampler3D voxelsSDF;
 | 
				
			||||||
@ -56,6 +57,10 @@ uniform vec3 backgroundCol;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#ifdef _SSAO
 | 
					#ifdef _SSAO
 | 
				
			||||||
uniform sampler2D ssaotex;
 | 
					uniform sampler2D ssaotex;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#ifdef _SSGI
 | 
				
			||||||
 | 
					uniform sampler2D ssaotex;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _SSS
 | 
					#ifdef _SSS
 | 
				
			||||||
@ -113,11 +118,15 @@ uniform vec2 cameraPlane;
 | 
				
			|||||||
#ifdef _SinglePoint
 | 
					#ifdef _SinglePoint
 | 
				
			||||||
	#ifdef _Spot
 | 
						#ifdef _Spot
 | 
				
			||||||
	//!uniform sampler2DShadow shadowMapSpot[1];
 | 
						//!uniform sampler2DShadow shadowMapSpot[1];
 | 
				
			||||||
 | 
						#ifdef _ShadowMapTransparent
 | 
				
			||||||
	//!uniform sampler2D shadowMapSpotTransparent[1];
 | 
						//!uniform sampler2D shadowMapSpotTransparent[1];
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
	//!uniform mat4 LWVPSpot[1];
 | 
						//!uniform mat4 LWVPSpot[1];
 | 
				
			||||||
	#else
 | 
						#else
 | 
				
			||||||
	//!uniform samplerCubeShadow shadowMapPoint[1];
 | 
						//!uniform samplerCubeShadow shadowMapPoint[1];
 | 
				
			||||||
 | 
						#ifdef _ShadowMapTransparent
 | 
				
			||||||
	//!uniform samplerCube shadowMapPointTransparent[1];
 | 
						//!uniform samplerCube shadowMapPointTransparent[1];
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
	//!uniform vec2 lightProj;
 | 
						//!uniform vec2 lightProj;
 | 
				
			||||||
	#endif
 | 
						#endif
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
@ -125,30 +134,40 @@ uniform vec2 cameraPlane;
 | 
				
			|||||||
	#ifdef _ShadowMapAtlas
 | 
						#ifdef _ShadowMapAtlas
 | 
				
			||||||
		#ifdef _SingleAtlas
 | 
							#ifdef _SingleAtlas
 | 
				
			||||||
		uniform sampler2DShadow shadowMapAtlas;
 | 
							uniform sampler2DShadow shadowMapAtlas;
 | 
				
			||||||
 | 
							#ifdef _ShadowMapTransparent
 | 
				
			||||||
		uniform sampler2D shadowMapAtlasTransparent;
 | 
							uniform sampler2D shadowMapAtlasTransparent;
 | 
				
			||||||
		#endif
 | 
							#endif
 | 
				
			||||||
		#endif
 | 
							#endif
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
	#ifdef _ShadowMapAtlas
 | 
						#ifdef _ShadowMapAtlas
 | 
				
			||||||
		#ifndef _SingleAtlas
 | 
							#ifndef _SingleAtlas
 | 
				
			||||||
		//!uniform sampler2DShadow shadowMapAtlasPoint;
 | 
							//!uniform sampler2DShadow shadowMapAtlasPoint;
 | 
				
			||||||
 | 
							#ifdef _ShadowMapTransparent
 | 
				
			||||||
		//!uniform sampler2D shadowMapAtlasPointTransparent;
 | 
							//!uniform sampler2D shadowMapAtlasPointTransparent;
 | 
				
			||||||
		#endif
 | 
							#endif
 | 
				
			||||||
		//!uniform vec4 pointLightDataArray[4];
 | 
							#endif
 | 
				
			||||||
 | 
							//!uniform vec4 pointLightDataArray[maxLightsCluster * 6];
 | 
				
			||||||
	#else
 | 
						#else
 | 
				
			||||||
		//!uniform samplerCubeShadow shadowMapPoint[4];
 | 
							//!uniform samplerCubeShadow shadowMapPoint[4];
 | 
				
			||||||
 | 
							#ifdef _ShadowMapTransparent
 | 
				
			||||||
		//!uniform samplerCube shadowMapPointTransparent[4];
 | 
							//!uniform samplerCube shadowMapPointTransparent[4];
 | 
				
			||||||
		#endif
 | 
							#endif
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
	//!uniform vec2 lightProj;
 | 
						//!uniform vec2 lightProj;
 | 
				
			||||||
	#ifdef _Spot
 | 
						#ifdef _Spot
 | 
				
			||||||
		#ifdef _ShadowMapAtlas
 | 
							#ifdef _ShadowMapAtlas
 | 
				
			||||||
		#ifndef _SingleAtlas
 | 
							#ifndef _SingleAtlas
 | 
				
			||||||
		//!uniform sampler2DShadow shadowMapAtlasSpot;
 | 
							//!uniform sampler2DShadow shadowMapAtlasSpot;
 | 
				
			||||||
 | 
							#ifdef _ShadowMapTransparent
 | 
				
			||||||
		//!uniform sampler2D shadowMapAtlasSpotTransparent;
 | 
							//!uniform sampler2D shadowMapAtlasSpotTransparent;
 | 
				
			||||||
		#endif
 | 
							#endif
 | 
				
			||||||
 | 
							#endif
 | 
				
			||||||
		#else
 | 
							#else
 | 
				
			||||||
		//!uniform sampler2DShadow shadowMapSpot[4];
 | 
							//!uniform sampler2DShadow shadowMapSpot[4];
 | 
				
			||||||
 | 
							#ifdef _ShadowMapTransparent
 | 
				
			||||||
		//!uniform sampler2D shadowMapSpotTransparent[4];
 | 
							//!uniform sampler2D shadowMapSpotTransparent[4];
 | 
				
			||||||
		#endif
 | 
							#endif
 | 
				
			||||||
 | 
							#endif
 | 
				
			||||||
	//!uniform mat4 LWVPSpotArray[maxLightsCluster];
 | 
						//!uniform mat4 LWVPSpotArray[maxLightsCluster];
 | 
				
			||||||
	#endif
 | 
						#endif
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
@ -161,12 +180,16 @@ uniform vec3 sunCol;
 | 
				
			|||||||
	#ifdef _ShadowMapAtlas
 | 
						#ifdef _ShadowMapAtlas
 | 
				
			||||||
	#ifndef _SingleAtlas
 | 
						#ifndef _SingleAtlas
 | 
				
			||||||
	uniform sampler2DShadow shadowMapAtlasSun;
 | 
						uniform sampler2DShadow shadowMapAtlasSun;
 | 
				
			||||||
 | 
						#ifdef _ShadowMapTransparent
 | 
				
			||||||
	uniform sampler2D shadowMapAtlasSunTransparent;
 | 
						uniform sampler2D shadowMapAtlasSunTransparent;
 | 
				
			||||||
	#endif
 | 
						#endif
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
	#else
 | 
						#else
 | 
				
			||||||
	uniform sampler2DShadow shadowMap;
 | 
						uniform sampler2DShadow shadowMap;
 | 
				
			||||||
 | 
						#ifdef _ShadowMapTransparent
 | 
				
			||||||
	uniform sampler2D shadowMapTransparent;
 | 
						uniform sampler2D shadowMapTransparent;
 | 
				
			||||||
	#endif
 | 
						#endif
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
	uniform float shadowsBias;
 | 
						uniform float shadowsBias;
 | 
				
			||||||
	#ifdef _CSM
 | 
						#ifdef _CSM
 | 
				
			||||||
	//!uniform vec4 casData[shadowmapCascades * 4 + 4];
 | 
						//!uniform vec4 casData[shadowmapCascades * 4 + 4];
 | 
				
			||||||
@ -227,17 +250,22 @@ void main() {
 | 
				
			|||||||
	vec4 g2 = textureLod(gbuffer2, texCoord, 0.0);
 | 
						vec4 g2 = textureLod(gbuffer2, texCoord, 0.0);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _MicroShadowing
 | 
					#ifdef _MicroShadowing
 | 
				
			||||||
	occspec.x = mix(1.0, occspec.x, dotNV); // AO Fresnel
 | 
						occspec.x = mix(1.0, occspec.x, dotNV); // AO Fresnel
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _Brdf
 | 
					#ifdef _Brdf
 | 
				
			||||||
	vec2 envBRDF = texelFetch(senvmapBrdf, ivec2(vec2(dotNV, 1.0 - roughness) * 256.0), 0).xy;
 | 
						vec2 envBRDF = texelFetch(senvmapBrdf, ivec2(vec2(dotNV, 1.0 - roughness) * 256.0), 0).xy;
 | 
				
			||||||
 | 
						vec3 F = f0 * envBRDF.x + envBRDF.y;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						vec3 F = f0;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef _VoxelAOvar
 | 
				
			||||||
 | 
					#ifndef _VoxelGI
 | 
				
			||||||
	// Envmap
 | 
						// Envmap
 | 
				
			||||||
#ifdef _Irr
 | 
					#ifdef _Irr
 | 
				
			||||||
 | 
					 | 
				
			||||||
	vec3 envl = shIrradiance(n, shirr);
 | 
						vec3 envl = shIrradiance(n, shirr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	#ifdef _gbuffer2
 | 
						#ifdef _gbuffer2
 | 
				
			||||||
@ -271,33 +299,33 @@ void main() {
 | 
				
			|||||||
	envl.rgb *= albedo;
 | 
						envl.rgb *= albedo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _Brdf
 | 
					#ifdef _Brdf
 | 
				
			||||||
	envl.rgb *= 1.0 - (f0 * envBRDF.x + envBRDF.y); //LV: We should take refracted light into account
 | 
						envl.rgb *= 1.0 - F; //LV: We should take refracted light into account
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _Rad // Indirect specular
 | 
					#ifdef _Rad // Indirect specular
 | 
				
			||||||
	envl.rgb += prefilteredColor * (f0 * envBRDF.x + envBRDF.y); //LV: Removed "1.5 * occspec.y". Specular should be weighted only by FV LUT
 | 
						envl.rgb += prefilteredColor * F; //LV: Removed "1.5 * occspec.y". Specular should be weighted only by FV LUT
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
	#ifdef _EnvCol
 | 
						#ifdef _EnvCol
 | 
				
			||||||
	envl.rgb += backgroundCol * (f0 * envBRDF.x + envBRDF.y); //LV: Eh, what's the point of weighting it only by F0?
 | 
						envl.rgb += backgroundCol * F; //LV: Eh, what's the point of weighting it only by F0?
 | 
				
			||||||
	#endif
 | 
						#endif
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	envl.rgb *= envmapStrength * occspec.x;
 | 
						envl.rgb *= envmapStrength * occspec.x;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _VoxelGI
 | 
					 | 
				
			||||||
	vec4 indirect_diffuse = textureLod(voxels_diffuse, texCoord, 0.0);
 | 
					 | 
				
			||||||
	fragColor.rgb = (indirect_diffuse.rgb + envl.rgb * (1.0 - indirect_diffuse.a)) * albedo * voxelgiDiff;
 | 
					 | 
				
			||||||
	if(roughness < 1.0 && occspec.y > 0.0)
 | 
					 | 
				
			||||||
		fragColor.rgb += textureLod(voxels_specular, texCoord, 0.0).rgb * occspec.y * voxelgiRefl;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef _VoxelAOvar
 | 
					 | 
				
			||||||
	envl.rgb *= textureLod(voxels_ao, texCoord, 0.0).r;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifndef _VoxelGI
 | 
					 | 
				
			||||||
	fragColor.rgb = envl;
 | 
						fragColor.rgb = envl;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef _VoxelGI
 | 
				
			||||||
 | 
						fragColor.rgb = textureLod(voxels_diffuse, texCoord, 0.0).rgb * voxelgiDiff;
 | 
				
			||||||
 | 
						if(roughness < 1.0 && occspec.y > 0.0)
 | 
				
			||||||
 | 
							fragColor.rgb += textureLod(voxels_specular, texCoord, 0.0).rgb * occspec.y * voxelgiRefl;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#ifdef _VoxelAOvar
 | 
				
			||||||
 | 
						fragColor.rgb = textureLod(voxels_ao, texCoord, 0.0).rgb * voxelgiOcc;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Show voxels
 | 
						// Show voxels
 | 
				
			||||||
	// vec3 origin = vec3(texCoord * 2.0 - 1.0, 0.99);
 | 
						// vec3 origin = vec3(texCoord * 2.0 - 1.0, 0.99);
 | 
				
			||||||
	// vec3 direction = vec3(0.0, 0.0, -1.0);
 | 
						// vec3 direction = vec3(0.0, 0.0, -1.0);
 | 
				
			||||||
@ -317,6 +345,10 @@ void main() {
 | 
				
			|||||||
	// #else
 | 
						// #else
 | 
				
			||||||
	fragColor.rgb *= textureLod(ssaotex, texCoord, 0.0).r;
 | 
						fragColor.rgb *= textureLod(ssaotex, texCoord, 0.0).r;
 | 
				
			||||||
	// #endif
 | 
						// #endif
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#ifdef _SSGI
 | 
				
			||||||
 | 
						fragColor.rgb += textureLod(ssaotex, texCoord, 0.0).rgb;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _EmissionShadeless
 | 
					#ifdef _EmissionShadeless
 | 
				
			||||||
@ -350,37 +382,67 @@ void main() {
 | 
				
			|||||||
		#ifdef _CSM
 | 
							#ifdef _CSM
 | 
				
			||||||
			svisibility = shadowTestCascade(
 | 
								svisibility = shadowTestCascade(
 | 
				
			||||||
											#ifdef _ShadowMapAtlas
 | 
																#ifdef _ShadowMapAtlas
 | 
				
			||||||
 | 
																	#ifdef _ShadowMapTransparent
 | 
				
			||||||
												#ifndef _SingleAtlas
 | 
																	#ifndef _SingleAtlas
 | 
				
			||||||
												shadowMapAtlasSun, shadowMapAtlasSunTransparent
 | 
																	shadowMapAtlasSun, shadowMapAtlasSunTransparent
 | 
				
			||||||
												#else
 | 
																	#else
 | 
				
			||||||
												shadowMapAtlas, shadowMapAtlasTransparent
 | 
																	shadowMapAtlas, shadowMapAtlasTransparent
 | 
				
			||||||
												#endif
 | 
																	#endif
 | 
				
			||||||
												#else
 | 
																	#else
 | 
				
			||||||
				shadowMap, shadowMapTransparent
 | 
																	#ifndef _SingleAtlas
 | 
				
			||||||
 | 
																	shadowMapAtlasSun
 | 
				
			||||||
 | 
																	#else
 | 
				
			||||||
 | 
																	shadowMapAtlas
 | 
				
			||||||
 | 
																	#endif
 | 
				
			||||||
 | 
																	#endif
 | 
				
			||||||
 | 
																#else
 | 
				
			||||||
 | 
																#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																shadowMap, shadowMapTransparent
 | 
				
			||||||
 | 
																#else
 | 
				
			||||||
 | 
																shadowMap
 | 
				
			||||||
 | 
																#endif
 | 
				
			||||||
 | 
																#endif
 | 
				
			||||||
 | 
																, eye, p + n * shadowsBias * 10, shadowsBias
 | 
				
			||||||
 | 
																#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																, false
 | 
				
			||||||
											#endif
 | 
																#endif
 | 
				
			||||||
				, eye, p + n * shadowsBias * 10, shadowsBias, false
 | 
					 | 
				
			||||||
											);
 | 
																);
 | 
				
			||||||
		#else
 | 
							#else
 | 
				
			||||||
			vec4 lPos = LWVP * vec4(p + n * shadowsBias * 100, 1.0);
 | 
								vec4 lPos = LWVP * vec4(p + n * shadowsBias * 100, 1.0);
 | 
				
			||||||
			if (lPos.w > 0.0) {
 | 
								if (lPos.w > 0.0) {
 | 
				
			||||||
				svisibility = shadowTest(
 | 
									svisibility = shadowTest(
 | 
				
			||||||
										#ifdef _ShadowMapAtlas
 | 
															#ifdef _ShadowMapAtlas
 | 
				
			||||||
 | 
																#ifdef _ShadowMapTransparent
 | 
				
			||||||
											#ifndef _SingleAtlas
 | 
																#ifndef _SingleAtlas
 | 
				
			||||||
											shadowMapAtlasSun, shadowMapAtlasSunTransparent
 | 
																shadowMapAtlasSun, shadowMapAtlasSunTransparent
 | 
				
			||||||
											#else
 | 
																#else
 | 
				
			||||||
											shadowMapAtlas, shadowMapAtlasTransparent
 | 
																shadowMapAtlas, shadowMapAtlasTransparent
 | 
				
			||||||
											#endif
 | 
																#endif
 | 
				
			||||||
											#else
 | 
																#else
 | 
				
			||||||
					shadowMap, shadowMapTransparent
 | 
																#ifndef _SingleAtlas
 | 
				
			||||||
 | 
																shadowMapAtlasSun
 | 
				
			||||||
 | 
																#else
 | 
				
			||||||
 | 
																shadowMapAtlas
 | 
				
			||||||
 | 
																#endif
 | 
				
			||||||
 | 
																#endif
 | 
				
			||||||
 | 
															#else
 | 
				
			||||||
 | 
															#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
															shadowMap, shadowMapTransparent
 | 
				
			||||||
 | 
															#else
 | 
				
			||||||
 | 
															shadowMap
 | 
				
			||||||
 | 
															#endif
 | 
				
			||||||
 | 
															#endif
 | 
				
			||||||
 | 
															, lPos.xyz / lPos.w, shadowsBias
 | 
				
			||||||
 | 
															#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
															, false
 | 
				
			||||||
										#endif
 | 
															#endif
 | 
				
			||||||
					, lPos.xyz / lPos.w, shadowsBias, false
 | 
					 | 
				
			||||||
										);
 | 
															);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		#endif
 | 
							#endif
 | 
				
			||||||
	#endif
 | 
						#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	#ifdef _VoxelShadow
 | 
						#ifdef _VoxelShadow
 | 
				
			||||||
	svisibility *= (1.0 - traceShadow(p, n, voxels, voxelsSDF, sunDir, clipmaps, gl_FragCoord.xy, g2.rg).r) * voxelgiShad;
 | 
						svisibility *= (1.0 - traceShadow(p, n, voxels, voxelsSDF, sunDir, clipmaps, gl_FragCoord.xy, -g2.rg).r) * voxelgiShad;
 | 
				
			||||||
	#endif
 | 
						#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	#ifdef _SSRS
 | 
						#ifdef _SSRS
 | 
				
			||||||
@ -439,13 +501,16 @@ void main() {
 | 
				
			|||||||
	fragColor.rgb += sampleLight(
 | 
						fragColor.rgb += sampleLight(
 | 
				
			||||||
		p, n, v, dotNV, pointPos, pointCol, albedo, roughness, occspec.y, f0
 | 
							p, n, v, dotNV, pointPos, pointCol, albedo, roughness, occspec.y, f0
 | 
				
			||||||
		#ifdef _ShadowMap
 | 
							#ifdef _ShadowMap
 | 
				
			||||||
			, 0, pointBias, true, false
 | 
								, 0, pointBias, true
 | 
				
			||||||
 | 
							#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
								, false
 | 
				
			||||||
 | 
							#endif
 | 
				
			||||||
		#endif
 | 
							#endif
 | 
				
			||||||
		#ifdef _Spot
 | 
							#ifdef _Spot
 | 
				
			||||||
		, true, spotData.x, spotData.y, spotDir, spotData.zw, spotRight
 | 
							, true, spotData.x, spotData.y, spotDir, spotData.zw, spotRight
 | 
				
			||||||
		#endif
 | 
							#endif
 | 
				
			||||||
		#ifdef _VoxelShadow
 | 
							#ifdef _VoxelShadow
 | 
				
			||||||
			, voxels, voxelsSDF, clipmaps
 | 
								, voxels, voxelsSDF, clipmaps, -g2.rg
 | 
				
			||||||
		#endif
 | 
							#endif
 | 
				
			||||||
		#ifdef _MicroShadowing
 | 
							#ifdef _MicroShadowing
 | 
				
			||||||
		, occspec.x
 | 
							, occspec.x
 | 
				
			||||||
@ -492,7 +557,10 @@ void main() {
 | 
				
			|||||||
			f0
 | 
								f0
 | 
				
			||||||
			#ifdef _ShadowMap
 | 
								#ifdef _ShadowMap
 | 
				
			||||||
				// light index, shadow bias, cast_shadows
 | 
									// light index, shadow bias, cast_shadows
 | 
				
			||||||
				, li, lightsArray[li * 3 + 2].x, lightsArray[li * 3 + 2].z != 0.0, false
 | 
									, li, lightsArray[li * 3 + 2].x, lightsArray[li * 3 + 2].z != 0.0
 | 
				
			||||||
 | 
								#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
									, false
 | 
				
			||||||
 | 
								#endif
 | 
				
			||||||
			#endif
 | 
								#endif
 | 
				
			||||||
			#ifdef _Spot
 | 
								#ifdef _Spot
 | 
				
			||||||
			, lightsArray[li * 3 + 2].y != 0.0
 | 
								, lightsArray[li * 3 + 2].y != 0.0
 | 
				
			||||||
@ -503,7 +571,7 @@ void main() {
 | 
				
			|||||||
			, lightsArraySpot[li * 2 + 1].xyz // right
 | 
								, lightsArraySpot[li * 2 + 1].xyz // right
 | 
				
			||||||
			#endif
 | 
								#endif
 | 
				
			||||||
			#ifdef _VoxelShadow
 | 
								#ifdef _VoxelShadow
 | 
				
			||||||
			, voxels, voxelsSDF, clipmaps
 | 
								, voxels, voxelsSDF, clipmaps, -g2.rg
 | 
				
			||||||
			#endif
 | 
								#endif
 | 
				
			||||||
			#ifdef _MicroShadowing
 | 
								#ifdef _MicroShadowing
 | 
				
			||||||
			, occspec.x
 | 
								, occspec.x
 | 
				
			||||||
@ -514,14 +582,5 @@ void main() {
 | 
				
			|||||||
		);
 | 
							);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
#endif // _Clusters
 | 
					#endif // _Clusters
 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
#ifdef _VoxelRefract
 | 
					 | 
				
			||||||
if(opac < 1.0) {
 | 
					 | 
				
			||||||
	vec3 refraction = traceRefraction(p, n, voxels, v, ior, roughness, eye) * voxelgiRefr;
 | 
					 | 
				
			||||||
	fragColor.rgb = mix(refraction, fragColor.rgb, opac);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
*/
 | 
					 | 
				
			||||||
	fragColor.a = 1.0; // Mark as opaque
 | 
						fragColor.a = 1.0; // Mark as opaque
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -2,13 +2,22 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "compiled.inc"
 | 
					#include "compiled.inc"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef _CPostprocess
 | 
				
			||||||
 | 
					uniform vec3 PPComp8;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uniform sampler2D tex;
 | 
					uniform sampler2D tex;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
in vec2 texCoord;
 | 
					in vec2 texCoord;
 | 
				
			||||||
out vec4 fragColor;
 | 
					out vec4 fragColor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void main() {
 | 
					void main() {
 | 
				
			||||||
 | 
						#ifdef _CPostprocess
 | 
				
			||||||
 | 
							fragColor.a = 0.01 * PPComp8.z;
 | 
				
			||||||
 | 
						#else
 | 
				
			||||||
		fragColor.a = 0.01 * autoExposureSpeed;
 | 
							fragColor.a = 0.01 * autoExposureSpeed;
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fragColor.rgb = textureLod(tex, vec2(0.5, 0.5), 0.0).rgb +
 | 
						fragColor.rgb = textureLod(tex, vec2(0.5, 0.5), 0.0).rgb +
 | 
				
			||||||
					textureLod(tex, vec2(0.2, 0.2), 0.0).rgb +
 | 
										textureLod(tex, vec2(0.2, 0.2), 0.0).rgb +
 | 
				
			||||||
					textureLod(tex, vec2(0.8, 0.2), 0.0).rgb +
 | 
										textureLod(tex, vec2(0.8, 0.2), 0.0).rgb +
 | 
				
			||||||
 | 
				
			|||||||
@ -8,7 +8,13 @@
 | 
				
			|||||||
			"blend_source": "source_alpha",
 | 
								"blend_source": "source_alpha",
 | 
				
			||||||
			"blend_destination": "inverse_source_alpha",
 | 
								"blend_destination": "inverse_source_alpha",
 | 
				
			||||||
			"blend_operation": "add",
 | 
								"blend_operation": "add",
 | 
				
			||||||
			"links": [],
 | 
								"links": [
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										"name": "PPComp8",
 | 
				
			||||||
 | 
										"link": "_PPComp8",
 | 
				
			||||||
 | 
										"ifdef": ["_CPostprocess"]
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								],
 | 
				
			||||||
			"texture_params": [],
 | 
								"texture_params": [],
 | 
				
			||||||
			"vertex_shader": "../include/pass.vert.glsl",
 | 
								"vertex_shader": "../include/pass.vert.glsl",
 | 
				
			||||||
			"fragment_shader": "histogram_pass.frag.glsl"
 | 
								"fragment_shader": "histogram_pass.frag.glsl"
 | 
				
			||||||
 | 
				
			|||||||
@ -1,107 +1,506 @@
 | 
				
			|||||||
#version 450
 | 
					#version 450
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "compiled.inc"
 | 
					#include "compiled.inc"
 | 
				
			||||||
#include "std/math.glsl"
 | 
					 | 
				
			||||||
#include "std/gbuffer.glsl"
 | 
					#include "std/gbuffer.glsl"
 | 
				
			||||||
 | 
					#include "std/brdf.glsl"
 | 
				
			||||||
 | 
					#include "std/math.glsl"
 | 
				
			||||||
 | 
					#ifdef _Clusters
 | 
				
			||||||
 | 
					#include "std/clusters.glsl"
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef _ShadowMap
 | 
				
			||||||
 | 
					#include "std/shadows.glsl"
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef _LTC
 | 
				
			||||||
 | 
					#include "std/ltc.glsl"
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef _LightIES
 | 
				
			||||||
 | 
					#include "std/ies.glsl"
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef _Spot
 | 
				
			||||||
 | 
					#include "std/light_common.glsl"
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#include "std/constants.glsl"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uniform sampler2D gbuffer0;
 | 
				
			||||||
 | 
					uniform sampler2D gbuffer1;
 | 
				
			||||||
uniform sampler2D gbufferD;
 | 
					uniform sampler2D gbufferD;
 | 
				
			||||||
uniform sampler2D gbuffer0; // Normal
 | 
					#ifdef _EmissionShaded
 | 
				
			||||||
// #ifdef _RTGI
 | 
					uniform sampler2D gbufferEmission;
 | 
				
			||||||
// uniform sampler2D gbuffer1; // Basecol
 | 
					#endif
 | 
				
			||||||
// #endif
 | 
					uniform sampler2D sveloc;
 | 
				
			||||||
uniform mat4 P;
 | 
					 | 
				
			||||||
uniform mat3 V3;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
uniform vec2 cameraProj;
 | 
					uniform vec2 cameraProj;
 | 
				
			||||||
 | 
					uniform vec3 eye;
 | 
				
			||||||
 | 
					uniform vec3 eyeLook;
 | 
				
			||||||
 | 
					uniform vec2 screenSize;
 | 
				
			||||||
 | 
					uniform mat4 invVP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const float angleMix = 0.5f;
 | 
					in vec2 texCoord;
 | 
				
			||||||
#ifdef _SSGICone9
 | 
					in vec3 viewRay;
 | 
				
			||||||
const float strength = 2.0 * (1.0 / ssgiStrength);
 | 
					out vec3 fragColor;
 | 
				
			||||||
#else
 | 
					
 | 
				
			||||||
const float strength = 2.0 * (1.0 / ssgiStrength) * 1.8;
 | 
					float metallic;
 | 
				
			||||||
 | 
					uint matid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef _SMSizeUniform
 | 
				
			||||||
 | 
					//!uniform vec2 smSizeUniform;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
in vec3 viewRay;
 | 
					#ifdef _Clusters
 | 
				
			||||||
in vec2 texCoord;
 | 
					uniform vec4 lightsArray[maxLights * 3];
 | 
				
			||||||
out float fragColor;
 | 
						#ifdef _Spot
 | 
				
			||||||
 | 
						uniform vec4 lightsArraySpot[maxLights * 2];
 | 
				
			||||||
vec3 hitCoord;
 | 
					 | 
				
			||||||
vec2 coord;
 | 
					 | 
				
			||||||
float depth;
 | 
					 | 
				
			||||||
// #ifdef _RTGI
 | 
					 | 
				
			||||||
// vec3 col = vec3(0.0);
 | 
					 | 
				
			||||||
// #endif
 | 
					 | 
				
			||||||
vec3 vpos;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
vec2 getProjectedCoord(vec3 hitCoord) {
 | 
					 | 
				
			||||||
	vec4 projectedCoord = P * vec4(hitCoord, 1.0);
 | 
					 | 
				
			||||||
	projectedCoord.xy /= projectedCoord.w;
 | 
					 | 
				
			||||||
	projectedCoord.xy = projectedCoord.xy * 0.5 + 0.5;
 | 
					 | 
				
			||||||
	#ifdef _InvY
 | 
					 | 
				
			||||||
	projectedCoord.y = 1.0 - projectedCoord.y;
 | 
					 | 
				
			||||||
	#endif
 | 
						#endif
 | 
				
			||||||
	return projectedCoord.xy;
 | 
					uniform sampler2D clustersData;
 | 
				
			||||||
}
 | 
					uniform vec2 cameraPlane;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
float getDeltaDepth(vec3 hitCoord) {
 | 
					#ifdef _SinglePoint // Fast path for single light
 | 
				
			||||||
	coord = getProjectedCoord(hitCoord);
 | 
					uniform vec3 pointPos;
 | 
				
			||||||
	depth = textureLod(gbufferD, coord, 0.0).r * 2.0 - 1.0;
 | 
					uniform vec3 pointCol;
 | 
				
			||||||
	vec3 p = getPosView(viewRay, depth, cameraProj);
 | 
						#ifdef _ShadowMap
 | 
				
			||||||
	return p.z - hitCoord.z;
 | 
						uniform float pointBias;
 | 
				
			||||||
}
 | 
						#endif
 | 
				
			||||||
 | 
						#ifdef _Spot
 | 
				
			||||||
 | 
						uniform vec3 spotDir;
 | 
				
			||||||
 | 
						uniform vec3 spotRight;
 | 
				
			||||||
 | 
						uniform vec4 spotData;
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void rayCast(vec3 dir) {
 | 
					#ifdef _CPostprocess
 | 
				
			||||||
	hitCoord = vpos;
 | 
					    uniform vec3 PPComp12;
 | 
				
			||||||
	dir *= ssgiRayStep * 2;
 | 
					#endif
 | 
				
			||||||
	float dist = 0.15;
 | 
					
 | 
				
			||||||
	for (int i = 0; i < ssgiMaxSteps; i++) {
 | 
					#ifdef _ShadowMap
 | 
				
			||||||
		hitCoord += dir;
 | 
						#ifdef _SinglePoint
 | 
				
			||||||
		float delta = getDeltaDepth(hitCoord);
 | 
							#ifdef _Spot
 | 
				
			||||||
		if (delta > 0.0 && delta < 0.2) {
 | 
								#ifndef _LTC
 | 
				
			||||||
			dist = distance(vpos, hitCoord);
 | 
									uniform sampler2DShadow shadowMapSpot[1];
 | 
				
			||||||
			break;
 | 
									uniform sampler2D shadowMapSpotTransparent[1];
 | 
				
			||||||
 | 
									uniform mat4 LWVPSpot[1];
 | 
				
			||||||
 | 
								#endif
 | 
				
			||||||
 | 
							#else
 | 
				
			||||||
 | 
								uniform samplerCubeShadow shadowMapPoint[1];
 | 
				
			||||||
 | 
								uniform samplerCube shadowMapPointTransparent[1];
 | 
				
			||||||
 | 
								uniform vec2 lightProj;
 | 
				
			||||||
 | 
							#endif
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
						#ifdef _Clusters
 | 
				
			||||||
 | 
							#ifdef _SingleAtlas
 | 
				
			||||||
 | 
							uniform sampler2DShadow shadowMapAtlas;
 | 
				
			||||||
 | 
							uniform sampler2D shadowMapAtlasTransparent;
 | 
				
			||||||
 | 
							#endif
 | 
				
			||||||
 | 
							uniform vec2 lightProj;
 | 
				
			||||||
 | 
							#ifdef _ShadowMapAtlas
 | 
				
			||||||
 | 
							#ifndef _SingleAtlas
 | 
				
			||||||
 | 
							uniform sampler2DShadow shadowMapAtlasPoint;
 | 
				
			||||||
 | 
							uniform sampler2D shadowMapAtlasPointTransparent;
 | 
				
			||||||
 | 
							//!uniform vec4 pointLightDataArray[maxLightsCluster * 6];
 | 
				
			||||||
 | 
							#else
 | 
				
			||||||
 | 
							uniform samplerCubeShadow shadowMapPoint[4];
 | 
				
			||||||
 | 
							uniform samplerCube shadowMapPointTransparent[4];
 | 
				
			||||||
 | 
							#endif
 | 
				
			||||||
 | 
							#endif
 | 
				
			||||||
 | 
							#ifdef _Spot
 | 
				
			||||||
 | 
								#ifdef _ShadowMapAtlas
 | 
				
			||||||
 | 
								#ifndef _SingleAtlas
 | 
				
			||||||
 | 
								uniform sampler2DShadow shadowMapAtlasSpot;
 | 
				
			||||||
 | 
								uniform sampler2D shadowMapAtlasSpotTransparent;
 | 
				
			||||||
 | 
								#endif
 | 
				
			||||||
 | 
								#else
 | 
				
			||||||
 | 
								uniform sampler2DShadow shadowMapSpot[4];
 | 
				
			||||||
 | 
								uniform sampler2D shadowMapSpotTransparent[4];
 | 
				
			||||||
 | 
								#endif
 | 
				
			||||||
 | 
								uniform mat4 LWVPSpotArray[maxLightsCluster];
 | 
				
			||||||
 | 
							#endif
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef _LTC
 | 
				
			||||||
 | 
					uniform vec3 lightArea0;
 | 
				
			||||||
 | 
					uniform vec3 lightArea1;
 | 
				
			||||||
 | 
					uniform vec3 lightArea2;
 | 
				
			||||||
 | 
					uniform vec3 lightArea3;
 | 
				
			||||||
 | 
					uniform sampler2D sltcMat;
 | 
				
			||||||
 | 
					uniform sampler2D sltcMag;
 | 
				
			||||||
 | 
					#ifdef _ShadowMap
 | 
				
			||||||
 | 
					#ifndef _Spot
 | 
				
			||||||
 | 
						#ifdef _SinglePoint
 | 
				
			||||||
 | 
							uniform sampler2DShadow shadowMapSpot[1];
 | 
				
			||||||
 | 
							uniform sampler2D shadowMapSpotTransparent[1];
 | 
				
			||||||
 | 
							uniform mat4 LWVPSpot[1];
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
						#ifdef _Clusters
 | 
				
			||||||
 | 
							uniform sampler2DShadow shadowMapSpot[maxLightsCluster];
 | 
				
			||||||
 | 
							uniform mat4 LWVPSpotArray[maxLightsCluster];
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef _Sun
 | 
				
			||||||
 | 
					uniform vec3 sunDir;
 | 
				
			||||||
 | 
					uniform vec3 sunCol;
 | 
				
			||||||
 | 
						#ifdef _ShadowMap
 | 
				
			||||||
 | 
						#ifdef _ShadowMapAtlas
 | 
				
			||||||
 | 
						#ifndef _SingleAtlas
 | 
				
			||||||
 | 
						uniform sampler2DShadow shadowMapAtlasSun;
 | 
				
			||||||
 | 
						uniform sampler2D shadowMapAtlasSunTransparent;
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
						#else
 | 
				
			||||||
 | 
						uniform sampler2DShadow shadowMap;
 | 
				
			||||||
 | 
						uniform sampler2D shadowMapTransparent;
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
						uniform float shadowsBias;
 | 
				
			||||||
 | 
						#ifdef _CSM
 | 
				
			||||||
 | 
						//!uniform vec4 casData[shadowmapCascades * 4 + 4];
 | 
				
			||||||
 | 
						#else
 | 
				
			||||||
 | 
						uniform mat4 LWVP;
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
						#endif // _ShadowMap
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					vec3 sampleLight(const vec3 p, const vec3 n, const vec3 lp, const vec3 lightCol
 | 
				
			||||||
 | 
						#ifdef _ShadowMap
 | 
				
			||||||
 | 
							, int index, float bias, bool receiveShadow, bool transparent
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
						#ifdef _Spot
 | 
				
			||||||
 | 
							, const bool isSpot, const float spotSize, float spotBlend, vec3 spotDir, vec2 scale, vec3 right
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vec3 ld = lp - p;
 | 
				
			||||||
 | 
						vec3 l = normalize(ld);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vec3 visibility = lightCol;
 | 
				
			||||||
 | 
						visibility *= attenuate(distance(p, lp));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#ifdef _LTC
 | 
				
			||||||
 | 
						#ifdef _ShadowMap
 | 
				
			||||||
 | 
							if (receiveShadow) {
 | 
				
			||||||
 | 
								#ifdef _SinglePoint
 | 
				
			||||||
 | 
								vec4 lPos = LWVPSpotArray[0] * vec4(p + n * bias * 10, 1.0);
 | 
				
			||||||
 | 
								visibility *= shadowTest(shadowMapSpot[0],
 | 
				
			||||||
 | 
												shadowMapSpotTransparent[0],
 | 
				
			||||||
 | 
												lPos.xyz / lPos.w, bias, transparent);
 | 
				
			||||||
 | 
								#endif
 | 
				
			||||||
 | 
								#ifdef _Clusters
 | 
				
			||||||
 | 
								vec4 lPos = LWVPSpotArray[index] * vec4(p + n * bias * 10, 1.0);
 | 
				
			||||||
 | 
								if (index == 0) visibility *= shadowTest(shadowMapSpot[0],
 | 
				
			||||||
 | 
										shadowMapSpotTransparent[0],
 | 
				
			||||||
 | 
										lPos.xyz / lPos.w, bias, transparent);
 | 
				
			||||||
 | 
								else if (index == 1) visibility *= shadowTest(shadowMapSpot[1],
 | 
				
			||||||
 | 
										shadowMapSpotTransparent[1],
 | 
				
			||||||
 | 
										, lPos.xyz / lPos.w, bias, transparent);
 | 
				
			||||||
 | 
								else if (index == 2) visibility *= shadowTest(shadowMapSpot[2],
 | 
				
			||||||
 | 
										shadowMapSpotTransparent[2],
 | 
				
			||||||
 | 
										lPos.xyz / lPos.w, bias, transparent);
 | 
				
			||||||
 | 
								else if (index == 3) visibility *= shadowTest(shadowMapSpot[3],
 | 
				
			||||||
 | 
										shadowMapSpotTransparent[3],
 | 
				
			||||||
 | 
										lPos.xyz / lPos.w, bias, transparent);
 | 
				
			||||||
 | 
								#endif
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
						return visibility;
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#ifdef _Spot
 | 
				
			||||||
 | 
						if (isSpot) {
 | 
				
			||||||
 | 
							visibility *= spotlightMask(l, spotDir, right, scale, spotSize, spotBlend);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							#ifdef _ShadowMap
 | 
				
			||||||
 | 
								if (receiveShadow) {
 | 
				
			||||||
 | 
									#ifdef _SinglePoint
 | 
				
			||||||
 | 
									vec4 lPos = LWVPSpot[0] * vec4(p + n * bias * 10, 1.0);
 | 
				
			||||||
 | 
									visibility *= shadowTest(shadowMapSpot[0],
 | 
				
			||||||
 | 
														 shadowMapSpotTransparent[0],
 | 
				
			||||||
 | 
														lPos.xyz / lPos.w, bias, transparent);
 | 
				
			||||||
 | 
									#endif
 | 
				
			||||||
 | 
									#ifdef _Clusters
 | 
				
			||||||
 | 
										vec4 lPos = LWVPSpotArray[index] * vec4(p + n * bias * 10, 1.0);
 | 
				
			||||||
 | 
										#ifdef _ShadowMapAtlas
 | 
				
			||||||
 | 
											visibility *= shadowTest(
 | 
				
			||||||
 | 
												#ifndef _SingleAtlas
 | 
				
			||||||
 | 
												shadowMapAtlasSpot, shadowMapAtlasSpotTransparent
 | 
				
			||||||
 | 
												#else
 | 
				
			||||||
 | 
												shadowMapAtlas, shadowMapAtlasTransparent
 | 
				
			||||||
 | 
												#endif
 | 
				
			||||||
 | 
												, lPos.xyz / lPos.w, bias, transparent
 | 
				
			||||||
 | 
											);
 | 
				
			||||||
 | 
										#else
 | 
				
			||||||
 | 
												 if (index == 0) visibility *= shadowTest(shadowMapSpot[0],
 | 
				
			||||||
 | 
														shadowMapSpotTransparent[0],
 | 
				
			||||||
 | 
														lPos.xyz / lPos.w, bias, transparent);
 | 
				
			||||||
 | 
											else if (index == 1) visibility *= shadowTest(shadowMapSpot[1],
 | 
				
			||||||
 | 
														shadowMapSpotTransparent[1],
 | 
				
			||||||
 | 
														lPos.xyz / lPos.w, bias, transparent);
 | 
				
			||||||
 | 
											else if (index == 2) visibility *= shadowTest(shadowMapSpot[2],
 | 
				
			||||||
 | 
														shadowMapSpotTransparent[2],
 | 
				
			||||||
 | 
														lPos.xyz / lPos.w, bias, transparent);
 | 
				
			||||||
 | 
											else if (index == 3) visibility *= shadowTest(shadowMapSpot[3],
 | 
				
			||||||
 | 
														shadowMapSpotTransparent[3],
 | 
				
			||||||
 | 
														lPos.xyz / lPos.w, bias, transparent);
 | 
				
			||||||
 | 
										#endif
 | 
				
			||||||
 | 
									#endif
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
	fragColor += dist;
 | 
							#endif
 | 
				
			||||||
	// #ifdef _RTGI
 | 
							return visibility;
 | 
				
			||||||
	// col += textureLod(gbuffer1, coord, 0.0).rgb * ((ssgiRayStep * ssgiMaxSteps) - dist);
 | 
						}
 | 
				
			||||||
	// #endif
 | 
						#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#ifdef _LightIES
 | 
				
			||||||
 | 
						visibility *= iesAttenuation(-l);
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#ifdef _ShadowMap
 | 
				
			||||||
 | 
							if (receiveShadow) {
 | 
				
			||||||
 | 
								#ifdef _SinglePoint
 | 
				
			||||||
 | 
								#ifndef _Spot
 | 
				
			||||||
 | 
								visibility *= PCFCube(shadowMapPoint[0],
 | 
				
			||||||
 | 
												shadowMapPointTransparent[0],
 | 
				
			||||||
 | 
												ld, -l, bias, lightProj, n, transparent);
 | 
				
			||||||
 | 
								#endif
 | 
				
			||||||
 | 
								#endif
 | 
				
			||||||
 | 
								#ifdef _Clusters
 | 
				
			||||||
 | 
									#ifdef _ShadowMapAtlas
 | 
				
			||||||
 | 
									visibility *= PCFFakeCube(
 | 
				
			||||||
 | 
										#ifndef _SingleAtlas
 | 
				
			||||||
 | 
										shadowMapAtlasPoint, shadowMapAtlasPointTransparent
 | 
				
			||||||
 | 
										#else
 | 
				
			||||||
 | 
										shadowMapAtlas, shadowMapAtlasTransparent
 | 
				
			||||||
 | 
										#endif
 | 
				
			||||||
 | 
										, ld, -l, bias, lightProj, n, index, transparent
 | 
				
			||||||
 | 
									);
 | 
				
			||||||
 | 
									#else
 | 
				
			||||||
 | 
										 if (index == 0) visibility *= PCFCube(shadowMapPoint[0],
 | 
				
			||||||
 | 
													shadowMapPointTransparent[0],
 | 
				
			||||||
 | 
													ld, -l, bias, lightProj, n, transparent);
 | 
				
			||||||
 | 
									else if (index == 1) visibility *= PCFCube(shadowMapPoint[1],
 | 
				
			||||||
 | 
													shadowMapPointTransparent[1],
 | 
				
			||||||
 | 
													ld, -l, bias, lightProj, n, transparent);
 | 
				
			||||||
 | 
									else if (index == 2) visibility *= PCFCube(shadowMapPoint[2],
 | 
				
			||||||
 | 
													shadowMapPointTransparent[2],
 | 
				
			||||||
 | 
													ld, -l, bias, lightProj, n, transparent);
 | 
				
			||||||
 | 
									else if (index == 3) visibility *= PCFCube(shadowMapPoint[3],
 | 
				
			||||||
 | 
													shadowMapPointTransparent[3],
 | 
				
			||||||
 | 
													ld, -l, bias, lightProj, n, transparent);
 | 
				
			||||||
 | 
									#endif
 | 
				
			||||||
 | 
								#endif
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return visibility;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
vec3 tangent(const vec3 n) {
 | 
					vec3 getVisibility(vec3 p, vec3 n, float depth, vec2 uv) {
 | 
				
			||||||
	vec3 t1 = cross(n, vec3(0, 0, 1));
 | 
							vec3 visibility = vec3(0.0);
 | 
				
			||||||
	vec3 t2 = cross(n, vec3(0, 1, 0));
 | 
					#ifdef _Sun
 | 
				
			||||||
	if (length(t1) > length(t2)) return normalize(t1);
 | 
						#ifdef _ShadowMap
 | 
				
			||||||
	else return normalize(t2);
 | 
							#ifdef _CSM
 | 
				
			||||||
 | 
								visibility = shadowTestCascade(
 | 
				
			||||||
 | 
									#ifdef _ShadowMapAtlas
 | 
				
			||||||
 | 
										#ifndef _SingleAtlas
 | 
				
			||||||
 | 
										shadowMapAtlasSun, shadowMapAtlasSunTransparent
 | 
				
			||||||
 | 
										#else
 | 
				
			||||||
 | 
										shadowMapAtlas, shadowMapAtlasTransparent
 | 
				
			||||||
 | 
										#endif
 | 
				
			||||||
 | 
									#else
 | 
				
			||||||
 | 
									shadowMap, shadowMapTransparent
 | 
				
			||||||
 | 
									#endif
 | 
				
			||||||
 | 
									, eye, p + n * shadowsBias * 10, shadowsBias, false
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							#else
 | 
				
			||||||
 | 
								vec4 lPos = LWVP * vec4(p + n * shadowsBias * 100, 1.0);
 | 
				
			||||||
 | 
								if (lPos.w > 0.0) {
 | 
				
			||||||
 | 
									visibility = shadowTest(
 | 
				
			||||||
 | 
										#ifdef _ShadowMapAtlas
 | 
				
			||||||
 | 
											#ifndef _SingleAtlas
 | 
				
			||||||
 | 
											shadowMapAtlasSun, shadowMapAtlasSunTransparent
 | 
				
			||||||
 | 
											#else
 | 
				
			||||||
 | 
											shadowMapAtlas, shadowMapAtlasTransparent
 | 
				
			||||||
 | 
											#endif
 | 
				
			||||||
 | 
										#else
 | 
				
			||||||
 | 
										shadowMap, shadowMapTransparent
 | 
				
			||||||
 | 
										#endif
 | 
				
			||||||
 | 
										, lPos.xyz / lPos.w, shadowsBias, false
 | 
				
			||||||
 | 
									);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							#endif
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef _SinglePoint
 | 
				
			||||||
 | 
						visibility += sampleLight(
 | 
				
			||||||
 | 
							p, n, pointPos, pointCol
 | 
				
			||||||
 | 
							#ifdef _ShadowMap
 | 
				
			||||||
 | 
								, 0, pointBias, true, false
 | 
				
			||||||
 | 
							#endif
 | 
				
			||||||
 | 
							#ifdef _Spot
 | 
				
			||||||
 | 
							, true, spotData.x, spotData.y, spotDir, spotData.zw, spotRight
 | 
				
			||||||
 | 
							#endif
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef _Clusters
 | 
				
			||||||
 | 
						float viewz = linearize(depth, cameraProj);
 | 
				
			||||||
 | 
						int clusterI = getClusterI(uv, viewz, cameraPlane);
 | 
				
			||||||
 | 
						int numLights = int(texelFetch(clustersData, ivec2(clusterI, 0), 0).r * 255);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#ifdef HLSL
 | 
				
			||||||
 | 
						viewz += textureLod(clustersData, vec2(0.0), 0.0).r * 1e-9; // TODO: krafix bug, needs to generate sampler
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#ifdef _Spot
 | 
				
			||||||
 | 
						int numSpots = int(texelFetch(clustersData, ivec2(clusterI, 1 + maxLightsCluster), 0).r * 255);
 | 
				
			||||||
 | 
						int numPoints = numLights - numSpots;
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (int i = 0; i < min(numLights, maxLightsCluster); i++) {
 | 
				
			||||||
 | 
							int li = int(texelFetch(clustersData, ivec2(clusterI, i + 1), 0).r * 255);
 | 
				
			||||||
 | 
							visibility += sampleLight(
 | 
				
			||||||
 | 
								p,
 | 
				
			||||||
 | 
								n,
 | 
				
			||||||
 | 
								lightsArray[li * 3].xyz, // lp
 | 
				
			||||||
 | 
								lightsArray[li * 3 + 1].xyz // lightCol
 | 
				
			||||||
 | 
								#ifdef _ShadowMap
 | 
				
			||||||
 | 
									// light index, shadow bias, cast_shadows
 | 
				
			||||||
 | 
									, li, lightsArray[li * 3 + 2].x, lightsArray[li * 3 + 2].z != 0.0, false
 | 
				
			||||||
 | 
								#endif
 | 
				
			||||||
 | 
								#ifdef _Spot
 | 
				
			||||||
 | 
								, lightsArray[li * 3 + 2].y != 0.0
 | 
				
			||||||
 | 
								, lightsArray[li * 3 + 2].y // spot size (cutoff)
 | 
				
			||||||
 | 
								, lightsArraySpot[li * 2].w // spot blend (exponent)
 | 
				
			||||||
 | 
								, lightsArraySpot[li * 2].xyz // spotDir
 | 
				
			||||||
 | 
								, vec2(lightsArray[li * 3].w, lightsArray[li * 3 + 1].w) // scale
 | 
				
			||||||
 | 
								, lightsArraySpot[li * 2 + 1].xyz // right
 | 
				
			||||||
 | 
								#endif
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#endif // _Clusters
 | 
				
			||||||
 | 
						return visibility;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void main() {
 | 
					vec3 getWorldPos(vec2 uv, float depth) {
 | 
				
			||||||
	fragColor = 0;
 | 
					    vec4 pos = invVP * vec4(uv * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);
 | 
				
			||||||
	vec4 g0 = textureLod(gbuffer0, texCoord, 0.0);
 | 
					    return pos.xyz / pos.w;
 | 
				
			||||||
	float d = textureLod(gbufferD, texCoord, 0.0).r * 2.0 - 1.0;
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					vec3 getNormal(vec2 uv) {
 | 
				
			||||||
 | 
					    vec4 g0 = textureLod(gbuffer0, uv, 0.0);
 | 
				
			||||||
    vec2 enc = g0.rg;
 | 
					    vec2 enc = g0.rg;
 | 
				
			||||||
    vec3 n;
 | 
					    vec3 n;
 | 
				
			||||||
    n.z = 1.0 - abs(enc.x) - abs(enc.y);
 | 
					    n.z = 1.0 - abs(enc.x) - abs(enc.y);
 | 
				
			||||||
    n.xy = n.z >= 0.0 ? enc.xy : octahedronWrap(enc.xy);
 | 
					    n.xy = n.z >= 0.0 ? enc.xy : octahedronWrap(enc.xy);
 | 
				
			||||||
	n = normalize(V3 * n);
 | 
					    return normalize(n);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
	vpos = getPosView(viewRay, d, cameraProj);
 | 
					
 | 
				
			||||||
 | 
					vec3 calculateIndirectLight(vec2 uv, vec3 pos, vec3 normal, float depth) {
 | 
				
			||||||
	rayCast(n);
 | 
					    // Simplified visibility - replace with your full visibility function if needed
 | 
				
			||||||
	vec3 o1 = normalize(tangent(n));
 | 
					    vec3 sampleColor = textureLod(gbuffer1, uv, 0.0).rgb * getVisibility(pos, normal, depth, uv);
 | 
				
			||||||
	vec3 o2 = (cross(o1, n));
 | 
					
 | 
				
			||||||
	vec3 c1 = 0.5f * (o1 + o2);
 | 
						#ifdef _EmissionShadeless
 | 
				
			||||||
	vec3 c2 = 0.5f * (o1 - o2);
 | 
							if (matid == 1) { // pure emissive material, color stored in basecol
 | 
				
			||||||
	rayCast(mix(n, o1, angleMix));
 | 
								sampleColor += textureLod(gbuffer1, uv, 0.0).rgb;
 | 
				
			||||||
	rayCast(mix(n, o2, angleMix));
 | 
							}
 | 
				
			||||||
	rayCast(mix(n, -c1, angleMix));
 | 
						#endif
 | 
				
			||||||
	rayCast(mix(n, -c2, angleMix));
 | 
						#ifdef _EmissionShaded
 | 
				
			||||||
 | 
							#ifdef _EmissionShadeless
 | 
				
			||||||
	#ifdef _SSGICone9
 | 
							else {
 | 
				
			||||||
	rayCast(mix(n, -o1, angleMix));
 | 
							#endif
 | 
				
			||||||
	rayCast(mix(n, -o2, angleMix));
 | 
								vec3 sampleEmission = textureLod(gbufferEmission, uv, 0.0).rgb;
 | 
				
			||||||
	rayCast(mix(n, c1, angleMix));
 | 
								sampleColor += sampleEmission; // Emission should be added directly
 | 
				
			||||||
	rayCast(mix(n, c2, angleMix));
 | 
							#ifdef _EmissionShadeless
 | 
				
			||||||
	#endif
 | 
							}
 | 
				
			||||||
 | 
							#endif
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return sampleColor;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Improved sampling parameters
 | 
				
			||||||
 | 
					const float GOLDEN_ANGLE = 2.39996323;
 | 
				
			||||||
 | 
					const float MAX_DEPTH_DIFFERENCE = 0.9; // More conservative depth threshold
 | 
				
			||||||
 | 
					const float SAMPLE_BIAS = 0.01; // Small offset to avoid self-occlusion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void main() {
 | 
				
			||||||
 | 
					    float depth = textureLod(gbufferD, texCoord, 0.0).r;
 | 
				
			||||||
 | 
					    if (depth >= 1.0) {
 | 
				
			||||||
 | 
					        fragColor = vec3(0.0);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vec4 g0 = textureLod(gbuffer0, texCoord, 0.0); // Normal.xy, roughness, metallic/matid
 | 
				
			||||||
 | 
						unpackFloatInt16(g0.a, metallic, matid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vec2 velocity = -textureLod(sveloc, texCoord, 0.0).rg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vec3 n;
 | 
				
			||||||
 | 
						n.z = 1.0 - abs(g0.x) - abs(g0.y);
 | 
				
			||||||
 | 
						n.xy = n.z >= 0.0 ? g0.xy : octahedronWrap(g0.xy);
 | 
				
			||||||
 | 
						n = normalize(n);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vec3 pos = getWorldPos(texCoord, depth);
 | 
				
			||||||
 | 
					    vec3 normal = getNormal(texCoord);
 | 
				
			||||||
 | 
					    vec3 centerColor = textureLod(gbuffer1, texCoord, 0.0).rgb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    float radius = ssaoRadius;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vec3 gi = vec3(0.0);
 | 
				
			||||||
 | 
					    float totalWeight = 0.0;
 | 
				
			||||||
 | 
					    float angle = fract(sin(dot(texCoord, vec2(12.9898, 78.233))) * 100.0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (int i = 0; i < ssgiSamples; i++) {
 | 
				
			||||||
 | 
							// Use quasi-random sequence for better coverage
 | 
				
			||||||
 | 
							float r = sqrt((float(i) + 0.5) / float(ssgiSamples)) * radius;
 | 
				
			||||||
 | 
							float a = (float(i) * GOLDEN_ANGLE) + angle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							vec2 offset = vec2(cos(a), sin(a)) * r * radius;
 | 
				
			||||||
 | 
							vec2 sampleUV = clamp(texCoord + offset * (BayerMatrix8[int(gl_FragCoord.x + velocity.x) % 8][int(gl_FragCoord.y + velocity.y) % 8] - 0.5) / screenSize, vec2(0.001), vec2(0.999));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							float sampleDepth = textureLod(gbufferD, sampleUV, 0.0).r;
 | 
				
			||||||
 | 
							if (sampleDepth >= 1.0) continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							vec3 samplePos = getWorldPos(sampleUV, sampleDepth);
 | 
				
			||||||
 | 
							vec3 sampleNormal = getNormal(sampleUV);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Apply small bias to sample position to avoid self-occlusion
 | 
				
			||||||
 | 
							samplePos += sampleNormal * SAMPLE_BIAS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							vec3 dir = pos - samplePos;
 | 
				
			||||||
 | 
							float dist = length(dir);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (abs(pos.z - samplePos.z) > MAX_DEPTH_DIFFERENCE) continue;;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							vec3 sampleColor = calculateIndirectLight(sampleUV, samplePos, sampleNormal, sampleDepth);
 | 
				
			||||||
 | 
							float weight = 1.0 / (1.0 + dist * dist * 2.0) * max(dot(sampleNormal, n), 0.0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							gi += sampleColor * weight;
 | 
				
			||||||
 | 
							totalWeight += weight;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Normalize and apply intensity
 | 
				
			||||||
 | 
					    if (totalWeight > 0.0) {
 | 
				
			||||||
 | 
					        gi /= totalWeight;
 | 
				
			||||||
 | 
					        #ifdef _CPostprocess
 | 
				
			||||||
 | 
					            gi *= PPComp12.x;
 | 
				
			||||||
 | 
					        #else
 | 
				
			||||||
 | 
					            gi *= ssaoStrength;
 | 
				
			||||||
 | 
					        #endif
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#ifdef _EmissionShadeless
 | 
				
			||||||
 | 
							if (matid == 1) { // pure emissive material, color stored in basecol
 | 
				
			||||||
 | 
								gi += textureLod(gbuffer1, texCoord, 0.0).rgb;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
						#ifdef _EmissionShaded
 | 
				
			||||||
 | 
							#ifdef _EmissionShadeless
 | 
				
			||||||
 | 
							else {
 | 
				
			||||||
 | 
							#endif
 | 
				
			||||||
 | 
								gi += textureLod(gbufferEmission, texCoord, 0.0).rgb;
 | 
				
			||||||
 | 
							#ifdef _EmissionShadeless
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							#endif
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
						fragColor = gi / (gi + vec3(1.0)); // Reinhard tone mapping
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -6,6 +6,10 @@
 | 
				
			|||||||
			"compare_mode": "always",
 | 
								"compare_mode": "always",
 | 
				
			||||||
			"cull_mode": "none",
 | 
								"cull_mode": "none",
 | 
				
			||||||
			"links": [
 | 
								"links": [
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										"name": "invVP",
 | 
				
			||||||
 | 
										"link": "_inverseViewProjectionMatrix"
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					"name": "P",
 | 
										"name": "P",
 | 
				
			||||||
					"link": "_projectionMatrix"
 | 
										"link": "_projectionMatrix"
 | 
				
			||||||
@ -15,16 +19,180 @@
 | 
				
			|||||||
					"link": "_viewMatrix3"
 | 
										"link": "_viewMatrix3"
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					"name": "invP",
 | 
										"name": "eye",
 | 
				
			||||||
					"link": "_inverseProjectionMatrix"
 | 
										"link": "_cameraPosition"
 | 
				
			||||||
 | 
									},				
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										"name": "eyeLook",
 | 
				
			||||||
 | 
										"link": "_cameraLook"
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					"name": "cameraProj",
 | 
										"name": "cameraProj",
 | 
				
			||||||
					"link": "_cameraPlaneProj"
 | 
										"link": "_cameraPlaneProj"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										"name": "screenSize",
 | 
				
			||||||
 | 
										"link": "_screenSize"
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										"name": "PPComp12",
 | 
				
			||||||
 | 
										"link": "_PPComp12",
 | 
				
			||||||
 | 
										"ifdef": ["_CPostprocess"]
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										"name": "lightsArraySpot",
 | 
				
			||||||
 | 
										"link": "_lightsArraySpot",
 | 
				
			||||||
 | 
										"ifdef": ["_Clusters", "_Spot"]
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										"name": "lightsArray",
 | 
				
			||||||
 | 
										"link": "_lightsArray",
 | 
				
			||||||
 | 
										"ifdef": ["_Clusters"]
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										"name": "clustersData",
 | 
				
			||||||
 | 
										"link": "_clustersData",
 | 
				
			||||||
 | 
										"ifdef": ["_Clusters"]
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										"name": "cameraPlane",
 | 
				
			||||||
 | 
										"link": "_cameraPlane",
 | 
				
			||||||
 | 
										"ifdef": ["_Clusters"]
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										"name": "sunDir",
 | 
				
			||||||
 | 
										"link": "_sunDirection",
 | 
				
			||||||
 | 
										"ifdef": ["_Sun"]
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										"name": "sunCol",
 | 
				
			||||||
 | 
										"link": "_sunColor",
 | 
				
			||||||
 | 
										"ifdef": ["_Sun"]
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										"name": "shadowsBias",
 | 
				
			||||||
 | 
										"link": "_sunShadowsBias",
 | 
				
			||||||
 | 
										"ifdef": ["_Sun", "_ShadowMap"]
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										"name": "LWVP",
 | 
				
			||||||
 | 
										"link": "_biasLightWorldViewProjectionMatrixSun",
 | 
				
			||||||
 | 
										"ifndef": ["_CSM"],
 | 
				
			||||||
 | 
										"ifdef": ["_Sun", "_ShadowMap"]
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										"name": "casData",
 | 
				
			||||||
 | 
										"link": "_cascadeData",
 | 
				
			||||||
 | 
										"ifdef": ["_Sun", "_ShadowMap", "_CSM"]
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										"name": "lightArea0",
 | 
				
			||||||
 | 
										"link": "_lightArea0",
 | 
				
			||||||
 | 
										"ifdef": ["_LTC"]
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										"name": "lightArea1",
 | 
				
			||||||
 | 
										"link": "_lightArea1",
 | 
				
			||||||
 | 
										"ifdef": ["_LTC"]
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										"name": "lightArea2",
 | 
				
			||||||
 | 
										"link": "_lightArea2",
 | 
				
			||||||
 | 
										"ifdef": ["_LTC"]
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										"name": "lightArea3",
 | 
				
			||||||
 | 
										"link": "_lightArea3",
 | 
				
			||||||
 | 
										"ifdef": ["_LTC"]
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										"name": "sltcMat",
 | 
				
			||||||
 | 
										"link": "_ltcMat",
 | 
				
			||||||
 | 
										"ifdef": ["_LTC"]
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										"name": "sltcMag",
 | 
				
			||||||
 | 
										"link": "_ltcMag",
 | 
				
			||||||
 | 
										"ifdef": ["_LTC"]
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										"name": "smSizeUniform",
 | 
				
			||||||
 | 
										"link": "_shadowMapSize",
 | 
				
			||||||
 | 
										"ifdef": ["_SMSizeUniform"]
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										"name": "lightProj",
 | 
				
			||||||
 | 
										"link": "_lightPlaneProj",
 | 
				
			||||||
 | 
										"ifdef": ["_ShadowMap"]
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										"name": "pointPos",
 | 
				
			||||||
 | 
										"link": "_pointPosition",
 | 
				
			||||||
 | 
										"ifdef": ["_SinglePoint"]
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										"name": "pointCol",
 | 
				
			||||||
 | 
										"link": "_pointColor",
 | 
				
			||||||
 | 
										"ifdef": ["_SinglePoint"]
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										"name": "pointBias",
 | 
				
			||||||
 | 
										"link": "_pointShadowsBias",
 | 
				
			||||||
 | 
										"ifdef": ["_SinglePoint", "_ShadowMap"]
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										"name": "spotDir",
 | 
				
			||||||
 | 
										"link": "_spotDirection",
 | 
				
			||||||
 | 
										"ifdef": ["_SinglePoint", "_Spot"]
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										"name": "spotData",
 | 
				
			||||||
 | 
										"link": "_spotData",
 | 
				
			||||||
 | 
										"ifdef": ["_SinglePoint", "_Spot"]
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										"name": "spotRight",
 | 
				
			||||||
 | 
										"link": "_spotRight",
 | 
				
			||||||
 | 
										"ifdef": ["_SinglePoint", "_Spot"]
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										"name": "LWVPSpotArray",
 | 
				
			||||||
 | 
										"link": "_biasLightWorldViewProjectionMatrixSpotArray",
 | 
				
			||||||
 | 
										"ifdef": ["_Clusters", "_ShadowMap", "_Spot"]
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										"name": "pointLightDataArray",
 | 
				
			||||||
 | 
										"link": "_pointLightsAtlasArray",
 | 
				
			||||||
 | 
										"ifdef": ["_Clusters", "_ShadowMap", "_ShadowMapAtlas"]
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										"name": "LWVPSpot[0]",
 | 
				
			||||||
 | 
										"link": "_biasLightWorldViewProjectionMatrixSpot0",
 | 
				
			||||||
 | 
										"ifndef": ["_ShadowMapAtlas"],
 | 
				
			||||||
 | 
										"ifdef": ["_LTC", "_ShadowMap"]
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										"name": "LWVPSpot[1]",
 | 
				
			||||||
 | 
										"link": "_biasLightWorldViewProjectionMatrixSpot1",
 | 
				
			||||||
 | 
										"ifndef": ["_ShadowMapAtlas"],
 | 
				
			||||||
 | 
										"ifdef": ["_LTC", "_ShadowMap"]
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										"name": "LWVPSpot[2]",
 | 
				
			||||||
 | 
										"link": "_biasLightWorldViewProjectionMatrixSpot2",
 | 
				
			||||||
 | 
										"ifndef": ["_ShadowMapAtlas"],
 | 
				
			||||||
 | 
										"ifdef": ["_LTC", "_ShadowMap"]
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										"name": "LWVPSpot[3]",
 | 
				
			||||||
 | 
										"link": "_biasLightWorldViewProjectionMatrixSpot3",
 | 
				
			||||||
 | 
										"ifndef": ["_ShadowMapAtlas"],
 | 
				
			||||||
 | 
										"ifdef": ["_LTC", "_ShadowMap"]
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			],
 | 
								],
 | 
				
			||||||
			"texture_params": [],
 | 
								"texture_params": [],
 | 
				
			||||||
			"vertex_shader": "../include/pass_viewray2.vert.glsl",
 | 
								"vertex_shader": "../include/pass_viewray.vert.glsl",
 | 
				
			||||||
			"fragment_shader": "ssgi_pass.frag.glsl"
 | 
								"fragment_shader": "ssgi_pass.frag.glsl"
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	]
 | 
						]
 | 
				
			||||||
 | 
				
			|||||||
@ -92,7 +92,7 @@ void main() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	vec3 viewNormal = V3 * n;
 | 
						vec3 viewNormal = V3 * n;
 | 
				
			||||||
	vec3 viewPos = getPosView(viewRay, d, cameraProj);
 | 
						vec3 viewPos = getPosView(viewRay, d, cameraProj);
 | 
				
			||||||
	vec3 reflected = reflect(normalize(viewPos), viewNormal);
 | 
						vec3 reflected = reflect(viewPos, viewNormal);
 | 
				
			||||||
	hitCoord = viewPos;
 | 
						hitCoord = viewPos;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	#ifdef _CPostprocess
 | 
						#ifdef _CPostprocess
 | 
				
			||||||
 | 
				
			|||||||
@ -62,12 +62,9 @@ vec4 rayCast(vec3 dir) {
 | 
				
			|||||||
	for (int i = 0; i < maxSteps; i++) {
 | 
						for (int i = 0; i < maxSteps; i++) {
 | 
				
			||||||
		hitCoord += dir;
 | 
							hitCoord += dir;
 | 
				
			||||||
		ddepth = getDeltaDepth(hitCoord);
 | 
							ddepth = getDeltaDepth(hitCoord);
 | 
				
			||||||
        if (ddepth > 0.0)
 | 
							if (ddepth > 0.0) return binarySearch(dir);
 | 
				
			||||||
            return binarySearch(dir);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
    // No hit — fallback to projecting the ray to UV space
 | 
						return vec4(texCoord, 0.0, 1.0);
 | 
				
			||||||
    vec2 fallbackUV = getProjectedCoord(hitCoord);
 | 
					 | 
				
			||||||
    return vec4(fallbackUV, 0.0, 0.5); // We set .w lower to indicate fallback
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void main() {
 | 
					void main() {
 | 
				
			||||||
@ -75,10 +72,11 @@ void main() {
 | 
				
			|||||||
    float roughness = g0.z;
 | 
					    float roughness = g0.z;
 | 
				
			||||||
    vec4 gr = textureLod(gbuffer_refraction, texCoord, 0.0);
 | 
					    vec4 gr = textureLod(gbuffer_refraction, texCoord, 0.0);
 | 
				
			||||||
    float ior = gr.x;
 | 
					    float ior = gr.x;
 | 
				
			||||||
    float opac = gr.y;
 | 
					    float opac = 1.0 - gr.y;
 | 
				
			||||||
    float d = textureLod(gbufferD, texCoord, 0.0).r * 2.0 - 1.0;
 | 
					    float d = textureLod(gbufferD, texCoord, 0.0).r * 2.0 - 1.0;
 | 
				
			||||||
    if (d == 0.0 || opac == 1.0 || ior == 1.0) {
 | 
					    if (d == 0.0 || d == 1.0 || opac == 1.0 || ior == 1.0) {
 | 
				
			||||||
        fragColor.rgb = textureLod(tex1, texCoord, 0.0).rgb;
 | 
					        fragColor.rgb = textureLod(tex1, texCoord, 0.0).rgb;
 | 
				
			||||||
 | 
							fragColor.a = opac;
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
	vec2 enc = g0.rg;
 | 
						vec2 enc = g0.rg;
 | 
				
			||||||
@ -101,9 +99,12 @@ void main() {
 | 
				
			|||||||
						clamp(-refracted.z, 0.0, 1.0) * clamp((length(viewPos - hitCoord)), 0.0, 1.0) * coords.w;
 | 
											clamp(-refracted.z, 0.0, 1.0) * clamp((length(viewPos - hitCoord)), 0.0, 1.0) * coords.w;
 | 
				
			||||||
	intensity = clamp(intensity, 0.0, 1.0);
 | 
						intensity = clamp(intensity, 0.0, 1.0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	vec3 refractionCol = textureLod(tex1, coords.xy, 0.0).rgb;
 | 
						vec4 refractionCol = textureLod(tex1, coords.xy, 0.0).rgba;
 | 
				
			||||||
	refractionCol *= intensity;
 | 
						refractionCol.a = opac;
 | 
				
			||||||
	vec3 color = textureLod(tex, texCoord.xy, 0.0).rgb;
 | 
						//refractionCol *= intensity;
 | 
				
			||||||
 | 
						vec4 color = textureLod(tex, texCoord.xy, 0.0).rgba;
 | 
				
			||||||
 | 
						color.a = opac;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fragColor.rgb = mix(refractionCol, color, opac);
 | 
						fragColor.rgba = mix(refractionCol, color, opac);
 | 
				
			||||||
 | 
						fragColor.a = opac;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -5,6 +5,12 @@
 | 
				
			|||||||
			"depth_write": false,
 | 
								"depth_write": false,
 | 
				
			||||||
			"compare_mode": "always",
 | 
								"compare_mode": "always",
 | 
				
			||||||
			"cull_mode": "none",
 | 
								"cull_mode": "none",
 | 
				
			||||||
 | 
								"blend_source": "source_alpha",
 | 
				
			||||||
 | 
								"blend_destination": "inverse_source_alpha",
 | 
				
			||||||
 | 
								"blend_operation": "add",
 | 
				
			||||||
 | 
								"alpha_blend_source": "blend_one",
 | 
				
			||||||
 | 
								"alpha_blend_destination": "blend_one",
 | 
				
			||||||
 | 
								"alpha_blend_operation": "add",
 | 
				
			||||||
			"links": [
 | 
								"links": [
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					"name": "P",
 | 
										"name": "P",
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
//
 | 
					//
 | 
				
			||||||
// Copyright (C) 2012 Jorge Jimenez (jorge@iryoku.com)
 | 
					// Copyright (C) 2012 Jorge Jimenez (jorge@iryoku.com)
 | 
				
			||||||
// Copyright (C) 2012 Diego Gutierrez (diegog@unizar.es)
 | 
					// Copyright (C) 2012 Diego Gutierrez (diegog@unizar.es)
 | 
				
			||||||
 | 
					// Copyright (C) 2025 Onek8 (info@leenkx.com)
 | 
				
			||||||
// All rights reserved.
 | 
					// All rights reserved.
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
// Redistribution and use in source and binary forms, with or without
 | 
					// Redistribution and use in source and binary forms, with or without
 | 
				
			||||||
@ -33,6 +34,14 @@
 | 
				
			|||||||
// policies, either expressed or implied, of the copyright holders.
 | 
					// policies, either expressed or implied, of the copyright holders.
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO:
 | 
				
			||||||
 | 
					// Add real sss radius
 | 
				
			||||||
 | 
					// Add real sss scale
 | 
				
			||||||
 | 
					// Move temp hash, reorganize shader utility functions
 | 
				
			||||||
 | 
					// Add compiler flag for quality presets or with samples parameter
 | 
				
			||||||
 | 
					// Clean up + Document comment
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#version 450
 | 
					#version 450
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "compiled.inc"
 | 
					#include "compiled.inc"
 | 
				
			||||||
@ -49,67 +58,93 @@ out vec4 fragColor;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const float SSSS_FOVY = 108.0;
 | 
					const float SSSS_FOVY = 108.0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Separable SSS Reflectance
 | 
					// Temp hash func - 
 | 
				
			||||||
// const float sssWidth = 0.005;
 | 
					float hash13(vec3 p3) {
 | 
				
			||||||
 | 
						p3 = fract(p3 * vec3(0.1031, 0.1030, 0.0973));
 | 
				
			||||||
 | 
						p3 += dot(p3, p3.yzx + 33.33);
 | 
				
			||||||
 | 
						return fract((p3.x + p3.y) * p3.z);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
vec4 SSSSBlur() {
 | 
					vec4 SSSSBlur() {
 | 
				
			||||||
	// Quality = 0
 | 
						const int SSSS_N_SAMPLES = 15;
 | 
				
			||||||
	const int SSSS_N_SAMPLES  = 11;
 | 
					 | 
				
			||||||
	vec4 kernel[SSSS_N_SAMPLES];
 | 
						vec4 kernel[SSSS_N_SAMPLES];
 | 
				
			||||||
	kernel[0] = vec4(0.560479, 0.669086, 0.784728, 0);
 | 
						
 | 
				
			||||||
	kernel[1] = vec4(0.00471691, 0.000184771, 5.07566e-005, -2);
 | 
						// color neutral kernel weights to prevent color shifting
 | 
				
			||||||
	kernel[2] = vec4(0.0192831, 0.00282018, 0.00084214, -1.28);
 | 
						kernel[0] = vec4(0.2, 0.2, 0.2, 0.0);
 | 
				
			||||||
	kernel[3] = vec4(0.03639, 0.0130999, 0.00643685, -0.72);
 | 
						kernel[1] = vec4(0.12, 0.12, 0.12, 0.2);
 | 
				
			||||||
	kernel[4] = vec4(0.0821904, 0.0358608, 0.0209261, -0.32);
 | 
						kernel[2] = vec4(0.09, 0.09, 0.09, 0.4);
 | 
				
			||||||
	kernel[5] = vec4(0.0771802, 0.113491, 0.0793803, -0.08);
 | 
						kernel[3] = vec4(0.06, 0.06, 0.06, 0.8);
 | 
				
			||||||
	kernel[6] = vec4(0.0771802, 0.113491, 0.0793803, 0.08);
 | 
						kernel[4] = vec4(0.04, 0.04, 0.04, 1.2);
 | 
				
			||||||
	kernel[7] = vec4(0.0821904, 0.0358608, 0.0209261, 0.32);
 | 
						kernel[5] = vec4(0.025, 0.025, 0.025, 1.6);
 | 
				
			||||||
	kernel[8] = vec4(0.03639, 0.0130999, 0.00643685, 0.72);
 | 
						kernel[6] = vec4(0.015, 0.015, 0.015, 2.0);
 | 
				
			||||||
	kernel[9] = vec4(0.0192831, 0.00282018, 0.00084214, 1.28);
 | 
						kernel[7] = vec4(0.005, 0.005, 0.005, 2.5);
 | 
				
			||||||
	kernel[10] = vec4(0.00471691, 0.000184771, 5.07565e-005, 2);
 | 
						kernel[8] = vec4(0.12, 0.12, 0.12, -0.2);
 | 
				
			||||||
 | 
						kernel[9] = vec4(0.09, 0.09, 0.09, -0.4);
 | 
				
			||||||
 | 
						kernel[10] = vec4(0.06, 0.06, 0.06, -0.8);
 | 
				
			||||||
 | 
						kernel[11] = vec4(0.04, 0.04, 0.04, -1.2);
 | 
				
			||||||
 | 
						kernel[12] = vec4(0.025, 0.025, 0.025, -1.6);
 | 
				
			||||||
 | 
						kernel[13] = vec4(0.015, 0.015, 0.015, -2.0);
 | 
				
			||||||
 | 
						kernel[14] = vec4(0.005, 0.005, 0.005, -2.5);
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	vec4 colorM = textureLod(tex, texCoord, 0.0);
 | 
						vec4 colorM = textureLod(tex, texCoord, 0.0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Fetch linear depth of current pixel
 | 
					 | 
				
			||||||
	float depth = textureLod(gbufferD, texCoord, 0.0).r;
 | 
						float depth = textureLod(gbufferD, texCoord, 0.0).r;
 | 
				
			||||||
	float depthM = cameraProj.y / (depth - cameraProj.x);
 | 
						float depthM = cameraProj.y / (depth - cameraProj.x);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Calculate the sssWidth scale (1.0 for a unit plane sitting on the projection window)
 | 
					 | 
				
			||||||
	float distanceToProjectionWindow = 1.0 / tan(0.5 * radians(SSSS_FOVY));
 | 
						float distanceToProjectionWindow = 1.0 / tan(0.5 * radians(SSSS_FOVY));
 | 
				
			||||||
	float scale = distanceToProjectionWindow / depthM;
 | 
						float scale = distanceToProjectionWindow / depthM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Calculate the final step to fetch the surrounding pixels
 | 
					 | 
				
			||||||
	vec2 finalStep = sssWidth * scale * dir;
 | 
						vec2 finalStep = sssWidth * scale * dir;
 | 
				
			||||||
	finalStep *= 1.0;//SSSS_STREGTH_SOURCE; // Modulate it using the alpha channel.
 | 
					 | 
				
			||||||
	finalStep *= 1.0 / 3.0; // Divide by 3 as the kernels range from -3 to 3.
 | 
					 | 
				
			||||||
	finalStep *= 0.05; //
 | 
					 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	// Accumulate the center sample:
 | 
					 | 
				
			||||||
	vec4 colorBlurred = colorM;
 | 
					 | 
				
			||||||
	colorBlurred.rgb *= kernel[0].rgb;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Accumulate the other samples
 | 
						vec3 jitterSeed = vec3(texCoord.xy * 1000.0, fract(cameraProj.x * 0.0001));
 | 
				
			||||||
 | 
						float jitterOffset = (hash13(jitterSeed) * 2.0 - 1.0) * 0.15; // 15% jitteR
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						finalStep *= (1.0 + jitterOffset);
 | 
				
			||||||
 | 
						finalStep *= 0.05; 
 | 
				
			||||||
 | 
						vec3 colorBlurred = vec3(0.0);
 | 
				
			||||||
 | 
						vec3 weightSum = vec3(0.0);
 | 
				
			||||||
 | 
						colorBlurred += colorM.rgb * kernel[0].rgb;
 | 
				
			||||||
 | 
						weightSum += kernel[0].rgb;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						// Accumulate the other samples with per-pixel jittering to reduce banding
 | 
				
			||||||
	for (int i = 1; i < SSSS_N_SAMPLES; i++) {
 | 
						for (int i = 1; i < SSSS_N_SAMPLES; i++) {
 | 
				
			||||||
		// Fetch color and depth for current sample
 | 
							float sampleJitter = hash13(vec3(texCoord.xy * 720.0, float(i) * 37.45)) * 0.1 - 0.05;
 | 
				
			||||||
		vec2 offset = texCoord + kernel[i].a * finalStep;
 | 
							
 | 
				
			||||||
 | 
							vec2 offset = texCoord + (kernel[i].a + sampleJitter) * finalStep;
 | 
				
			||||||
		vec4 color = textureLod(tex, offset, 0.0);
 | 
							vec4 color = textureLod(tex, offset, 0.0);
 | 
				
			||||||
		//#if SSSS_FOLLOW_SURFACE == 1
 | 
							
 | 
				
			||||||
		// If the difference in depth is huge, we lerp color back to "colorM":
 | 
							// ADJUST FOR SURFACE FOLLOWING
 | 
				
			||||||
		//float depth = textureLod(tex, offset, 0.0).r;
 | 
							// 0.0 = disabled (maximum SSS but with bleeding), 1.0 = fully enabled (prevents bleeding but might reduce SSS effect)
 | 
				
			||||||
		//float s = clamp(300.0f * distanceToProjectionWindow * sssWidth * abs(depthM - depth),0.0,1.0);
 | 
							const float SURFACE_FOLLOWING_STRENGTH = 0.15; // Reduced to preserve more SSS effect
 | 
				
			||||||
		//color.rgb = mix(color.rgb, colorM.rgb, s);
 | 
							
 | 
				
			||||||
		//#endif
 | 
							if (SURFACE_FOLLOWING_STRENGTH > 0.0) {
 | 
				
			||||||
		// Accumulate
 | 
								float sampleDepth = textureLod(gbufferD, offset, 0.0).r;
 | 
				
			||||||
		colorBlurred.rgb += kernel[i].rgb * color.rgb;
 | 
								float depthScale = 5.0; 
 | 
				
			||||||
 | 
								float depthDiff = abs(depth - sampleDepth) * depthScale;
 | 
				
			||||||
 | 
								if (depthDiff > 0.3) { 
 | 
				
			||||||
 | 
									float blendFactor = clamp(depthDiff - 0.3, 0.0, 1.0) * SURFACE_FOLLOWING_STRENGTH;
 | 
				
			||||||
 | 
									color.rgb = mix(color.rgb, colorM.rgb, blendFactor);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
	return colorBlurred;
 | 
							colorBlurred += color.rgb * kernel[i].rgb;
 | 
				
			||||||
 | 
							weightSum += kernel[i].rgb;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						vec3 normalizedColor = colorBlurred / max(weightSum, vec3(0.00001));
 | 
				
			||||||
 | 
						float dither = hash13(vec3(texCoord * 1333.0, 0.0)) * 0.003 - 0.0015;
 | 
				
			||||||
 | 
						return vec4(normalizedColor + vec3(dither), colorM.a);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void main() {
 | 
					void main() {
 | 
				
			||||||
 | 
						
 | 
				
			||||||
	if (textureLod(gbuffer0, texCoord, 0.0).a == 8192.0) {
 | 
						if (textureLod(gbuffer0, texCoord, 0.0).a == 8192.0) {
 | 
				
			||||||
		fragColor = clamp(SSSSBlur(), 0.0, 1.0);
 | 
							vec4 originalColor = textureLod(tex, texCoord, 0.0);
 | 
				
			||||||
	}
 | 
							vec4 blurredColor = SSSSBlur();
 | 
				
			||||||
	else {
 | 
							vec4 finalColor = mix(blurredColor, originalColor, 0.15);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							fragColor = clamp(finalColor, 0.0, 1.0);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
		fragColor = textureLod(tex, texCoord, 0.0);
 | 
							fragColor = textureLod(tex, texCoord, 0.0);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										18
									
								
								leenkx/Shaders/std/aabb.glsl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								leenkx/Shaders/std/aabb.glsl
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					#ifndef _AABB_GLSL
 | 
				
			||||||
 | 
					#define _AABB_GLSL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool IntersectAABB(vec3[2] a, vec3[2] b) {
 | 
				
			||||||
 | 
					    const float EPSILON = 0.001; // Small tolerance to prevent false negatives
 | 
				
			||||||
 | 
					    if (abs(a[0].x - b[0].x) > (a[1].x + b[1].x + EPSILON)) return false;
 | 
				
			||||||
 | 
					    if (abs(a[0].y - b[0].y) > (a[1].y + b[1].y + EPSILON)) return false;
 | 
				
			||||||
 | 
					    if (abs(a[0].z - b[0].z) > (a[1].z + b[1].z + EPSILON)) return false;
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void AABBfromMinMax(inout vec3[2] aabb, vec3 _min, vec3 _max)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						aabb[0] = (_min + _max) * 0.5f;
 | 
				
			||||||
 | 
						aabb[1] = abs(_max - aabb[0]);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
@ -22,7 +22,7 @@ THE SOFTWARE.
 | 
				
			|||||||
#ifndef _CONETRACE_GLSL_
 | 
					#ifndef _CONETRACE_GLSL_
 | 
				
			||||||
#define _CONETRACE_GLSL_
 | 
					#define _CONETRACE_GLSL_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "std/voxels_constants.glsl"
 | 
					#include "std/constants.glsl"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// References
 | 
					// References
 | 
				
			||||||
// https://github.com/Friduric/voxel-cone-tracing
 | 
					// https://github.com/Friduric/voxel-cone-tracing
 | 
				
			||||||
@ -92,14 +92,14 @@ vec4 traceCone(const sampler3D voxels, const sampler3D voxelsSDF, const vec3 ori
 | 
				
			|||||||
	float dist = voxelSize0;
 | 
						float dist = voxelSize0;
 | 
				
			||||||
	float step_dist = dist;
 | 
						float step_dist = dist;
 | 
				
			||||||
	vec3 samplePos;
 | 
						vec3 samplePos;
 | 
				
			||||||
	vec3 start_pos = origin + n * voxelSize0 * voxelgiOffset;
 | 
						vec3 start_pos = origin + n * voxelSize0;
 | 
				
			||||||
	int clipmap_index0 = 0;
 | 
						int clipmap_index0 = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	vec3 aniso_direction = -dir;
 | 
						vec3 aniso_direction = -dir;
 | 
				
			||||||
	vec3 face_offset = vec3(
 | 
						vec3 face_offset = vec3(
 | 
				
			||||||
		aniso_direction.x > 0.0 ? 0 : 1,
 | 
							aniso_direction.x > 0.0 ? 0.0 : 1.0,
 | 
				
			||||||
		aniso_direction.y > 0.0 ? 2 : 3,
 | 
							aniso_direction.y > 0.0 ? 2.0 : 3.0,
 | 
				
			||||||
		aniso_direction.z > 0.0 ? 4 : 5
 | 
							aniso_direction.z > 0.0 ? 4.0 : 5.0
 | 
				
			||||||
	) / (6 + DIFFUSE_CONE_COUNT);
 | 
						) / (6 + DIFFUSE_CONE_COUNT);
 | 
				
			||||||
	vec3 direction_weight = abs(dir);
 | 
						vec3 direction_weight = abs(dir);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -125,7 +125,7 @@ vec4 traceCone(const sampler3D voxels, const sampler3D voxelsSDF, const vec3 ori
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		if(clipmap_blend > 0.0 && clipmap_index < voxelgiClipmapCount - 1) {
 | 
							if(clipmap_blend > 0.0 && clipmap_index < voxelgiClipmapCount - 1) {
 | 
				
			||||||
			vec4 mipSampleNext = sampleVoxel(voxels, p0, clipmaps, clipmap_index + 1.0, step_dist, precomputed_direction, face_offset, direction_weight);
 | 
								vec4 mipSampleNext = sampleVoxel(voxels, p0, clipmaps, clipmap_index + 1.0, step_dist, precomputed_direction, face_offset, direction_weight);
 | 
				
			||||||
			mipSample = mix(mipSample, mipSampleNext, smoothstep(0.0, 1.0, clipmap_blend));
 | 
								mipSample = mix(mipSample, mipSampleNext, clipmap_blend);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		sampleCol += (1.0 - sampleCol.a) * mipSample;
 | 
							sampleCol += (1.0 - sampleCol.a) * mipSample;
 | 
				
			||||||
@ -148,8 +148,9 @@ vec4 traceCone(const sampler3D voxels, const sampler3D voxelsSDF, const vec3 ori
 | 
				
			|||||||
vec4 traceDiffuse(const vec3 origin, const vec3 normal, const sampler3D voxels, const float clipmaps[voxelgiClipmapCount * 10]) {
 | 
					vec4 traceDiffuse(const vec3 origin, const vec3 normal, const sampler3D voxels, const float clipmaps[voxelgiClipmapCount * 10]) {
 | 
				
			||||||
	float sum = 0.0;
 | 
						float sum = 0.0;
 | 
				
			||||||
	vec4 amount = vec4(0.0);
 | 
						vec4 amount = vec4(0.0);
 | 
				
			||||||
 | 
						mat3 TBN = makeTangentBasis(normal);
 | 
				
			||||||
	for (int i = 0; i < DIFFUSE_CONE_COUNT; ++i) {
 | 
						for (int i = 0; i < DIFFUSE_CONE_COUNT; ++i) {
 | 
				
			||||||
		vec3 coneDir = DIFFUSE_CONE_DIRECTIONS[i];
 | 
							vec3 coneDir = TBN * DIFFUSE_CONE_DIRECTIONS[i];
 | 
				
			||||||
		const float cosTheta = dot(normal, coneDir);
 | 
							const float cosTheta = dot(normal, coneDir);
 | 
				
			||||||
		if (cosTheta <= 0)
 | 
							if (cosTheta <= 0)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
@ -196,14 +197,14 @@ float traceConeAO(const sampler3D voxels, const vec3 origin, const vec3 n, const
 | 
				
			|||||||
	float dist = voxelSize0;
 | 
						float dist = voxelSize0;
 | 
				
			||||||
	float step_dist = dist;
 | 
						float step_dist = dist;
 | 
				
			||||||
	vec3 samplePos;
 | 
						vec3 samplePos;
 | 
				
			||||||
	vec3 start_pos = origin + n * voxelSize0 * voxelgiOffset;
 | 
						vec3 start_pos = origin + n * voxelSize0;
 | 
				
			||||||
	int clipmap_index0 = 0;
 | 
						int clipmap_index0 = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	vec3 aniso_direction = -dir;
 | 
						vec3 aniso_direction = -dir;
 | 
				
			||||||
	vec3 face_offset = vec3(
 | 
						vec3 face_offset = vec3(
 | 
				
			||||||
		aniso_direction.x > 0.0 ? 0 : 1,
 | 
							aniso_direction.x > 0.0 ? 0.0 : 1.0,
 | 
				
			||||||
		aniso_direction.y > 0.0 ? 2 : 3,
 | 
							aniso_direction.y > 0.0 ? 2.0 : 3.0,
 | 
				
			||||||
		aniso_direction.z > 0.0 ? 4 : 5
 | 
							aniso_direction.z > 0.0 ? 4.0 : 5.0
 | 
				
			||||||
	) / (6 + DIFFUSE_CONE_COUNT);
 | 
						) / (6 + DIFFUSE_CONE_COUNT);
 | 
				
			||||||
	vec3 direction_weight = abs(dir);
 | 
						vec3 direction_weight = abs(dir);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -259,7 +260,6 @@ float traceAO(const vec3 origin, const vec3 normal, const sampler3D voxels, cons
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef _VoxelShadow
 | 
					#ifdef _VoxelShadow
 | 
				
			||||||
float traceConeShadow(const sampler3D voxels, const sampler3D voxelsSDF, const vec3 origin, const vec3 n, const vec3 dir, const float aperture, const float step_size, const float clipmaps[voxelgiClipmapCount * 10]) {
 | 
					float traceConeShadow(const sampler3D voxels, const sampler3D voxelsSDF, const vec3 origin, const vec3 n, const vec3 dir, const float aperture, const float step_size, const float clipmaps[voxelgiClipmapCount * 10]) {
 | 
				
			||||||
    float sampleCol = 0.0;
 | 
					    float sampleCol = 0.0;
 | 
				
			||||||
@ -267,14 +267,14 @@ float traceConeShadow(const sampler3D voxels, const sampler3D voxelsSDF, const v
 | 
				
			|||||||
	float dist = voxelSize0;
 | 
						float dist = voxelSize0;
 | 
				
			||||||
	float step_dist = dist;
 | 
						float step_dist = dist;
 | 
				
			||||||
	vec3 samplePos;
 | 
						vec3 samplePos;
 | 
				
			||||||
	vec3 start_pos = origin + n * voxelSize0 * voxelgiOffset;
 | 
						vec3 start_pos = origin + n * voxelSize0;
 | 
				
			||||||
	int clipmap_index0 = 0;
 | 
						int clipmap_index0 = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	vec3 aniso_direction = -dir;
 | 
						vec3 aniso_direction = -dir;
 | 
				
			||||||
	vec3 face_offset = vec3(
 | 
						vec3 face_offset = vec3(
 | 
				
			||||||
		aniso_direction.x > 0.0 ? 0 : 1,
 | 
							aniso_direction.x > 0.0 ? 0.0 : 1.0,
 | 
				
			||||||
		aniso_direction.y > 0.0 ? 2 : 3,
 | 
							aniso_direction.y > 0.0 ? 2.0 : 3.0,
 | 
				
			||||||
		aniso_direction.z > 0.0 ? 4 : 5
 | 
							aniso_direction.z > 0.0 ? 4.0 : 5.0
 | 
				
			||||||
	) / (6 + DIFFUSE_CONE_COUNT);
 | 
						) / (6 + DIFFUSE_CONE_COUNT);
 | 
				
			||||||
	vec3 direction_weight = abs(dir);
 | 
						vec3 direction_weight = abs(dir);
 | 
				
			||||||
	float coneCoefficient = 2.0 * tan(aperture * 0.5);
 | 
						float coneCoefficient = 2.0 * tan(aperture * 0.5);
 | 
				
			||||||
@ -287,7 +287,7 @@ float traceConeShadow(const sampler3D voxels, const sampler3D voxelsSDF, const v
 | 
				
			|||||||
		float clipmap_blend = fract(lod);
 | 
							float clipmap_blend = fract(lod);
 | 
				
			||||||
		vec3 p0 = start_pos + dir * dist;
 | 
							vec3 p0 = start_pos + dir * dist;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        samplePos = (p0 - vec3(clipmaps[int(clipmap_index * 10 + 4)], clipmaps[int(clipmap_index * 10 + 5)], clipmaps[int(clipmap_index * 10 + 6)])) / (float(clipmaps[int(clipmap_index * 10)]) * voxelgiResolution.x);
 | 
					        samplePos = (p0 - vec3(clipmaps[int(clipmap_index * 10 + 4)], clipmaps[int(clipmap_index * 10 + 5)], clipmaps[int(clipmap_index * 10 + 6)])) / (float(clipmaps[int(clipmap_index * 10)]) * voxelgiResolution);
 | 
				
			||||||
		samplePos = samplePos * 0.5 + 0.5;
 | 
							samplePos = samplePos * 0.5 + 0.5;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if ((any(notEqual(samplePos, clamp(samplePos, 0.0, 1.0))))) {
 | 
							if ((any(notEqual(samplePos, clamp(samplePos, 0.0, 1.0))))) {
 | 
				
			||||||
@ -330,7 +330,7 @@ float traceConeShadow(const sampler3D voxels, const sampler3D voxelsSDF, const v
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
float traceShadow(const vec3 origin, const vec3 normal, const sampler3D voxels, const sampler3D voxelsSDF, const vec3 dir, const float clipmaps[voxelgiClipmapCount * 10], const vec2 pixel, const vec2 velocity) {
 | 
					float traceShadow(const vec3 origin, const vec3 normal, const sampler3D voxels, const sampler3D voxelsSDF, const vec3 dir, const float clipmaps[voxelgiClipmapCount * 10], const vec2 pixel, const vec2 velocity) {
 | 
				
			||||||
 	vec3 P = origin + dir * (BayerMatrix8[int(pixel.x + velocity.x) % 8][int(pixel.y + velocity.y) % 8] - 0.5) * voxelgiStep;
 | 
					 	vec3 P = origin + dir * (BayerMatrix8[int(pixel.x + velocity.x) % 8][int(pixel.y + velocity.y) % 8] - 0.5) * voxelgiStep;
 | 
				
			||||||
	float amount = traceConeShadow(voxels, voxelsSDF, P, normal, dir, DIFFUSE_CONE_APERTURE, voxelgiStep, clipmaps);
 | 
						float amount = traceConeShadow(voxels, voxelsSDF, P, normal, dir, SHADOW_CONE_APERTURE, voxelgiStep, clipmaps);
 | 
				
			||||||
	amount = clamp(amount, 0.0, 1.0);
 | 
						amount = clamp(amount, 0.0, 1.0);
 | 
				
			||||||
	return amount * voxelgiOcc;
 | 
						return amount * voxelgiOcc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -21,29 +21,49 @@ THE SOFTWARE.
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const int DIFFUSE_CONE_COUNT = 16;
 | 
					const int DIFFUSE_CONE_COUNT = 16;
 | 
				
			||||||
const float DIFFUSE_CONE_APERTURE = radians(45.0);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const vec3 DIFFUSE_CONE_DIRECTIONS[16] = {
 | 
					const float SHADOW_CONE_APERTURE = radians(15.0);
 | 
				
			||||||
	vec3(0.0000, 0.0000, 1.0000),   // Central direction
 | 
					 | 
				
			||||||
	vec3(0.3827, 0.0000, 0.9239),   // Ring 1
 | 
					 | 
				
			||||||
	vec3(-0.3827, 0.0000, 0.9239),
 | 
					 | 
				
			||||||
	vec3(0.0000, 0.3827, 0.9239),
 | 
					 | 
				
			||||||
	vec3(0.0000, -0.3827, 0.9239),
 | 
					 | 
				
			||||||
	vec3(0.2706, 0.2706, 0.9239),   // Ring 2
 | 
					 | 
				
			||||||
	vec3(-0.2706, 0.2706, 0.9239),
 | 
					 | 
				
			||||||
	vec3(0.2706, -0.2706, 0.9239),
 | 
					 | 
				
			||||||
	vec3(-0.2706, -0.2706, 0.9239),
 | 
					 | 
				
			||||||
	vec3(0.1802, 0.3604, 0.9239),   // Ring 3
 | 
					 | 
				
			||||||
	vec3(-0.1802, 0.3604, 0.9239),
 | 
					 | 
				
			||||||
	vec3(0.1802, -0.3604, 0.9239),
 | 
					 | 
				
			||||||
	vec3(-0.1802, -0.3604, 0.9239),
 | 
					 | 
				
			||||||
	vec3(0.3604, 0.1802, 0.9239),
 | 
					 | 
				
			||||||
	vec3(-0.3604, 0.1802, 0.9239),
 | 
					 | 
				
			||||||
	vec3(0.3604, -0.1802, 0.9239)
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const float DIFFUSE_CONE_APERTURE = 0.872665; // 50 degrees in radians
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const float BayerMatrix8[8][8] =
 | 
					mat3 makeTangentBasis(const vec3 normal) {
 | 
				
			||||||
 | 
					    // Create a tangent basis from normal vector
 | 
				
			||||||
 | 
					    vec3 tangent;
 | 
				
			||||||
 | 
					    vec3 bitangent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Compute tangent (Frisvad's method)
 | 
				
			||||||
 | 
					    if (abs(normal.z) < 0.999) {
 | 
				
			||||||
 | 
					        tangent = normalize(cross(vec3(0, 1, 0), normal));
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        tangent = normalize(cross(normal, vec3(1, 0, 0)));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    bitangent = cross(normal, tangent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return mat3(tangent, bitangent, normal);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 16 optimized cone directions for hemisphere sampling (Z-up, normalized)
 | 
				
			||||||
 | 
					const vec3 DIFFUSE_CONE_DIRECTIONS[16] = vec3[](
 | 
				
			||||||
 | 
					    vec3(0.707107, 0.000000, 0.707107),  // Front
 | 
				
			||||||
 | 
					    vec3(-0.707107, 0.000000, 0.707107), // Back
 | 
				
			||||||
 | 
					    vec3(0.000000, 0.707107, 0.707107),  // Right
 | 
				
			||||||
 | 
					    vec3(0.000000, -0.707107, 0.707107), // Left
 | 
				
			||||||
 | 
					    vec3(0.500000, 0.500000, 0.707107),  // Front-right
 | 
				
			||||||
 | 
					    vec3(-0.500000, 0.500000, 0.707107), // Back-right
 | 
				
			||||||
 | 
					    vec3(0.500000, -0.500000, 0.707107), // Front-left
 | 
				
			||||||
 | 
					    vec3(-0.500000, -0.500000, 0.707107),// Back-left
 | 
				
			||||||
 | 
					    vec3(0.353553, 0.000000, 0.935414),  // Narrow front
 | 
				
			||||||
 | 
					    vec3(-0.353553, 0.000000, 0.935414), // Narrow back
 | 
				
			||||||
 | 
					    vec3(0.000000, 0.353553, 0.935414),  // Narrow right
 | 
				
			||||||
 | 
					    vec3(0.000000, -0.353553, 0.935414), // Narrow left
 | 
				
			||||||
 | 
					    vec3(0.270598, 0.270598, 0.923880),  // Narrow front-right
 | 
				
			||||||
 | 
					    vec3(-0.270598, 0.270598, 0.923880), // Narrow back-right
 | 
				
			||||||
 | 
					    vec3(0.270598, -0.270598, 0.923880), // Narrow front-left
 | 
				
			||||||
 | 
					    vec3(-0.270598, -0.270598, 0.923880) // Narrow back-left
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TO DO - Disabled momentarily instead of changing formulas
 | 
				
			||||||
 | 
					const float off_BayerMatrix8[8][8] =
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	{ 1.0 / 65.0, 49.0 / 65.0, 13.0 / 65.0, 61.0 / 65.0, 4.0 / 65.0, 52.0 / 65.0, 16.0 / 65.0, 64.0 / 65.0 },
 | 
						{ 1.0 / 65.0, 49.0 / 65.0, 13.0 / 65.0, 61.0 / 65.0, 4.0 / 65.0, 52.0 / 65.0, 16.0 / 65.0, 64.0 / 65.0 },
 | 
				
			||||||
	{ 33.0 / 65.0, 17.0 / 65.0, 45.0 / 65.0, 29.0 / 65.0, 36.0 / 65.0, 20.0 / 65.0, 48.0 / 65.0, 32.0 / 65.0 },
 | 
						{ 33.0 / 65.0, 17.0 / 65.0, 45.0 / 65.0, 29.0 / 65.0, 36.0 / 65.0, 20.0 / 65.0, 48.0 / 65.0, 32.0 / 65.0 },
 | 
				
			||||||
@ -54,3 +74,15 @@ const float BayerMatrix8[8][8] =
 | 
				
			|||||||
	{ 11.0 / 65.0, 59.0 / 65.0, 7.0 / 65.0, 55.0 / 65.0, 10.0 / 65.0, 58.0 / 65.0, 6.0 / 65.0, 54.0 / 65.0 },
 | 
						{ 11.0 / 65.0, 59.0 / 65.0, 7.0 / 65.0, 55.0 / 65.0, 10.0 / 65.0, 58.0 / 65.0, 6.0 / 65.0, 54.0 / 65.0 },
 | 
				
			||||||
	{ 43.0 / 65.0, 27.0 / 65.0, 39.0 / 65.0, 23.0 / 65.0, 42.0 / 65.0, 26.0 / 65.0, 38.0 / 65.0, 22.0 / 65.0 }
 | 
						{ 43.0 / 65.0, 27.0 / 65.0, 39.0 / 65.0, 23.0 / 65.0, 42.0 / 65.0, 26.0 / 65.0, 38.0 / 65.0, 22.0 / 65.0 }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					const float BayerMatrix8[8][8] =
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						{ 1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0 },
 | 
				
			||||||
 | 
						{ 1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0 },
 | 
				
			||||||
 | 
						{ 1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0 },
 | 
				
			||||||
 | 
						{ 1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0 },
 | 
				
			||||||
 | 
						{ 1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0 },
 | 
				
			||||||
 | 
						{ 1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0 },
 | 
				
			||||||
 | 
						{ 1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0 },
 | 
				
			||||||
 | 
						{ 1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0 }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -10,9 +10,6 @@
 | 
				
			|||||||
#ifdef _VoxelShadow
 | 
					#ifdef _VoxelShadow
 | 
				
			||||||
#include "std/conetrace.glsl"
 | 
					#include "std/conetrace.glsl"
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
#ifdef _gbuffer2
 | 
					 | 
				
			||||||
uniform sampler2D gbuffer2;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef _LTC
 | 
					#ifdef _LTC
 | 
				
			||||||
#include "std/ltc.glsl"
 | 
					#include "std/ltc.glsl"
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
@ -25,46 +22,63 @@ uniform sampler2D gbuffer2;
 | 
				
			|||||||
#ifdef _Spot
 | 
					#ifdef _Spot
 | 
				
			||||||
#include "std/light_common.glsl"
 | 
					#include "std/light_common.glsl"
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef _VoxelShadow
 | 
				
			||||||
 | 
					#include "std/conetrace.glsl"
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _ShadowMap
 | 
					#ifdef _ShadowMap
 | 
				
			||||||
	#ifdef _SinglePoint
 | 
						#ifdef _SinglePoint
 | 
				
			||||||
		#ifdef _Spot
 | 
							#ifdef _Spot
 | 
				
			||||||
			#ifndef _LTC
 | 
								#ifndef _LTC
 | 
				
			||||||
				uniform sampler2DShadow shadowMapSpot[1];
 | 
									uniform sampler2DShadow shadowMapSpot[1];
 | 
				
			||||||
 | 
									#ifdef _ShadowMapTransparent
 | 
				
			||||||
				uniform sampler2D shadowMapSpotTransparent[1];
 | 
									uniform sampler2D shadowMapSpotTransparent[1];
 | 
				
			||||||
				uniform mat4 LWVPSpot[1];
 | 
									#endif
 | 
				
			||||||
 | 
									uniform mat4 LWVPSpotArray[1];
 | 
				
			||||||
			#endif
 | 
								#endif
 | 
				
			||||||
		#else
 | 
							#else
 | 
				
			||||||
			uniform samplerCubeShadow shadowMapPoint[1];
 | 
								uniform samplerCubeShadow shadowMapPoint[1];
 | 
				
			||||||
 | 
								#ifdef _ShadowMapTransparent
 | 
				
			||||||
			uniform samplerCube shadowMapPointTransparent[1];
 | 
								uniform samplerCube shadowMapPointTransparent[1];
 | 
				
			||||||
 | 
								#endif
 | 
				
			||||||
			uniform vec2 lightProj;
 | 
								uniform vec2 lightProj;
 | 
				
			||||||
		#endif
 | 
							#endif
 | 
				
			||||||
	#endif
 | 
						#endif
 | 
				
			||||||
	#ifdef _Clusters
 | 
						#ifdef _Clusters
 | 
				
			||||||
		#ifdef _SingleAtlas
 | 
							#ifdef _SingleAtlas
 | 
				
			||||||
		//!uniform sampler2DShadow shadowMapAtlas;
 | 
							//!uniform sampler2DShadow shadowMapAtlas;
 | 
				
			||||||
 | 
							#ifdef _ShadowMapTransparent
 | 
				
			||||||
		//!uniform sampler2D shadowMapAtlasTransparent;
 | 
							//!uniform sampler2D shadowMapAtlasTransparent;
 | 
				
			||||||
		#endif
 | 
							#endif
 | 
				
			||||||
 | 
							#endif
 | 
				
			||||||
		uniform vec2 lightProj;
 | 
							uniform vec2 lightProj;
 | 
				
			||||||
		#ifdef _ShadowMapAtlas
 | 
							#ifdef _ShadowMapAtlas
 | 
				
			||||||
		#ifndef _SingleAtlas
 | 
							#ifndef _SingleAtlas
 | 
				
			||||||
		uniform sampler2DShadow shadowMapAtlasPoint;
 | 
							uniform sampler2DShadow shadowMapAtlasPoint;
 | 
				
			||||||
 | 
							#ifdef _ShadowMapTransparent
 | 
				
			||||||
		uniform sampler2D shadowMapAtlasPointTransparent;
 | 
							uniform sampler2D shadowMapAtlasPointTransparent;
 | 
				
			||||||
		#endif
 | 
							#endif
 | 
				
			||||||
 | 
							#endif
 | 
				
			||||||
		#else
 | 
							#else
 | 
				
			||||||
		uniform samplerCubeShadow shadowMapPoint[4];
 | 
							uniform samplerCubeShadow shadowMapPoint[4];
 | 
				
			||||||
 | 
							#ifdef _ShadowMapTransparent
 | 
				
			||||||
		uniform samplerCube shadowMapPointTransparent[4];
 | 
							uniform samplerCube shadowMapPointTransparent[4];
 | 
				
			||||||
		#endif
 | 
							#endif
 | 
				
			||||||
 | 
							#endif
 | 
				
			||||||
		#ifdef _Spot
 | 
							#ifdef _Spot
 | 
				
			||||||
			#ifdef _ShadowMapAtlas
 | 
								#ifdef _ShadowMapAtlas
 | 
				
			||||||
			#ifndef _SingleAtlas
 | 
								#ifndef _SingleAtlas
 | 
				
			||||||
			uniform sampler2DShadow shadowMapAtlasSpot;
 | 
								uniform sampler2DShadow shadowMapAtlasSpot;
 | 
				
			||||||
 | 
								#ifdef _ShadowMapTransparent
 | 
				
			||||||
			uniform sampler2D shadowMapAtlasSpotTransparent;
 | 
								uniform sampler2D shadowMapAtlasSpotTransparent;
 | 
				
			||||||
			#endif
 | 
								#endif
 | 
				
			||||||
 | 
								#endif
 | 
				
			||||||
			#else
 | 
								#else
 | 
				
			||||||
			uniform sampler2DShadow shadowMapSpot[4];
 | 
								uniform sampler2DShadow shadowMapSpot[4];
 | 
				
			||||||
 | 
								#ifdef _ShadowMapTransparent
 | 
				
			||||||
			uniform sampler2D shadowMapSpotTransparent[4];
 | 
								uniform sampler2D shadowMapSpotTransparent[4];
 | 
				
			||||||
			#endif
 | 
								#endif
 | 
				
			||||||
 | 
								#endif
 | 
				
			||||||
			uniform mat4 LWVPSpotArray[maxLightsCluster];
 | 
								uniform mat4 LWVPSpotArray[maxLightsCluster];
 | 
				
			||||||
		#endif
 | 
							#endif
 | 
				
			||||||
	#endif
 | 
						#endif
 | 
				
			||||||
@ -81,28 +95,35 @@ uniform sampler2D sltcMag;
 | 
				
			|||||||
#ifndef _Spot
 | 
					#ifndef _Spot
 | 
				
			||||||
	#ifdef _SinglePoint
 | 
						#ifdef _SinglePoint
 | 
				
			||||||
		uniform sampler2DShadow shadowMapSpot[1];
 | 
							uniform sampler2DShadow shadowMapSpot[1];
 | 
				
			||||||
 | 
							#ifdef _ShadowMapTransparent
 | 
				
			||||||
		uniform sampler2D shadowMapSpotTransparent[1];
 | 
							uniform sampler2D shadowMapSpotTransparent[1];
 | 
				
			||||||
		uniform mat4 LWVPSpot[1];
 | 
							#endif
 | 
				
			||||||
 | 
							uniform mat4 LWVPSpotArray[1];
 | 
				
			||||||
	#endif
 | 
						#endif
 | 
				
			||||||
	#ifdef _Clusters
 | 
						#ifdef _Clusters
 | 
				
			||||||
		uniform sampler2DShadow shadowMapSpot[maxLightsCluster];
 | 
							uniform sampler2DShadow shadowMapSpot[maxLightsCluster];
 | 
				
			||||||
 | 
							#ifdef _ShadowMapTransparent
 | 
				
			||||||
		uniform sampler2D shadowMapSpotTransparent[maxLightsCluster];
 | 
							uniform sampler2D shadowMapSpotTransparent[maxLightsCluster];
 | 
				
			||||||
 | 
							#endif
 | 
				
			||||||
		uniform mat4 LWVPSpotArray[maxLightsCluster];
 | 
							uniform mat4 LWVPSpotArray[maxLightsCluster];
 | 
				
			||||||
	#endif
 | 
						#endif
 | 
				
			||||||
	#endif
 | 
					#endif
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, const vec3 lp, const vec3 lightCol,
 | 
					vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, const vec3 lp, const vec3 lightCol,
 | 
				
			||||||
	const vec3 albedo, const float rough, const float spec, const vec3 f0
 | 
						const vec3 albedo, const float rough, const float spec, const vec3 f0
 | 
				
			||||||
	#ifdef _ShadowMap
 | 
						#ifdef _ShadowMap
 | 
				
			||||||
		, int index, float bias, bool receiveShadow, bool transparent
 | 
							, int index, float bias, bool receiveShadow
 | 
				
			||||||
 | 
						#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
							, bool transparent
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
	#endif
 | 
						#endif
 | 
				
			||||||
	#ifdef _Spot
 | 
						#ifdef _Spot
 | 
				
			||||||
		, const bool isSpot, const float spotSize, float spotBlend, vec3 spotDir, vec2 scale, vec3 right
 | 
							, const bool isSpot, const float spotSize, float spotBlend, vec3 spotDir, vec2 scale, vec3 right
 | 
				
			||||||
	#endif
 | 
						#endif
 | 
				
			||||||
	#ifdef _VoxelShadow
 | 
						#ifdef _VoxelShadow
 | 
				
			||||||
		, sampler3D voxels, sampler3D voxelsSDF, float clipmaps[10 * voxelgiClipmapCount]
 | 
							, sampler3D voxels, sampler3D voxelsSDF, float clipmaps[10 * voxelgiClipmapCount], vec2 velocity
 | 
				
			||||||
	#endif
 | 
						#endif
 | 
				
			||||||
	#ifdef _MicroShadowing
 | 
						#ifdef _MicroShadowing
 | 
				
			||||||
		, float occ
 | 
							, float occ
 | 
				
			||||||
@ -148,23 +169,67 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
 | 
				
			|||||||
	#endif
 | 
						#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	#ifdef _VoxelShadow
 | 
						#ifdef _VoxelShadow
 | 
				
			||||||
	vec4 g2 = textureLod(gbuffer2, gl_FragCoord.xy, 0.0);
 | 
						vec3 lightDir = l;
 | 
				
			||||||
	direct *= (1.0 - traceShadow(p, n, voxels, voxelsSDF, l, clipmaps, gl_FragCoord.xy, g2.rg).r) * voxelgiShad;
 | 
						#ifdef _Spot
 | 
				
			||||||
 | 
						if (isSpot)
 | 
				
			||||||
 | 
							lightDir = spotDir;
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
						direct *= (1.0 - traceShadow(p, n, voxels, voxelsSDF, lightDir, clipmaps, gl_FragCoord.xy, velocity).r) * voxelgiShad;
 | 
				
			||||||
	#endif
 | 
						#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	#ifdef _LTC
 | 
						#ifdef _LTC
 | 
				
			||||||
	#ifdef _ShadowMap
 | 
						#ifdef _ShadowMap
 | 
				
			||||||
		if (receiveShadow) {
 | 
							if (receiveShadow) {
 | 
				
			||||||
			#ifdef _SinglePoint
 | 
								#ifdef _SinglePoint
 | 
				
			||||||
			vec4 lPos = LWVPSpotArray[0] * vec4(p + n * bias * 10, 1.0);
 | 
								vec4 lPos = LWVPSpot[0] * vec4(p + n * bias * 10, 1.0);
 | 
				
			||||||
			direct *= shadowTest(shadowMapSpot[0], shadowMapSpotTransparent[0], lPos.xyz / lPos.w, bias, transparent);
 | 
								direct *= shadowTest(shadowMapSpot[0],
 | 
				
			||||||
 | 
													#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
													shadowMapSpotTransparent[0],
 | 
				
			||||||
 | 
													#endif
 | 
				
			||||||
 | 
													lPos.xyz / lPos.w, bias
 | 
				
			||||||
 | 
													#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
													, transparent
 | 
				
			||||||
 | 
													#endif
 | 
				
			||||||
 | 
													);
 | 
				
			||||||
			#endif
 | 
								#endif
 | 
				
			||||||
			#ifdef _Clusters
 | 
								#ifdef _Clusters
 | 
				
			||||||
			vec4 lPos = LWVPSpotArray[index] * vec4(p + n * bias * 10, 1.0);
 | 
								vec4 lPos = LWVPSpot[index] * vec4(p + n * bias * 10, 1.0);
 | 
				
			||||||
			if (index == 0) direct *= shadowTest(shadowMapSpot[0], shadowMapSpotTransparent[0], lPos.xyz / lPos.w, bias, transparent);
 | 
								if (index == 0) direct *= shadowTest(shadowMapSpot[0],
 | 
				
			||||||
			else if (index == 1) direct *= shadowTest(shadowMapSpot[1], shadowMapSpotTransparent[1], lPos.xyz / lPos.w, bias, transparent);
 | 
																	#ifdef _ShadowMapTransparent
 | 
				
			||||||
			else if (index == 2) direct *= shadowTest(shadowMapSpot[2], shadowMapSpotTransparent[2], lPos.xyz / lPos.w, bias, transparent);
 | 
																	shadowMapSpotTransparent[0],
 | 
				
			||||||
			else if (index == 3) direct *= shadowTest(shadowMapSpot[3], shadowMapSpotTransparent[3], lPos.xyz / lPos.w, bias, transparent);
 | 
																	#endif
 | 
				
			||||||
 | 
																	lPos.xyz / lPos.w, bias
 | 
				
			||||||
 | 
																	#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																	, transparent
 | 
				
			||||||
 | 
																	#endif
 | 
				
			||||||
 | 
																	);
 | 
				
			||||||
 | 
								else if (index == 1) direct *= shadowTest(shadowMapSpot[1],
 | 
				
			||||||
 | 
																		#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																		shadowMapSpotTransparent[1],
 | 
				
			||||||
 | 
																		#endif
 | 
				
			||||||
 | 
																		lPos.xyz / lPos.w, bias
 | 
				
			||||||
 | 
																		#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																		, transparent
 | 
				
			||||||
 | 
																		#endif
 | 
				
			||||||
 | 
																		);
 | 
				
			||||||
 | 
								else if (index == 2) direct *= shadowTest(shadowMapSpot[2],
 | 
				
			||||||
 | 
																		#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																		shadowMapSpotTransparent[2],
 | 
				
			||||||
 | 
																		#endif
 | 
				
			||||||
 | 
																		lPos.xyz / lPos.w, bias
 | 
				
			||||||
 | 
																		#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																		, transparent
 | 
				
			||||||
 | 
																		#endif
 | 
				
			||||||
 | 
																		);
 | 
				
			||||||
 | 
								else if (index == 3) direct *= shadowTest(shadowMapSpot[3],
 | 
				
			||||||
 | 
																		#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																		shadowMapSpotTransparent[3],
 | 
				
			||||||
 | 
																		#endif
 | 
				
			||||||
 | 
																		lPos.xyz / lPos.w, bias
 | 
				
			||||||
 | 
																		#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																		, transparent
 | 
				
			||||||
 | 
																		#endif
 | 
				
			||||||
 | 
																		);
 | 
				
			||||||
			#endif
 | 
								#endif
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	#endif
 | 
						#endif
 | 
				
			||||||
@ -178,25 +243,76 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
 | 
				
			|||||||
		#ifdef _ShadowMap
 | 
							#ifdef _ShadowMap
 | 
				
			||||||
			if (receiveShadow) {
 | 
								if (receiveShadow) {
 | 
				
			||||||
				#ifdef _SinglePoint
 | 
									#ifdef _SinglePoint
 | 
				
			||||||
				vec4 lPos = LWVPSpot[0] * vec4(p + n * bias * 10, 1.0);
 | 
									vec4 lPos = LWVPSpotArray[0] * vec4(p + n * bias * 10, 1.0);
 | 
				
			||||||
				direct *= shadowTest(shadowMapSpot[0], shadowMapSpotTransparent[0], lPos.xyz / lPos.w, bias, transparent);
 | 
									direct *= shadowTest(shadowMapSpot[0],
 | 
				
			||||||
 | 
														#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
														shadowMapSpotTransparent[0],
 | 
				
			||||||
 | 
														#endif
 | 
				
			||||||
 | 
														lPos.xyz / lPos.w, bias
 | 
				
			||||||
 | 
														#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
														, transparent
 | 
				
			||||||
 | 
														#endif
 | 
				
			||||||
 | 
														);
 | 
				
			||||||
				#endif
 | 
									#endif
 | 
				
			||||||
				#ifdef _Clusters
 | 
									#ifdef _Clusters
 | 
				
			||||||
					vec4 lPos = LWVPSpotArray[index] * vec4(p + n * bias * 10, 1.0);
 | 
										vec4 lPos = LWVPSpotArray[index] * vec4(p + n * bias * 10, 1.0);
 | 
				
			||||||
					#ifdef _ShadowMapAtlas
 | 
										#ifdef _ShadowMapAtlas
 | 
				
			||||||
						direct *= shadowTest(
 | 
											direct *= shadowTest(
 | 
				
			||||||
 | 
																#ifdef _ShadowMapTransparent
 | 
				
			||||||
											#ifndef _SingleAtlas
 | 
																#ifndef _SingleAtlas
 | 
				
			||||||
											shadowMapAtlasSpot, shadowMapAtlasSpotTransparent
 | 
																shadowMapAtlasSpot, shadowMapAtlasSpotTransparent
 | 
				
			||||||
											#else
 | 
																#else
 | 
				
			||||||
											shadowMapAtlas, shadowMapAtlasTransparent
 | 
																shadowMapAtlas, shadowMapAtlasTransparent
 | 
				
			||||||
											#endif
 | 
																#endif
 | 
				
			||||||
							, lPos.xyz / lPos.w, bias, transparent
 | 
																#else
 | 
				
			||||||
 | 
																#ifndef _SingleAtlas
 | 
				
			||||||
 | 
																shadowMapAtlasSpot
 | 
				
			||||||
 | 
																#else
 | 
				
			||||||
 | 
																shadowMapAtlas
 | 
				
			||||||
 | 
																#endif
 | 
				
			||||||
 | 
																#endif
 | 
				
			||||||
 | 
																, lPos.xyz / lPos.w, bias
 | 
				
			||||||
 | 
																#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																, transparent
 | 
				
			||||||
 | 
																#endif
 | 
				
			||||||
											);
 | 
																);
 | 
				
			||||||
					#else
 | 
										#else
 | 
				
			||||||
							 if (index == 0) direct *= shadowTest(shadowMapSpot[0], shadowMapSpotTransparent[0], lPos.xyz / lPos.w, bias, transparent);
 | 
												 if (index == 0) direct *= shadowTest(shadowMapSpot[0],
 | 
				
			||||||
						else if (index == 1) direct *= shadowTest(shadowMapSpot[1], shadowMapSpotTransparent[1], lPos.xyz / lPos.w, bias, transparent);
 | 
																					#ifdef _ShadowMapTransparent
 | 
				
			||||||
						else if (index == 2) direct *= shadowTest(shadowMapSpot[2], shadowMapSpotTransparent[2], lPos.xyz / lPos.w, bias, transparent);
 | 
																					shadowMapSpotTransparent[0],
 | 
				
			||||||
						else if (index == 3) direct *= shadowTest(shadowMapSpot[3], shadowMapSpotTransparent[3], lPos.xyz / lPos.w, bias, transparent);
 | 
																					#endif
 | 
				
			||||||
 | 
																					lPos.xyz / lPos.w, bias
 | 
				
			||||||
 | 
																					#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																					, transparent
 | 
				
			||||||
 | 
																					#endif
 | 
				
			||||||
 | 
																					);
 | 
				
			||||||
 | 
											else if (index == 1) direct *= shadowTest(shadowMapSpot[1],
 | 
				
			||||||
 | 
																					#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																					shadowMapSpotTransparent[1],
 | 
				
			||||||
 | 
																					#endif
 | 
				
			||||||
 | 
																					lPos.xyz / lPos.w, bias
 | 
				
			||||||
 | 
																					#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																					, transparent
 | 
				
			||||||
 | 
																					#endif
 | 
				
			||||||
 | 
																					);
 | 
				
			||||||
 | 
											else if (index == 2) direct *= shadowTest(shadowMapSpot[2],
 | 
				
			||||||
 | 
																					#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																					shadowMapSpotTransparent[2],
 | 
				
			||||||
 | 
																					#endif
 | 
				
			||||||
 | 
																					lPos.xyz / lPos.w, bias
 | 
				
			||||||
 | 
																					#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																					, transparent
 | 
				
			||||||
 | 
																					#endif
 | 
				
			||||||
 | 
																					);
 | 
				
			||||||
 | 
											else if (index == 3) direct *= shadowTest(shadowMapSpot[3],
 | 
				
			||||||
 | 
																					#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																					shadowMapSpotTransparent[3],
 | 
				
			||||||
 | 
																					#endif
 | 
				
			||||||
 | 
																					lPos.xyz / lPos.w, bias
 | 
				
			||||||
 | 
																					#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																					, transparent
 | 
				
			||||||
 | 
																					#endif
 | 
				
			||||||
 | 
																					);
 | 
				
			||||||
					#endif
 | 
										#endif
 | 
				
			||||||
				#endif
 | 
									#endif
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@ -213,24 +329,75 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
 | 
				
			|||||||
		if (receiveShadow) {
 | 
							if (receiveShadow) {
 | 
				
			||||||
			#ifdef _SinglePoint
 | 
								#ifdef _SinglePoint
 | 
				
			||||||
			#ifndef _Spot
 | 
								#ifndef _Spot
 | 
				
			||||||
			direct *= PCFCube(shadowMapPoint[0], shadowMapPointTransparent[0], ld, -l, bias, lightProj, n, transparent);
 | 
								direct *= PCFCube(shadowMapPoint[0],
 | 
				
			||||||
 | 
												#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
												shadowMapPointTransparent[0],
 | 
				
			||||||
 | 
												#endif
 | 
				
			||||||
 | 
												ld, -l, bias, lightProj, n
 | 
				
			||||||
 | 
												#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
												, transparent
 | 
				
			||||||
 | 
												#endif
 | 
				
			||||||
 | 
												);
 | 
				
			||||||
			#endif
 | 
								#endif
 | 
				
			||||||
			#endif
 | 
								#endif
 | 
				
			||||||
			#ifdef _Clusters
 | 
								#ifdef _Clusters
 | 
				
			||||||
				#ifdef _ShadowMapAtlas
 | 
									#ifdef _ShadowMapAtlas
 | 
				
			||||||
				direct *= PCFFakeCube(
 | 
									direct *= PCFFakeCube(
 | 
				
			||||||
 | 
														#ifdef _ShadowMapTransparent
 | 
				
			||||||
									#ifndef _SingleAtlas
 | 
														#ifndef _SingleAtlas
 | 
				
			||||||
									shadowMapAtlasPoint, shadowMapAtlasPointTransparent
 | 
														shadowMapAtlasPoint, shadowMapAtlasPointTransparent
 | 
				
			||||||
									#else
 | 
														#else
 | 
				
			||||||
									shadowMapAtlas, shadowMapAtlasTransparent
 | 
														shadowMapAtlas, shadowMapAtlasTransparent
 | 
				
			||||||
									#endif
 | 
														#endif
 | 
				
			||||||
					, ld, -l, bias, lightProj, n, index, transparent
 | 
														#else
 | 
				
			||||||
 | 
														#ifndef _SingleAtlas
 | 
				
			||||||
 | 
														shadowMapAtlasPoint
 | 
				
			||||||
 | 
														#else
 | 
				
			||||||
 | 
														shadowMapAtlas
 | 
				
			||||||
 | 
														#endif
 | 
				
			||||||
 | 
														#endif
 | 
				
			||||||
 | 
														, ld, -l, bias, lightProj, n, index
 | 
				
			||||||
 | 
														#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
														, transparent
 | 
				
			||||||
 | 
														#endif
 | 
				
			||||||
									);
 | 
														);
 | 
				
			||||||
				#else
 | 
									#else
 | 
				
			||||||
					 if (index == 0) direct *= PCFCube(shadowMapPoint[0], shadowMapPointTransparent[0], ld, -l, bias, lightProj, n, transparent);
 | 
										 if (index == 0) direct *= PCFCube(shadowMapPoint[0],
 | 
				
			||||||
				else if (index == 1) direct *= PCFCube(shadowMapPoint[1], shadowMapPointTransparent[1], ld, -l, bias, lightProj, n, transparent);
 | 
																		#ifdef _ShadowMapTransparent
 | 
				
			||||||
				else if (index == 2) direct *= PCFCube(shadowMapPoint[2], shadowMapPointTransparent[2], ld, -l, bias, lightProj, n, transparent);
 | 
																		shadowMapPointTransparent[0],
 | 
				
			||||||
				else if (index == 3) direct *= PCFCube(shadowMapPoint[3], shadowMapPointTransparent[3], ld, -l, bias, lightProj, n, transparent);
 | 
																		#endif
 | 
				
			||||||
 | 
																		ld, -l, bias, lightProj, n
 | 
				
			||||||
 | 
																		#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																		, transparent
 | 
				
			||||||
 | 
																		#endif
 | 
				
			||||||
 | 
																		);
 | 
				
			||||||
 | 
									else if (index == 1) direct *= PCFCube(shadowMapPoint[1],
 | 
				
			||||||
 | 
																		#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																		shadowMapPointTransparent[1],
 | 
				
			||||||
 | 
																		#endif
 | 
				
			||||||
 | 
																		ld, -l, bias, lightProj, n
 | 
				
			||||||
 | 
																		#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																		, transparent
 | 
				
			||||||
 | 
																		#endif
 | 
				
			||||||
 | 
																		);
 | 
				
			||||||
 | 
									else if (index == 2) direct *= PCFCube(shadowMapPoint[2],
 | 
				
			||||||
 | 
																		#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																		shadowMapPointTransparent[2],
 | 
				
			||||||
 | 
																		#endif
 | 
				
			||||||
 | 
																		ld, -l, bias, lightProj, n
 | 
				
			||||||
 | 
																		#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																		, transparent
 | 
				
			||||||
 | 
																		#endif
 | 
				
			||||||
 | 
																		);
 | 
				
			||||||
 | 
									else if (index == 3) direct *= PCFCube(shadowMapPoint[3],
 | 
				
			||||||
 | 
																		#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																		shadowMapPointTransparent[3],
 | 
				
			||||||
 | 
																		#endif
 | 
				
			||||||
 | 
																		ld, -l, bias, lightProj, n
 | 
				
			||||||
 | 
																		#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																		, transparent
 | 
				
			||||||
 | 
																		#endif
 | 
				
			||||||
 | 
																		);
 | 
				
			||||||
				#endif
 | 
									#endif
 | 
				
			||||||
			#endif
 | 
								#endif
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@ -239,4 +406,274 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
 | 
				
			|||||||
	return direct;
 | 
						return direct;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef _VoxelGI
 | 
				
			||||||
 | 
					vec3 sampleLightVoxels(const vec3 p, const vec3 n, const vec3 v, const float dotNV, const vec3 lp, const vec3 lightCol,
 | 
				
			||||||
 | 
						const vec3 albedo, const float rough, const float spec, const vec3 f0
 | 
				
			||||||
 | 
						#ifdef _ShadowMap
 | 
				
			||||||
 | 
							, int index, float bias, bool receiveShadow
 | 
				
			||||||
 | 
						#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
							, bool transparent
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
						#ifdef _Spot
 | 
				
			||||||
 | 
							, const bool isSpot, const float spotSize, float spotBlend, vec3 spotDir, vec2 scale, vec3 right
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
						vec3 ld = lp - p;
 | 
				
			||||||
 | 
						vec3 l = normalize(ld);
 | 
				
			||||||
 | 
						vec3 h = normalize(v + l);
 | 
				
			||||||
 | 
						float dotNH = max(0.0, dot(n, h));
 | 
				
			||||||
 | 
						float dotVH = max(0.0, dot(v, h));
 | 
				
			||||||
 | 
						float dotNL = max(0.0, dot(n, l));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#ifdef _LTC
 | 
				
			||||||
 | 
						float theta = acos(dotNV);
 | 
				
			||||||
 | 
						vec2 tuv = vec2(rough, theta / (0.5 * PI));
 | 
				
			||||||
 | 
						tuv = tuv * LUT_SCALE + LUT_BIAS;
 | 
				
			||||||
 | 
						vec4 t = textureLod(sltcMat, tuv, 0.0);
 | 
				
			||||||
 | 
						mat3 invM = mat3(
 | 
				
			||||||
 | 
							vec3(1.0, 0.0, t.y),
 | 
				
			||||||
 | 
							vec3(0.0, t.z, 0.0),
 | 
				
			||||||
 | 
							vec3(t.w, 0.0, t.x));
 | 
				
			||||||
 | 
						float ltcspec = ltcEvaluate(n, v, dotNV, p, invM, lightArea0, lightArea1, lightArea2, lightArea3);
 | 
				
			||||||
 | 
						ltcspec *= textureLod(sltcMag, tuv, 0.0).a;
 | 
				
			||||||
 | 
						float ltcdiff = ltcEvaluate(n, v, dotNV, p, mat3(1.0), lightArea0, lightArea1, lightArea2, lightArea3);
 | 
				
			||||||
 | 
						vec3 direct = albedo * ltcdiff + ltcspec * spec * 0.05;
 | 
				
			||||||
 | 
						#else
 | 
				
			||||||
 | 
						vec3 direct = lambertDiffuseBRDF(albedo, dotNL) +
 | 
				
			||||||
 | 
									  specularBRDF(f0, rough, dotNL, dotNH, dotNV, dotVH) * spec;
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						direct *= attenuate(distance(p, lp));
 | 
				
			||||||
 | 
						direct *= lightCol;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#ifdef _LTC
 | 
				
			||||||
 | 
						#ifdef _ShadowMap
 | 
				
			||||||
 | 
							if (receiveShadow) {
 | 
				
			||||||
 | 
								#ifdef _SinglePoint
 | 
				
			||||||
 | 
								vec4 lPos = LWVPSpot[0] * vec4(p + n * bias * 10, 1.0);
 | 
				
			||||||
 | 
								direct *= shadowTest(shadowMapSpot[0],
 | 
				
			||||||
 | 
													#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
													shadowMapSpotTransparent[0],
 | 
				
			||||||
 | 
													#endif
 | 
				
			||||||
 | 
													lPos.xyz / lPos.w, bias
 | 
				
			||||||
 | 
													#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
													, transparent
 | 
				
			||||||
 | 
													#endif
 | 
				
			||||||
 | 
													);
 | 
				
			||||||
 | 
								#endif
 | 
				
			||||||
 | 
								#ifdef _Clusters
 | 
				
			||||||
 | 
								vec4 lPos = LWVPSpot[index] * vec4(p + n * bias * 10, 1.0);
 | 
				
			||||||
 | 
								if (index == 0) direct *= shadowTest(shadowMapSpot[0],
 | 
				
			||||||
 | 
																	#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																	shadowMapSpotTransparent[0],
 | 
				
			||||||
 | 
																	#endif
 | 
				
			||||||
 | 
																	lPos.xyz / lPos.w, bias
 | 
				
			||||||
 | 
																	#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																	, transparent
 | 
				
			||||||
 | 
																	#endif
 | 
				
			||||||
 | 
																	);
 | 
				
			||||||
 | 
								else if (index == 1) direct *= shadowTest(shadowMapSpot[1],
 | 
				
			||||||
 | 
																		#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																		shadowMapSpotTransparent[1],
 | 
				
			||||||
 | 
																		#endif
 | 
				
			||||||
 | 
																		lPos.xyz / lPos.w, bias
 | 
				
			||||||
 | 
																		#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																		, transparent
 | 
				
			||||||
 | 
																		#endif
 | 
				
			||||||
 | 
																		);
 | 
				
			||||||
 | 
								else if (index == 2) direct *= shadowTest(shadowMapSpot[2],
 | 
				
			||||||
 | 
																		#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																		shadowMapSpotTransparent[2],
 | 
				
			||||||
 | 
																		#endif
 | 
				
			||||||
 | 
																		lPos.xyz / lPos.w, bias
 | 
				
			||||||
 | 
																		#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																		, transparent
 | 
				
			||||||
 | 
																		#endif
 | 
				
			||||||
 | 
																		);
 | 
				
			||||||
 | 
								else if (index == 3) direct *= shadowTest(shadowMapSpot[3],
 | 
				
			||||||
 | 
																		#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																		shadowMapSpotTransparent[3],
 | 
				
			||||||
 | 
																		#endif
 | 
				
			||||||
 | 
																		lPos.xyz / lPos.w, bias
 | 
				
			||||||
 | 
																		#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																		, transparent
 | 
				
			||||||
 | 
																		#endif
 | 
				
			||||||
 | 
																		);
 | 
				
			||||||
 | 
								#endif
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
						return direct;
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#ifdef _Spot
 | 
				
			||||||
 | 
						if (isSpot) {
 | 
				
			||||||
 | 
							direct *= spotlightMask(l, spotDir, right, scale, spotSize, spotBlend);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							#ifdef _ShadowMap
 | 
				
			||||||
 | 
								if (receiveShadow) {
 | 
				
			||||||
 | 
									#ifdef _SinglePoint
 | 
				
			||||||
 | 
									vec4 lPos = LWVPSpotArray[0] * vec4(p + n * bias * 10, 1.0);
 | 
				
			||||||
 | 
									direct *= shadowTest(shadowMapSpot[0],
 | 
				
			||||||
 | 
														#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
														shadowMapSpotTransparent[0],
 | 
				
			||||||
 | 
														#endif
 | 
				
			||||||
 | 
														lPos.xyz / lPos.w, bias
 | 
				
			||||||
 | 
														#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
														, transparent
 | 
				
			||||||
 | 
														#endif
 | 
				
			||||||
 | 
														);
 | 
				
			||||||
 | 
									#endif
 | 
				
			||||||
 | 
									#ifdef _Clusters
 | 
				
			||||||
 | 
										vec4 lPos = LWVPSpotArray[index] * vec4(p + n * bias * 10, 1.0);
 | 
				
			||||||
 | 
										#ifdef _ShadowMapAtlas
 | 
				
			||||||
 | 
											direct *= shadowTest(
 | 
				
			||||||
 | 
																#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																#ifndef _SingleAtlas
 | 
				
			||||||
 | 
																shadowMapAtlasSpot, shadowMapAtlasSpotTransparent
 | 
				
			||||||
 | 
																#else
 | 
				
			||||||
 | 
																shadowMapAtlas, shadowMapAtlasTransparent
 | 
				
			||||||
 | 
																#endif
 | 
				
			||||||
 | 
																#else
 | 
				
			||||||
 | 
																#ifndef _SingleAtlas
 | 
				
			||||||
 | 
																shadowMapAtlasSpot
 | 
				
			||||||
 | 
																#else
 | 
				
			||||||
 | 
																shadowMapAtlas
 | 
				
			||||||
 | 
																#endif
 | 
				
			||||||
 | 
																#endif
 | 
				
			||||||
 | 
																, lPos.xyz / lPos.w, bias
 | 
				
			||||||
 | 
																#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																, transparent
 | 
				
			||||||
 | 
																#endif
 | 
				
			||||||
 | 
																);
 | 
				
			||||||
 | 
										#else
 | 
				
			||||||
 | 
												 if (index == 0) direct *= shadowTest(shadowMapSpot[0],
 | 
				
			||||||
 | 
																					#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																					shadowMapSpotTransparent[0],
 | 
				
			||||||
 | 
																					#endif
 | 
				
			||||||
 | 
																					lPos.xyz / lPos.w, bias
 | 
				
			||||||
 | 
																					#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																					, transparent
 | 
				
			||||||
 | 
																					#endif
 | 
				
			||||||
 | 
																					);
 | 
				
			||||||
 | 
											else if (index == 1) direct *= shadowTest(shadowMapSpot[1],
 | 
				
			||||||
 | 
																					#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																					shadowMapSpotTransparent[1],
 | 
				
			||||||
 | 
																					#endif
 | 
				
			||||||
 | 
																					lPos.xyz / lPos.w, bias
 | 
				
			||||||
 | 
																					#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																					, transparent
 | 
				
			||||||
 | 
																					#endif
 | 
				
			||||||
 | 
																					);
 | 
				
			||||||
 | 
											else if (index == 2) direct *= shadowTest(shadowMapSpot[2],
 | 
				
			||||||
 | 
																					#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																					shadowMapSpotTransparent[2],
 | 
				
			||||||
 | 
																					#endif
 | 
				
			||||||
 | 
																					lPos.xyz / lPos.w, bias
 | 
				
			||||||
 | 
																					#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																					, transparent
 | 
				
			||||||
 | 
																					#endif
 | 
				
			||||||
 | 
																					);
 | 
				
			||||||
 | 
											else if (index == 3) direct *= shadowTest(shadowMapSpot[3],
 | 
				
			||||||
 | 
																					#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																					shadowMapSpotTransparent[3],
 | 
				
			||||||
 | 
																					#endif
 | 
				
			||||||
 | 
																					lPos.xyz / lPos.w, bias
 | 
				
			||||||
 | 
																					#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																					, transparent
 | 
				
			||||||
 | 
																					#endif
 | 
				
			||||||
 | 
																					);
 | 
				
			||||||
 | 
										#endif
 | 
				
			||||||
 | 
									#endif
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							#endif
 | 
				
			||||||
 | 
							return direct;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#ifdef _LightIES
 | 
				
			||||||
 | 
						direct *= iesAttenuation(-l);
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#ifdef _ShadowMap
 | 
				
			||||||
 | 
							if (receiveShadow) {
 | 
				
			||||||
 | 
								#ifdef _SinglePoint
 | 
				
			||||||
 | 
								#ifndef _Spot
 | 
				
			||||||
 | 
								direct *= PCFCube(shadowMapPoint[0],
 | 
				
			||||||
 | 
												#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
												shadowMapPointTransparent[0],
 | 
				
			||||||
 | 
												#endif
 | 
				
			||||||
 | 
												ld, -l, bias, lightProj, n
 | 
				
			||||||
 | 
												#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
												, transparent
 | 
				
			||||||
 | 
												#endif
 | 
				
			||||||
 | 
												);
 | 
				
			||||||
 | 
								#endif
 | 
				
			||||||
 | 
								#endif
 | 
				
			||||||
 | 
								#ifdef _Clusters
 | 
				
			||||||
 | 
									#ifdef _ShadowMapAtlas
 | 
				
			||||||
 | 
									direct *= PCFFakeCube(
 | 
				
			||||||
 | 
														#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
														#ifndef _SingleAtlas
 | 
				
			||||||
 | 
														shadowMapAtlasPoint, shadowMapAtlasPointTransparent
 | 
				
			||||||
 | 
														#else
 | 
				
			||||||
 | 
														shadowMapAtlas, shadowMapAtlasTransparent
 | 
				
			||||||
 | 
														#endif
 | 
				
			||||||
 | 
														#else
 | 
				
			||||||
 | 
														#ifndef _SingleAtlas
 | 
				
			||||||
 | 
														shadowMapAtlasPoint
 | 
				
			||||||
 | 
														#else
 | 
				
			||||||
 | 
														shadowMapAtlas
 | 
				
			||||||
 | 
														#endif
 | 
				
			||||||
 | 
														#endif
 | 
				
			||||||
 | 
														, ld, -l, bias, lightProj, n, index
 | 
				
			||||||
 | 
														#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
														, transparent
 | 
				
			||||||
 | 
														#endif
 | 
				
			||||||
 | 
														);
 | 
				
			||||||
 | 
									#else
 | 
				
			||||||
 | 
										 if (index == 0) direct *= PCFCube(shadowMapPoint[0],
 | 
				
			||||||
 | 
																		#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																		shadowMapPointTransparent[0],
 | 
				
			||||||
 | 
																		#endif
 | 
				
			||||||
 | 
																		ld, -l, bias, lightProj, n
 | 
				
			||||||
 | 
																		#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																		, transparent
 | 
				
			||||||
 | 
																		#endif
 | 
				
			||||||
 | 
																		);
 | 
				
			||||||
 | 
									else if (index == 1) direct *= PCFCube(shadowMapPoint[1],
 | 
				
			||||||
 | 
																		#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																		shadowMapPointTransparent[1],
 | 
				
			||||||
 | 
																		#endif
 | 
				
			||||||
 | 
																		ld, -l, bias, lightProj, n
 | 
				
			||||||
 | 
																		#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																		, transparent
 | 
				
			||||||
 | 
																		#endif
 | 
				
			||||||
 | 
																		);
 | 
				
			||||||
 | 
									else if (index == 2) direct *= PCFCube(shadowMapPoint[2],
 | 
				
			||||||
 | 
																		#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																		shadowMapPointTransparent[2],
 | 
				
			||||||
 | 
																		#endif
 | 
				
			||||||
 | 
																		ld, -l, bias, lightProj, n
 | 
				
			||||||
 | 
																		#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																		, transparent
 | 
				
			||||||
 | 
																		#endif
 | 
				
			||||||
 | 
																		);
 | 
				
			||||||
 | 
									else if (index == 3) direct *= PCFCube(shadowMapPoint[3],
 | 
				
			||||||
 | 
																		#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																		shadowMapPointTransparent[3],
 | 
				
			||||||
 | 
																		#endif
 | 
				
			||||||
 | 
																		ld, -l, bias, lightProj, n
 | 
				
			||||||
 | 
																		#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																		, transparent
 | 
				
			||||||
 | 
																		#endif
 | 
				
			||||||
 | 
																		);
 | 
				
			||||||
 | 
									#endif
 | 
				
			||||||
 | 
								#endif
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return direct;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
				
			|||||||
@ -58,7 +58,15 @@ vec2 sampleCube(vec3 dir, out int faceIndex) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
vec3 PCF(sampler2DShadow shadowMap, sampler2D shadowMapTransparent, const vec2 uv, const float compare, const vec2 smSize, const bool transparent) {
 | 
					vec3 PCF(sampler2DShadow shadowMap,
 | 
				
			||||||
 | 
							#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
							sampler2D shadowMapTransparent,
 | 
				
			||||||
 | 
							#endif
 | 
				
			||||||
 | 
							const vec2 uv, const float compare, const vec2 smSize
 | 
				
			||||||
 | 
							#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
							, const bool transparent
 | 
				
			||||||
 | 
							#endif
 | 
				
			||||||
 | 
							) {
 | 
				
			||||||
	vec3 result = vec3(0.0);
 | 
						vec3 result = vec3(0.0);
 | 
				
			||||||
	result.x = texture(shadowMap, vec3(uv + (vec2(-1.0, -1.0) / smSize), compare));
 | 
						result.x = texture(shadowMap, vec3(uv + (vec2(-1.0, -1.0) / smSize), compare));
 | 
				
			||||||
	result.x += texture(shadowMap, vec3(uv + (vec2(-1.0, 0.0) / smSize), compare));
 | 
						result.x += texture(shadowMap, vec3(uv + (vec2(-1.0, 0.0) / smSize), compare));
 | 
				
			||||||
@ -71,11 +79,13 @@ vec3 PCF(sampler2DShadow shadowMap, sampler2D shadowMapTransparent, const vec2 u
 | 
				
			|||||||
	result.x += texture(shadowMap, vec3(uv + (vec2(1.0, 1.0) / smSize), compare));
 | 
						result.x += texture(shadowMap, vec3(uv + (vec2(1.0, 1.0) / smSize), compare));
 | 
				
			||||||
	result = result.xxx / 9.0;
 | 
						result = result.xxx / 9.0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#ifdef _ShadowMapTransparent
 | 
				
			||||||
	if (transparent == false) {
 | 
						if (transparent == false) {
 | 
				
			||||||
		vec4 shadowmap_transparent = texture(shadowMapTransparent, uv);
 | 
							vec4 shadowmap_transparent = texture(shadowMapTransparent, uv);
 | 
				
			||||||
		if (shadowmap_transparent.a < compare)
 | 
							if (shadowmap_transparent.a < compare)
 | 
				
			||||||
			result *= shadowmap_transparent.rgb;
 | 
								result *= shadowmap_transparent.rgb;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return result;
 | 
						return result;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -87,7 +97,15 @@ float lpToDepth(vec3 lp, const vec2 lightProj) {
 | 
				
			|||||||
	return zcomp * 0.5 + 0.5;
 | 
						return zcomp * 0.5 + 0.5;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
vec3 PCFCube(samplerCubeShadow shadowMapCube, samplerCube shadowMapCubeTransparent, const vec3 lp, vec3 ml, const float bias, const vec2 lightProj, const vec3 n, const bool transparent) {
 | 
					vec3 PCFCube(samplerCubeShadow shadowMapCube,
 | 
				
			||||||
 | 
								#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
								samplerCube shadowMapCubeTransparent,
 | 
				
			||||||
 | 
								#endif
 | 
				
			||||||
 | 
								const vec3 lp, vec3 ml, const float bias, const vec2 lightProj, const vec3 n
 | 
				
			||||||
 | 
								#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
								, const bool transparent
 | 
				
			||||||
 | 
								#endif
 | 
				
			||||||
 | 
								) {
 | 
				
			||||||
	const float s = shadowmapCubePcfSize; // TODO: incorrect...
 | 
						const float s = shadowmapCubePcfSize; // TODO: incorrect...
 | 
				
			||||||
	float compare = lpToDepth(lp, lightProj) - bias * 1.5;
 | 
						float compare = lpToDepth(lp, lightProj) - bias * 1.5;
 | 
				
			||||||
	ml = ml + n * bias * 20;
 | 
						ml = ml + n * bias * 20;
 | 
				
			||||||
@ -106,11 +124,13 @@ vec3 PCFCube(samplerCubeShadow shadowMapCube, samplerCube shadowMapCubeTranspare
 | 
				
			|||||||
	result.x += texture(shadowMapCube, vec4(ml + vec3(-s, -s, -s), compare));
 | 
						result.x += texture(shadowMapCube, vec4(ml + vec3(-s, -s, -s), compare));
 | 
				
			||||||
	result = result.xxx / 9.0;
 | 
						result = result.xxx / 9.0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#ifdef _ShadowMapTransparent
 | 
				
			||||||
	if (transparent == false) {
 | 
						if (transparent == false) {
 | 
				
			||||||
		vec4 shadowmap_transparent = texture(shadowMapCubeTransparent, ml);
 | 
							vec4 shadowmap_transparent = texture(shadowMapCubeTransparent, ml);
 | 
				
			||||||
		if (shadowmap_transparent.a < compare)
 | 
							if (shadowmap_transparent.a < compare)
 | 
				
			||||||
			result *= shadowmap_transparent.rgb;
 | 
								result *= shadowmap_transparent.rgb;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return result;
 | 
						return result;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -209,21 +229,31 @@ vec2 transformOffsetedUV(const int faceIndex, out int newFaceIndex, vec2 uv) {
 | 
				
			|||||||
	return uv;
 | 
						return uv;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
vec3 PCFFakeCube(sampler2DShadow shadowMap, sampler2D shadowMapTransparent, const vec3 lp, vec3 ml, const float bias, const vec2 lightProj, const vec3 n, const int index, const bool transparent) {
 | 
					vec3 PCFFakeCube(sampler2DShadow shadowMap,
 | 
				
			||||||
 | 
									#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
									sampler2D shadowMapTransparent,
 | 
				
			||||||
 | 
									#endif
 | 
				
			||||||
 | 
									const vec3 lp, vec3 ml, const float bias, const vec2 lightProj, const vec3 n, const int index
 | 
				
			||||||
 | 
									#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
									, const bool transparent
 | 
				
			||||||
 | 
									#endif
 | 
				
			||||||
 | 
									) {
 | 
				
			||||||
	const vec2 smSize = smSizeUniform; // TODO: incorrect...
 | 
						const vec2 smSize = smSizeUniform; // TODO: incorrect...
 | 
				
			||||||
	const float compare = lpToDepth(lp, lightProj) - bias * 1.5;
 | 
						const float compare = lpToDepth(lp, lightProj) - bias * 1.5;
 | 
				
			||||||
	ml = ml + n * bias * 20;
 | 
						ml = ml + n * bias * 20;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	int faceIndex = 0;
 | 
						int faceIndex = 0;
 | 
				
			||||||
	const int lightIndex = index * 6;
 | 
						const int lightIndex = index * 6;
 | 
				
			||||||
	const vec2 uv = sampleCube(ml, faceIndex);
 | 
						const vec2 uv = sampleCube(ml, faceIndex);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	vec4 pointLightTile = pointLightDataArray[lightIndex + faceIndex]; // x: tile X offset, y: tile Y offset, z: tile size relative to atlas
 | 
						vec4 pointLightTile = pointLightDataArray[lightIndex + faceIndex]; // x: tile X offset, y: tile Y offset, z: tile size relative to atlas
 | 
				
			||||||
	vec2 uvtiled = pointLightTile.z * uv + pointLightTile.xy;
 | 
						vec2 uvtiled = pointLightTile.z * uv + pointLightTile.xy;
 | 
				
			||||||
	#ifdef _FlipY
 | 
						#ifdef _FlipY
 | 
				
			||||||
	uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system
 | 
						uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system
 | 
				
			||||||
	#endif
 | 
						#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (any(lessThan(uvtiled, vec2(0.0))) || any(greaterThan(uvtiled, vec2(1.0)))) {
 | 
				
			||||||
 | 
							return vec3(1.0); // Handle edge cases by returning full light
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	vec3 result = vec3(0.0);
 | 
						vec3 result = vec3(0.0);
 | 
				
			||||||
	result.x += texture(shadowMap, vec3(uvtiled, compare));
 | 
						result.x += texture(shadowMap, vec3(uvtiled, compare));
 | 
				
			||||||
	// soft shadowing
 | 
						// soft shadowing
 | 
				
			||||||
@ -236,14 +266,6 @@ vec3 PCFFakeCube(sampler2DShadow shadowMap, sampler2D shadowMapTransparent, cons
 | 
				
			|||||||
	#endif
 | 
						#endif
 | 
				
			||||||
	result.x += texture(shadowMap, vec3(uvtiled, compare));
 | 
						result.x += texture(shadowMap, vec3(uvtiled, compare));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uvtiled = transformOffsetedUV(faceIndex, newFaceIndex, vec2(uv + (vec2(-1.0, 1.0) / smSize)));
 | 
					 | 
				
			||||||
	pointLightTile = pointLightDataArray[lightIndex + newFaceIndex];
 | 
					 | 
				
			||||||
	uvtiled = pointLightTile.z * uvtiled + pointLightTile.xy;
 | 
					 | 
				
			||||||
	#ifdef _FlipY
 | 
					 | 
				
			||||||
	uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system
 | 
					 | 
				
			||||||
	#endif
 | 
					 | 
				
			||||||
	result.x += texture(shadowMap, vec3(uvtiled, compare));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	uvtiled = transformOffsetedUV(faceIndex, newFaceIndex, vec2(uv + (vec2(0.0, -1.0) / smSize)));
 | 
						uvtiled = transformOffsetedUV(faceIndex, newFaceIndex, vec2(uv + (vec2(0.0, -1.0) / smSize)));
 | 
				
			||||||
	pointLightTile = pointLightDataArray[lightIndex + newFaceIndex];
 | 
						pointLightTile = pointLightDataArray[lightIndex + newFaceIndex];
 | 
				
			||||||
	uvtiled = pointLightTile.z * uvtiled + pointLightTile.xy;
 | 
						uvtiled = pointLightTile.z * uvtiled + pointLightTile.xy;
 | 
				
			||||||
@ -300,30 +322,47 @@ vec3 PCFFakeCube(sampler2DShadow shadowMap, sampler2D shadowMapTransparent, cons
 | 
				
			|||||||
	uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system
 | 
						uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system
 | 
				
			||||||
	#endif
 | 
						#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#ifdef _ShadowMapTransparent
 | 
				
			||||||
	if (transparent == false) {
 | 
						if (transparent == false) {
 | 
				
			||||||
		vec4 shadowmap_transparent = texture(shadowMapTransparent, uvtiled);
 | 
							vec4 shadowmap_transparent = texture(shadowMapTransparent, uvtiled);
 | 
				
			||||||
		if (shadowmap_transparent.a < compare)
 | 
							if (shadowmap_transparent.a < compare)
 | 
				
			||||||
			result *= shadowmap_transparent.rgb;
 | 
								result *= shadowmap_transparent.rgb;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return result;
 | 
						return result;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
vec3 shadowTest(sampler2DShadow shadowMap, sampler2D shadowMapTransparent, const vec3 lPos, const float shadowsBias, const bool transparent) {
 | 
					vec3 shadowTest(sampler2DShadow shadowMap,
 | 
				
			||||||
 | 
									#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
									sampler2D shadowMapTransparent,
 | 
				
			||||||
 | 
									#endif
 | 
				
			||||||
 | 
									const vec3 lPos, const float shadowsBias
 | 
				
			||||||
 | 
									#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
									, const bool transparent
 | 
				
			||||||
 | 
									#endif
 | 
				
			||||||
 | 
									) {
 | 
				
			||||||
	#ifdef _SMSizeUniform
 | 
						#ifdef _SMSizeUniform
 | 
				
			||||||
	vec2 smSize = smSizeUniform;
 | 
						vec2 smSize = smSizeUniform;
 | 
				
			||||||
	#else
 | 
						#else
 | 
				
			||||||
	const vec2 smSize = shadowmapSize;
 | 
						const vec2 smSize = shadowmapSize;
 | 
				
			||||||
	#endif
 | 
						#endif
 | 
				
			||||||
	if (lPos.x < 0.0 || lPos.y < 0.0 || lPos.x > 1.0 || lPos.y > 1.0) return vec3(1.0);
 | 
						if (lPos.x < 0.0 || lPos.y < 0.0 || lPos.x > 1.0 || lPos.y > 1.0) return vec3(1.0);
 | 
				
			||||||
	return PCF(shadowMap, shadowMapTransparent, lPos.xy, lPos.z - shadowsBias, smSize, transparent);
 | 
						return PCF(shadowMap,
 | 
				
			||||||
 | 
									#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
									shadowMapTransparent,
 | 
				
			||||||
 | 
									#endif
 | 
				
			||||||
 | 
									lPos.xy, lPos.z - shadowsBias, smSize
 | 
				
			||||||
 | 
									#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
									, transparent
 | 
				
			||||||
 | 
									#endif
 | 
				
			||||||
 | 
									);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _CSM
 | 
					#ifdef _CSM
 | 
				
			||||||
mat4 getCascadeMat(const float d, out int casi, out int casIndex) {
 | 
					mat4 getCascadeMat(const float d, out int casi, out int casIndex) {
 | 
				
			||||||
	const int c = shadowmapCascades;
 | 
						const int c = shadowmapCascades;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Get cascade index
 | 
						// Get cascade index
 | 
				
			||||||
	// TODO: use bounding box slice selection instead of sphere
 | 
						// TODO: use bounding box slice selection instead of sphere
 | 
				
			||||||
	const vec4 ci = vec4(float(c > 0), float(c > 1), float(c > 2), float(c > 3));
 | 
						const vec4 ci = vec4(float(c > 0), float(c > 1), float(c > 2), float(c > 3));
 | 
				
			||||||
@ -339,21 +378,26 @@ mat4 getCascadeMat(const float d, out int casi, out int casIndex) {
 | 
				
			|||||||
		float(d > casData[c * 4].z),
 | 
							float(d > casData[c * 4].z),
 | 
				
			||||||
		float(d > casData[c * 4].w));
 | 
							float(d > casData[c * 4].w));
 | 
				
			||||||
	casi = int(min(dot(ci, comp), c));
 | 
						casi = int(min(dot(ci, comp), c));
 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Get cascade mat
 | 
						// Get cascade mat
 | 
				
			||||||
	casIndex = casi * 4;
 | 
						casIndex = casi * 4;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	return mat4(
 | 
						return mat4(
 | 
				
			||||||
		casData[casIndex    ],
 | 
							casData[casIndex    ],
 | 
				
			||||||
		casData[casIndex + 1],
 | 
							casData[casIndex + 1],
 | 
				
			||||||
		casData[casIndex + 2],
 | 
							casData[casIndex + 2],
 | 
				
			||||||
		casData[casIndex + 3]);
 | 
							casData[casIndex + 3]);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	// if (casIndex == 0) return mat4(casData[0], casData[1], casData[2], casData[3]);
 | 
						// if (casIndex == 0) return mat4(casData[0], casData[1], casData[2], casData[3]);
 | 
				
			||||||
	// ..
 | 
						// ..
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
vec3 shadowTestCascade(sampler2DShadow shadowMap, sampler2D shadowMapTransparent, const vec3 eye, const vec3 p, const float shadowsBias, const bool transparent) {
 | 
					vec3 shadowTestCascade(sampler2DShadow shadowMap,
 | 
				
			||||||
 | 
										   #ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
										   sampler2D shadowMapTransparent,
 | 
				
			||||||
 | 
										   #endif
 | 
				
			||||||
 | 
										   const vec3 eye, const vec3 p, const float shadowsBias
 | 
				
			||||||
 | 
										   #ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
										   , const bool transparent
 | 
				
			||||||
 | 
										   #endif
 | 
				
			||||||
 | 
										   ) {
 | 
				
			||||||
	#ifdef _SMSizeUniform
 | 
						#ifdef _SMSizeUniform
 | 
				
			||||||
	vec2 smSize = smSizeUniform;
 | 
						vec2 smSize = smSizeUniform;
 | 
				
			||||||
	#else
 | 
						#else
 | 
				
			||||||
@ -361,16 +405,22 @@ vec3 shadowTestCascade(sampler2DShadow shadowMap, sampler2D shadowMapTransparent
 | 
				
			|||||||
	#endif
 | 
						#endif
 | 
				
			||||||
	const int c = shadowmapCascades;
 | 
						const int c = shadowmapCascades;
 | 
				
			||||||
	float d = distance(eye, p);
 | 
						float d = distance(eye, p);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	int casi;
 | 
						int casi;
 | 
				
			||||||
	int casIndex;
 | 
						int casIndex;
 | 
				
			||||||
	mat4 LWVP = getCascadeMat(d, casi, casIndex);
 | 
						mat4 LWVP = getCascadeMat(d, casi, casIndex);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	vec4 lPos = LWVP * vec4(p, 1.0);
 | 
						vec4 lPos = LWVP * vec4(p, 1.0);
 | 
				
			||||||
	lPos.xyz /= lPos.w;
 | 
						lPos.xyz /= lPos.w;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	vec3 visibility = vec3(1.0);
 | 
						vec3 visibility = vec3(1.0);
 | 
				
			||||||
	if (lPos.w > 0.0) visibility = PCF(shadowMap, shadowMapTransparent, lPos.xy, lPos.z - shadowsBias, smSize, transparent);
 | 
						if (lPos.w > 0.0) visibility = PCF(shadowMap,
 | 
				
			||||||
 | 
														#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
														shadowMapTransparent,
 | 
				
			||||||
 | 
														#endif
 | 
				
			||||||
 | 
														lPos.xy, lPos.z - shadowsBias, smSize
 | 
				
			||||||
 | 
														#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
														, transparent
 | 
				
			||||||
 | 
														#endif
 | 
				
			||||||
 | 
														);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Blend cascade
 | 
						// Blend cascade
 | 
				
			||||||
	// https://github.com/TheRealMJP/Shadows
 | 
						// https://github.com/TheRealMJP/Shadows
 | 
				
			||||||
@ -389,13 +439,20 @@ vec3 shadowTestCascade(sampler2DShadow shadowMap, sampler2D shadowMapTransparent
 | 
				
			|||||||
		vec4 lPos2 = LWVP2 * vec4(p, 1.0);
 | 
							vec4 lPos2 = LWVP2 * vec4(p, 1.0);
 | 
				
			||||||
		lPos2.xyz /= lPos2.w;
 | 
							lPos2.xyz /= lPos2.w;
 | 
				
			||||||
		vec3 visibility2 = vec3(1.0);
 | 
							vec3 visibility2 = vec3(1.0);
 | 
				
			||||||
		if (lPos2.w > 0.0) visibility2 = PCF(shadowMap, shadowMapTransparent, lPos2.xy, lPos2.z - shadowsBias, smSize, transparent);
 | 
							if (lPos2.w > 0.0) visibility2 = PCF(shadowMap,
 | 
				
			||||||
 | 
																#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																shadowMapTransparent,
 | 
				
			||||||
 | 
																#endif
 | 
				
			||||||
 | 
																lPos.xy, lPos.z - shadowsBias, smSize
 | 
				
			||||||
 | 
																#ifdef _ShadowMapTransparent
 | 
				
			||||||
 | 
																, transparent
 | 
				
			||||||
 | 
																#endif
 | 
				
			||||||
 | 
																);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		float lerpAmt = smoothstep(0.0, blendThres, splitDist);
 | 
							float lerpAmt = smoothstep(0.0, blendThres, splitDist);
 | 
				
			||||||
		return mix(visibility2, visibility, lerpAmt);
 | 
							return mix(visibility2, visibility, lerpAmt);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return visibility;
 | 
						return visibility;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Visualize cascades
 | 
						// Visualize cascades
 | 
				
			||||||
	// if (ci == 0) albedo.rgb = vec3(1.0, 0.0, 0.0);
 | 
						// if (ci == 0) albedo.rgb = vec3(1.0, 0.0, 0.0);
 | 
				
			||||||
	// if (ci == 4) albedo.rgb = vec3(0.0, 1.0, 0.0);
 | 
						// if (ci == 4) albedo.rgb = vec3(0.0, 1.0, 0.0);
 | 
				
			||||||
 | 
				
			|||||||
@ -11,6 +11,8 @@ vec3 uncharted2Tonemap(const vec3 x) {
 | 
				
			|||||||
vec3 tonemapUncharted2(const vec3 color) {
 | 
					vec3 tonemapUncharted2(const vec3 color) {
 | 
				
			||||||
	const float W = 11.2;
 | 
						const float W = 11.2;
 | 
				
			||||||
	const float exposureBias = 2.0;
 | 
						const float exposureBias = 2.0;
 | 
				
			||||||
 | 
					    // TODO - Find out why black world value of 0.0,0.0,0.0 turns to white pixels
 | 
				
			||||||
 | 
						if (dot(color, color) < 0.001) return vec3(0.001);
 | 
				
			||||||
	vec3 curr = uncharted2Tonemap(exposureBias * color);
 | 
						vec3 curr = uncharted2Tonemap(exposureBias * color);
 | 
				
			||||||
	vec3 whiteScale = 1.0 / uncharted2Tonemap(vec3(W));
 | 
						vec3 whiteScale = 1.0 / uncharted2Tonemap(vec3(W));
 | 
				
			||||||
	return curr * whiteScale;
 | 
						return curr * whiteScale;
 | 
				
			||||||
 | 
				
			|||||||
@ -11,6 +11,11 @@
 | 
				
			|||||||
#include "std/light_common.glsl"
 | 
					#include "std/light_common.glsl"
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef _CPostprocess
 | 
				
			||||||
 | 
					uniform vec3 PPComp11;
 | 
				
			||||||
 | 
					uniform vec4 PPComp17;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uniform sampler2D gbufferD;
 | 
					uniform sampler2D gbufferD;
 | 
				
			||||||
uniform sampler2D snoise;
 | 
					uniform sampler2D snoise;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -87,7 +92,13 @@ out float fragColor;
 | 
				
			|||||||
const float tScat = 0.08;
 | 
					const float tScat = 0.08;
 | 
				
			||||||
const float tAbs = 0.0;
 | 
					const float tAbs = 0.0;
 | 
				
			||||||
const float tExt = tScat + tAbs;
 | 
					const float tExt = tScat + tAbs;
 | 
				
			||||||
const float stepLen = 1.0 / volumSteps;
 | 
					#ifdef _CPostprocess
 | 
				
			||||||
 | 
						float stepLen = 1.0 / int(PPComp11.y);
 | 
				
			||||||
 | 
						float AirTurbidity = PPComp17.w;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						const float stepLen = 1.0 / volumSteps;
 | 
				
			||||||
 | 
						float AirTurbidity = volumAirTurbidity;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
const float lighting = 0.4;
 | 
					const float lighting = 0.4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void rayStep(inout vec3 curPos, inout float curOpticalDepth, inout float scatteredLightAmount, float stepLenWorld, vec3 viewVecNorm) {
 | 
					void rayStep(inout vec3 curPos, inout float curOpticalDepth, inout float scatteredLightAmount, float stepLenWorld, vec3 viewVecNorm) {
 | 
				
			||||||
@ -162,5 +173,5 @@ void main() {
 | 
				
			|||||||
		rayStep(curPos, curOpticalDepth, scatteredLightAmount, stepLenWorld, viewVecNorm);
 | 
							rayStep(curPos, curOpticalDepth, scatteredLightAmount, stepLenWorld, viewVecNorm);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fragColor = scatteredLightAmount * volumAirTurbidity;
 | 
						fragColor = scatteredLightAmount * AirTurbidity;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -140,6 +140,16 @@
 | 
				
			|||||||
					"link": "_biasLightWorldViewProjectionMatrixSpot3",
 | 
										"link": "_biasLightWorldViewProjectionMatrixSpot3",
 | 
				
			||||||
					"ifndef": ["_ShadowMapAtlas"],
 | 
										"ifndef": ["_ShadowMapAtlas"],
 | 
				
			||||||
					"ifdef": ["_Spot", "_ShadowMap"]
 | 
										"ifdef": ["_Spot", "_ShadowMap"]
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										"name": "PPComp11",
 | 
				
			||||||
 | 
										"link": "_PPComp11",
 | 
				
			||||||
 | 
										"ifdef": ["_CPostprocess"]
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										"name": "PPComp17",
 | 
				
			||||||
 | 
										"link": "_PPComp17",
 | 
				
			||||||
 | 
										"ifdef": ["_CPostprocess"]
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			],
 | 
								],
 | 
				
			||||||
			"texture_params": [],
 | 
								"texture_params": [],
 | 
				
			||||||
 | 
				
			|||||||
@ -87,25 +87,28 @@ float lpToDepth(vec3 lp, const vec2 lightProj) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void main() {
 | 
					void main() {
 | 
				
			||||||
	int res = voxelgiResolution.x;
 | 
						int res = voxelgiResolution.x;
 | 
				
			||||||
	for (int i = 0; i < 6; i++) {
 | 
					 | 
				
			||||||
	ivec3 dst = ivec3(gl_GlobalInvocationID.xyz);
 | 
						ivec3 dst = ivec3(gl_GlobalInvocationID.xyz);
 | 
				
			||||||
		vec3 P = (gl_GlobalInvocationID.xyz + 0.5) / voxelgiResolution;
 | 
					
 | 
				
			||||||
		P = P * 2.0 - 1.0;
 | 
						vec3 wposition = (gl_GlobalInvocationID.xyz + 0.5) / voxelgiResolution.x;
 | 
				
			||||||
 | 
						wposition = wposition * 2.0 - 1.0;
 | 
				
			||||||
 | 
						wposition *= float(clipmaps[int(clipmapLevel * 10)]);
 | 
				
			||||||
 | 
						wposition *= voxelgiResolution.x;
 | 
				
			||||||
 | 
						wposition += vec3(clipmaps[clipmapLevel * 10 + 4], clipmaps[clipmapLevel * 10 + 5], clipmaps[clipmapLevel * 10 + 6]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	float visibility;
 | 
						float visibility;
 | 
				
			||||||
		vec3 lp = lightPos - P;
 | 
						vec3 lp = lightPos -wposition;
 | 
				
			||||||
	vec3 l;
 | 
						vec3 l;
 | 
				
			||||||
	if (lightType == 0) { l = lightDir; visibility = 1.0; }
 | 
						if (lightType == 0) { l = lightDir; visibility = 1.0; }
 | 
				
			||||||
		else { l = normalize(lp); visibility = attenuate(distance(P, lightPos)); }
 | 
						else { l = normalize(lp); visibility = attenuate(distance(wposition, lightPos)); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _ShadowMap
 | 
					#ifdef _ShadowMap
 | 
				
			||||||
	if (lightShadow == 1) {
 | 
						if (lightShadow == 1) {
 | 
				
			||||||
			vec4 lightPosition = LVP * vec4(P, 1.0);
 | 
							vec4 lightPosition = LVP * vec4(wposition, 1.0);
 | 
				
			||||||
		vec3 lPos = lightPosition.xyz / lightPosition.w;
 | 
							vec3 lPos = lightPosition.xyz / lightPosition.w;
 | 
				
			||||||
		visibility = texture(shadowMap, vec3(lPos.xy, lPos.z - shadowsBias)).r;
 | 
							visibility = texture(shadowMap, vec3(lPos.xy, lPos.z - shadowsBias)).r;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	else if (lightShadow == 2) {
 | 
						else if (lightShadow == 2) {
 | 
				
			||||||
			vec4 lightPosition = LVP * vec4(P, 1.0);
 | 
							vec4 lightPosition = LVP * vec4(wposition, 1.0);
 | 
				
			||||||
		vec3 lPos = lightPosition.xyz / lightPosition.w;
 | 
							vec3 lPos = lightPosition.xyz / lightPosition.w;
 | 
				
			||||||
		visibility *= texture(shadowMapSpot, vec3(lPos.xy, lPos.z - shadowsBias)).r;
 | 
							visibility *= texture(shadowMapSpot, vec3(lPos.xy, lPos.z - shadowsBias)).r;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -124,14 +127,9 @@ void main() {
 | 
				
			|||||||
		visibility *= texture(shadowMapPoint, vec4(-l, lpToDepth(lp, lightProj) - shadowsBias)).r;
 | 
							visibility *= texture(shadowMapPoint, vec4(-l, lpToDepth(lp, lightProj) - shadowsBias)).r;
 | 
				
			||||||
		#endif
 | 
							#endif
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	#endif
 | 
					#endif
 | 
				
			||||||
		vec3 uvw_light = (P - vec3(clipmaps[int(clipmapLevel * 10 + 4)], clipmaps[int(clipmapLevel * 10 + 5)], clipmaps[int(clipmapLevel * 10 + 6)])) / (float(clipmaps[int(clipmapLevel * 10)]) * voxelgiResolution);
 | 
					 | 
				
			||||||
		uvw_light = (uvw_light * 0.5 + 0.5);
 | 
					 | 
				
			||||||
		if (any(notEqual(uvw_light, clamp(uvw_light, 0.0, 1.0)))) return;
 | 
					 | 
				
			||||||
		vec3 writecoords_light = floor(uvw_light * voxelgiResolution);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		imageAtomicMax(voxelsLight, ivec3(writecoords_light), uint(visibility * lightColor.r * 255));
 | 
						imageAtomicAdd(voxelsLight, dst, uint(visibility * lightColor.r * 255));
 | 
				
			||||||
		imageAtomicMax(voxelsLight, ivec3(writecoords_light) + ivec3(0, 0, voxelgiResolution.x), uint(visibility * lightColor.g * 255));
 | 
						imageAtomicAdd(voxelsLight, dst + ivec3(0, 0, voxelgiResolution.x), uint(visibility * lightColor.g * 255));
 | 
				
			||||||
		imageAtomicMax(voxelsLight, ivec3(writecoords_light) + ivec3(0, 0, voxelgiResolution.x * 2), uint(visibility * lightColor.b * 255));
 | 
						imageAtomicAdd(voxelsLight, dst + ivec3(0, 0, voxelgiResolution.x * 2), uint(visibility * lightColor.b * 255));
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -27,14 +27,14 @@ layout (local_size_x = 8, local_size_y = 8, local_size_z = 8) in;
 | 
				
			|||||||
#include "std/math.glsl"
 | 
					#include "std/math.glsl"
 | 
				
			||||||
#include "std/gbuffer.glsl"
 | 
					#include "std/gbuffer.glsl"
 | 
				
			||||||
#include "std/imageatomic.glsl"
 | 
					#include "std/imageatomic.glsl"
 | 
				
			||||||
#include "std/voxels_constants.glsl"
 | 
					#include "std/constants.glsl"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _VoxelGI
 | 
					#ifdef _VoxelGI
 | 
				
			||||||
uniform layout(rgba8) image3D voxelsB;
 | 
					uniform layout(rgba8) image3D voxelsB;
 | 
				
			||||||
uniform layout(rgba8) image3D voxelsOut;
 | 
					uniform layout(rgba8) image3D voxelsOut;
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
uniform layout(r16) image3D voxelsB;
 | 
					uniform layout(r8) image3D voxelsB;
 | 
				
			||||||
uniform layout(r16) image3D voxelsOut;
 | 
					uniform layout(r8) image3D voxelsOut;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uniform int clipmapLevel;
 | 
					uniform int clipmapLevel;
 | 
				
			||||||
 | 
				
			|||||||
@ -29,19 +29,38 @@ layout (local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
 | 
				
			|||||||
#include "std/gbuffer.glsl"
 | 
					#include "std/gbuffer.glsl"
 | 
				
			||||||
#include "std/imageatomic.glsl"
 | 
					#include "std/imageatomic.glsl"
 | 
				
			||||||
#include "std/conetrace.glsl"
 | 
					#include "std/conetrace.glsl"
 | 
				
			||||||
 | 
					#include "std/brdf.glsl"
 | 
				
			||||||
 | 
					#include "std/shirr.glsl"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uniform sampler3D voxels;
 | 
					uniform sampler3D voxels;
 | 
				
			||||||
uniform sampler2D gbufferD;
 | 
					uniform sampler2D gbufferD;
 | 
				
			||||||
uniform sampler2D gbuffer0;
 | 
					uniform sampler2D gbuffer0;
 | 
				
			||||||
uniform layout(r16) image2D voxels_ao;
 | 
					uniform layout(rgba8) image2D voxels_ao;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uniform float clipmaps[voxelgiClipmapCount * 10];
 | 
					uniform float clipmaps[voxelgiClipmapCount * 10];
 | 
				
			||||||
uniform mat4 InvVP;
 | 
					uniform mat4 InvVP;
 | 
				
			||||||
uniform vec2 cameraProj;
 | 
					 | 
				
			||||||
uniform vec3 eye;
 | 
					uniform vec3 eye;
 | 
				
			||||||
uniform vec3 eyeLook;
 | 
					 | 
				
			||||||
uniform vec2 postprocess_resolution;
 | 
					uniform vec2 postprocess_resolution;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uniform sampler2D gbuffer1;
 | 
				
			||||||
 | 
					#ifdef _gbuffer2
 | 
				
			||||||
 | 
					uniform sampler2D gbuffer2;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					uniform float envmapStrength;
 | 
				
			||||||
 | 
					#ifdef _Irr
 | 
				
			||||||
 | 
					uniform float shirr[7 * 4];
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef _Brdf
 | 
				
			||||||
 | 
					uniform sampler2D senvmapBrdf;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef _Rad
 | 
				
			||||||
 | 
					uniform sampler2D senvmapRadiance;
 | 
				
			||||||
 | 
					uniform int envmapNumMipmaps;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef _EnvCol
 | 
				
			||||||
 | 
					uniform vec3 backgroundCol;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void main() {
 | 
					void main() {
 | 
				
			||||||
	const vec2 pixel = gl_GlobalInvocationID.xy;
 | 
						const vec2 pixel = gl_GlobalInvocationID.xy;
 | 
				
			||||||
	vec2 uv = (pixel + 0.5) / postprocess_resolution;
 | 
						vec2 uv = (pixel + 0.5) / postprocess_resolution;
 | 
				
			||||||
@ -54,12 +73,11 @@ void main() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	float x = uv.x * 2 - 1;
 | 
						float x = uv.x * 2 - 1;
 | 
				
			||||||
	float y = uv.y * 2 - 1;
 | 
						float y = uv.y * 2 - 1;
 | 
				
			||||||
	vec4 v = vec4(x, y, 1.0, 1.0);
 | 
						vec4 clipPos = vec4(x, y, depth, 1.0);
 | 
				
			||||||
	v = vec4(InvVP * v);
 | 
					    vec4 worldPos = InvVP * clipPos;
 | 
				
			||||||
	v.xyz /= v.w;
 | 
					    vec3 P = worldPos.xyz / worldPos.w;
 | 
				
			||||||
	vec3 viewRay = v.xyz - eye;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	vec3 P = getPos(eye, eyeLook, normalize(viewRay), depth, cameraProj);
 | 
						vec3 v = normalize(eye - P);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	vec4 g0 = textureLod(gbuffer0, uv, 0.0);
 | 
						vec4 g0 = textureLod(gbuffer0, uv, 0.0);
 | 
				
			||||||
	vec3 n;
 | 
						vec3 n;
 | 
				
			||||||
@ -67,7 +85,89 @@ void main() {
 | 
				
			|||||||
	n.xy = n.z >= 0.0 ? g0.xy : octahedronWrap(g0.xy);
 | 
						n.xy = n.z >= 0.0 ? g0.xy : octahedronWrap(g0.xy);
 | 
				
			||||||
	n = normalize(n);
 | 
						n = normalize(n);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	float occ = 1.0 - traceAO(P, n, voxels, clipmaps);
 | 
						float roughness = g0.b;
 | 
				
			||||||
 | 
						float metallic;
 | 
				
			||||||
 | 
						uint matid;
 | 
				
			||||||
 | 
						unpackFloatInt16(g0.a, metallic, matid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	imageStore(voxels_ao, ivec2(pixel), vec4(occ));
 | 
						vec4 g1 = textureLod(gbuffer1, uv, 0.0); // Basecolor.rgb, spec/occ
 | 
				
			||||||
 | 
						vec2 occspec = unpackFloat2(g1.a);
 | 
				
			||||||
 | 
						vec3 albedo = surfaceAlbedo(g1.rgb, metallic); // g1.rgb - basecolor
 | 
				
			||||||
 | 
						vec3 f0 = surfaceF0(g1.rgb, metallic);
 | 
				
			||||||
 | 
						float dotNV = max(dot(n, v), 0.0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef _gbuffer2
 | 
				
			||||||
 | 
						vec4 g2 = textureLod(gbuffer2, uv, 0.0);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef _MicroShadowing
 | 
				
			||||||
 | 
						occspec.x = mix(1.0, occspec.x, dotNV); // AO Fresnel
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef _Brdf
 | 
				
			||||||
 | 
						vec2 envBRDF = texelFetch(senvmapBrdf, ivec2(vec2(dotNV, 1.0 - roughness) * 256.0), 0).xy;
 | 
				
			||||||
 | 
						vec3 F = f0 * envBRDF.x + envBRDF.y;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Envmap
 | 
				
			||||||
 | 
					#ifdef _Irr
 | 
				
			||||||
 | 
						vec4 shPacked[7];
 | 
				
			||||||
 | 
					    for (int i = 0; i < 7; i++) {
 | 
				
			||||||
 | 
					        int base = i * 4;
 | 
				
			||||||
 | 
					        shPacked[i] = vec4(
 | 
				
			||||||
 | 
					            shirr[base],
 | 
				
			||||||
 | 
					            shirr[base + 1],
 | 
				
			||||||
 | 
					            shirr[base + 2],
 | 
				
			||||||
 | 
					            shirr[base + 3]
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
						vec3 envl = shIrradiance(n, shPacked);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#ifdef _gbuffer2
 | 
				
			||||||
 | 
							if (g2.b < 0.5) {
 | 
				
			||||||
 | 
								envl = envl;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								envl = vec3(0.0);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#ifdef _EnvTex
 | 
				
			||||||
 | 
							envl /= PI;
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						vec3 envl = vec3(0.0);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef _Rad
 | 
				
			||||||
 | 
						vec3 reflectionWorld = reflect(-v, n);
 | 
				
			||||||
 | 
						float lod = getMipFromRoughness(roughness, envmapNumMipmaps);
 | 
				
			||||||
 | 
						vec3 prefilteredColor = textureLod(senvmapRadiance, envMapEquirect(reflectionWorld), lod).rgb;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef _EnvLDR
 | 
				
			||||||
 | 
						envl.rgb = pow(envl.rgb, vec3(2.2));
 | 
				
			||||||
 | 
						#ifdef _Rad
 | 
				
			||||||
 | 
							prefilteredColor = pow(prefilteredColor, vec3(2.2));
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						envl.rgb *= albedo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef _Brdf
 | 
				
			||||||
 | 
						envl.rgb *= 1.0 - F; //LV: We should take refracted light into account
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef _Rad // Indirect specular
 | 
				
			||||||
 | 
						envl.rgb += prefilteredColor * F; //LV: Removed "1.5 * occspec.y". Specular should be weighted only by FV LUT
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						#ifdef _EnvCol
 | 
				
			||||||
 | 
						envl.rgb += backgroundCol * F; //LV: Eh, what's the point of weighting it only by F0?
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						envl.rgb *= envmapStrength * occspec.x;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vec3 occ = envl * (1.0 - traceAO(P, n, voxels, clipmaps));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						imageStore(voxels_ao, ivec2(pixel), vec4(occ, 1.0));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -29,19 +29,38 @@ layout (local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
 | 
				
			|||||||
#include "std/gbuffer.glsl"
 | 
					#include "std/gbuffer.glsl"
 | 
				
			||||||
#include "std/imageatomic.glsl"
 | 
					#include "std/imageatomic.glsl"
 | 
				
			||||||
#include "std/conetrace.glsl"
 | 
					#include "std/conetrace.glsl"
 | 
				
			||||||
 | 
					#include "std/brdf.glsl"
 | 
				
			||||||
 | 
					#include "std/shirr.glsl"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uniform sampler3D voxels;
 | 
					uniform sampler3D voxels;
 | 
				
			||||||
uniform sampler2D gbufferD;
 | 
					uniform sampler2D gbufferD;
 | 
				
			||||||
uniform sampler2D gbuffer0;
 | 
					uniform sampler2D gbuffer0;
 | 
				
			||||||
uniform layout(rgba16) image2D voxels_diffuse;
 | 
					uniform layout(rgba8) image2D voxels_diffuse;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uniform float clipmaps[voxelgiClipmapCount * 10];
 | 
					uniform float clipmaps[voxelgiClipmapCount * 10];
 | 
				
			||||||
uniform mat4 InvVP;
 | 
					uniform mat4 InvVP;
 | 
				
			||||||
uniform vec2 cameraProj;
 | 
					 | 
				
			||||||
uniform vec3 eye;
 | 
					uniform vec3 eye;
 | 
				
			||||||
uniform vec3 eyeLook;
 | 
					 | 
				
			||||||
uniform vec2 postprocess_resolution;
 | 
					uniform vec2 postprocess_resolution;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uniform sampler2D gbuffer1;
 | 
				
			||||||
 | 
					#ifdef _gbuffer2
 | 
				
			||||||
 | 
					uniform sampler2D gbuffer2;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					uniform float envmapStrength;
 | 
				
			||||||
 | 
					#ifdef _Irr
 | 
				
			||||||
 | 
					uniform float shirr[7 * 4];
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef _Brdf
 | 
				
			||||||
 | 
					uniform sampler2D senvmapBrdf;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef _Rad
 | 
				
			||||||
 | 
					uniform sampler2D senvmapRadiance;
 | 
				
			||||||
 | 
					uniform int envmapNumMipmaps;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef _EnvCol
 | 
				
			||||||
 | 
					uniform vec3 backgroundCol;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void main() {
 | 
					void main() {
 | 
				
			||||||
	const vec2 pixel = gl_GlobalInvocationID.xy;
 | 
						const vec2 pixel = gl_GlobalInvocationID.xy;
 | 
				
			||||||
	vec2 uv = (pixel + 0.5) / postprocess_resolution;
 | 
						vec2 uv = (pixel + 0.5) / postprocess_resolution;
 | 
				
			||||||
@ -50,16 +69,14 @@ void main() {
 | 
				
			|||||||
	#endif
 | 
						#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	float depth = textureLod(gbufferD, uv, 0.0).r * 2.0 - 1.0;
 | 
						float depth = textureLod(gbufferD, uv, 0.0).r * 2.0 - 1.0;
 | 
				
			||||||
	if (depth == 0) return;
 | 
						if (depth == 0.0) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	float x = uv.x * 2 - 1;
 | 
						float x = uv.x * 2 - 1;
 | 
				
			||||||
	float y = uv.y * 2 - 1;
 | 
						float y = uv.y * 2 - 1;
 | 
				
			||||||
	vec4 v = vec4(x, y, 1.0, 1.0);
 | 
						vec4 clipPos = vec4(x, y, depth, 1.0);
 | 
				
			||||||
	v = vec4(InvVP * v);
 | 
					    vec4 worldPos = InvVP * clipPos;
 | 
				
			||||||
	v.xyz /= v.w;
 | 
					    vec3 P = worldPos.xyz / worldPos.w;
 | 
				
			||||||
	vec3 viewRay = v.xyz - eye;
 | 
						vec3 v = normalize(eye - P);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	vec3 P = getPos(eye, eyeLook, normalize(viewRay), depth, cameraProj);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	vec4 g0 = textureLod(gbuffer0, uv, 0.0);
 | 
						vec4 g0 = textureLod(gbuffer0, uv, 0.0);
 | 
				
			||||||
	vec3 n;
 | 
						vec3 n;
 | 
				
			||||||
@ -67,7 +84,94 @@ void main() {
 | 
				
			|||||||
	n.xy = n.z >= 0.0 ? g0.xy : octahedronWrap(g0.xy);
 | 
						n.xy = n.z >= 0.0 ? g0.xy : octahedronWrap(g0.xy);
 | 
				
			||||||
	n = normalize(n);
 | 
						n = normalize(n);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	vec4 color = traceDiffuse(P, n, voxels, clipmaps);
 | 
						float roughness = g0.b;
 | 
				
			||||||
 | 
						float metallic;
 | 
				
			||||||
 | 
						uint matid;
 | 
				
			||||||
 | 
						unpackFloatInt16(g0.a, metallic, matid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	imageStore(voxels_diffuse, ivec2(pixel), color);
 | 
						vec4 g1 = textureLod(gbuffer1, uv, 0.0); // Basecolor.rgb, spec/occ
 | 
				
			||||||
 | 
						vec2 occspec = unpackFloat2(g1.a);
 | 
				
			||||||
 | 
						vec3 albedo = surfaceAlbedo(g1.rgb, metallic); // g1.rgb - basecolor
 | 
				
			||||||
 | 
						vec3 f0 = surfaceF0(g1.rgb, metallic);
 | 
				
			||||||
 | 
						float dotNV = max(dot(n, v), 0.0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef _gbuffer2
 | 
				
			||||||
 | 
						vec4 g2 = textureLod(gbuffer2, uv, 0.0);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef _MicroShadowing
 | 
				
			||||||
 | 
						occspec.x = mix(1.0, occspec.x, dotNV); // AO Fresnel
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef _Brdf
 | 
				
			||||||
 | 
						vec2 envBRDF = texelFetch(senvmapBrdf, ivec2(vec2(dotNV, 1.0 - roughness) * 256.0), 0).xy;
 | 
				
			||||||
 | 
						vec3 F = f0 * envBRDF.x + envBRDF.y;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						vec3 F = f0;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Envmap
 | 
				
			||||||
 | 
					#ifdef _Irr
 | 
				
			||||||
 | 
						vec4 shPacked[7];
 | 
				
			||||||
 | 
					    for (int i = 0; i < 7; i++) {
 | 
				
			||||||
 | 
					        int base = i * 4;
 | 
				
			||||||
 | 
					        shPacked[i] = vec4(
 | 
				
			||||||
 | 
					            shirr[base],
 | 
				
			||||||
 | 
					            shirr[base + 1],
 | 
				
			||||||
 | 
					            shirr[base + 2],
 | 
				
			||||||
 | 
					            shirr[base + 3]
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
						vec3 envl = shIrradiance(n, shPacked);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#ifdef _gbuffer2
 | 
				
			||||||
 | 
							if (g2.b < 0.5) {
 | 
				
			||||||
 | 
								envl = envl;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								envl = vec3(0.0);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#ifdef _EnvTex
 | 
				
			||||||
 | 
							envl /= PI;
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						vec3 envl = vec3(0.0);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef _Rad
 | 
				
			||||||
 | 
						vec3 reflectionWorld = reflect(-v, n);
 | 
				
			||||||
 | 
						float lod = getMipFromRoughness(roughness, envmapNumMipmaps);
 | 
				
			||||||
 | 
						vec3 prefilteredColor = textureLod(senvmapRadiance, envMapEquirect(reflectionWorld), lod).rgb;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef _EnvLDR
 | 
				
			||||||
 | 
						envl.rgb = pow(envl.rgb, vec3(2.2));
 | 
				
			||||||
 | 
						#ifdef _Rad
 | 
				
			||||||
 | 
							prefilteredColor = pow(prefilteredColor, vec3(2.2));
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						envl.rgb *= albedo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef _Brdf
 | 
				
			||||||
 | 
						envl.rgb *= 1.0 - F; //LV: We should take refracted light into account
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef _Rad // Indirect specular
 | 
				
			||||||
 | 
						envl.rgb += prefilteredColor * F; //LV: Removed "1.5 * occspec.y". Specular should be weighted only by FV LUT
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						#ifdef _EnvCol
 | 
				
			||||||
 | 
						envl.rgb += backgroundCol * F; //LV: Eh, what's the point of weighting it only by F0?
 | 
				
			||||||
 | 
						#endif
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						envl.rgb *= envmapStrength * occspec.x;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vec4 trace = traceDiffuse(P, n, voxels, clipmaps);
 | 
				
			||||||
 | 
						vec3 color = trace.rgb * albedo * (1.0 - F);
 | 
				
			||||||
 | 
						color += envl * (1.0 - trace.a);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						imageStore(voxels_diffuse, ivec2(pixel), vec4(color, 1.0));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,79 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
Copyright (c) 2024 Turánszki János
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
					 | 
				
			||||||
of this software and associated documentation files (the "Software"), to deal
 | 
					 | 
				
			||||||
in the Software without restriction, including without limitation the rights
 | 
					 | 
				
			||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
					 | 
				
			||||||
copies of the Software, and to permit persons to whom the Software is
 | 
					 | 
				
			||||||
furnished to do so, subject to the following conditions:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
The above copyright notice and this permission notice shall be included in
 | 
					 | 
				
			||||||
all copies or substantial portions of the Software.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
					 | 
				
			||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
					 | 
				
			||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 | 
					 | 
				
			||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
					 | 
				
			||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
					 | 
				
			||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
					 | 
				
			||||||
THE SOFTWARE.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#version 450
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
layout (local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "compiled.inc"
 | 
					 | 
				
			||||||
#include "std/math.glsl"
 | 
					 | 
				
			||||||
#include "std/gbuffer.glsl"
 | 
					 | 
				
			||||||
#include "std/imageatomic.glsl"
 | 
					 | 
				
			||||||
#include "std/conetrace.glsl"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
uniform sampler2D gbufferD;
 | 
					 | 
				
			||||||
uniform sampler2D gbuffer0;
 | 
					 | 
				
			||||||
uniform sampler3D voxels;
 | 
					 | 
				
			||||||
uniform sampler3D voxelsSDF;
 | 
					 | 
				
			||||||
uniform sampler2D gbuffer_refraction;
 | 
					 | 
				
			||||||
uniform layout(rgba8) image2D voxels_refraction;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
uniform float clipmaps[voxelgiClipmapCount * 10];
 | 
					 | 
				
			||||||
uniform mat4 InvVP;
 | 
					 | 
				
			||||||
uniform vec2 cameraProj;
 | 
					 | 
				
			||||||
uniform vec3 eye;
 | 
					 | 
				
			||||||
uniform vec3 eyeLook;
 | 
					 | 
				
			||||||
uniform vec2 postprocess_resolution;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void main() {
 | 
					 | 
				
			||||||
	const vec2 pixel = gl_GlobalInvocationID.xy;
 | 
					 | 
				
			||||||
	vec2 uv = (pixel + 0.5) / postprocess_resolution;
 | 
					 | 
				
			||||||
	#ifdef _InvY
 | 
					 | 
				
			||||||
	uv.y = 1.0 - uv.y
 | 
					 | 
				
			||||||
	#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	float depth = textureLod(gbufferD, uv, 0.0).r * 2.0 - 1.0;
 | 
					 | 
				
			||||||
	if (depth == 0) return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	vec2 ior_opac = textureLod(gbuffer_refraction, uv, 0.0).xy;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	float x = uv.x * 2 - 1;
 | 
					 | 
				
			||||||
	float y = uv.y * 2 - 1;
 | 
					 | 
				
			||||||
	vec4 v = vec4(x, y, 1.0, 1.0);
 | 
					 | 
				
			||||||
	v = vec4(InvVP * v);
 | 
					 | 
				
			||||||
	v.xyz /= v.w;
 | 
					 | 
				
			||||||
	vec3 viewRay = v.xyz - eye;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	vec3 P = getPos(eye, eyeLook, normalize(viewRay), depth, cameraProj);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	vec4 g0 = textureLod(gbuffer0, uv, 0.0);
 | 
					 | 
				
			||||||
	vec3 n;
 | 
					 | 
				
			||||||
	n.z = 1.0 - abs(g0.x) - abs(g0.y);
 | 
					 | 
				
			||||||
	n.xy = n.z >= 0.0 ? g0.xy : octahedronWrap(g0.xy);
 | 
					 | 
				
			||||||
	n = normalize(n);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	vec3 color = vec3(0.0);
 | 
					 | 
				
			||||||
	if(ior_opac.y < 1.0)
 | 
					 | 
				
			||||||
		color = traceRefraction(P, n, voxels, voxelsSDF, normalize(eye - P), ior_opac.x, g0.b, clipmaps, pixel).rgb;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	imageStore(voxels_refraction, ivec2(pixel), vec4(color, 1.0));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,75 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
Copyright (c) 2024 Turánszki János
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
					 | 
				
			||||||
of this software and associated documentation files (the "Software"), to deal
 | 
					 | 
				
			||||||
in the Software without restriction, including without limitation the rights
 | 
					 | 
				
			||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
					 | 
				
			||||||
copies of the Software, and to permit persons to whom the Software is
 | 
					 | 
				
			||||||
furnished to do so, subject to the following conditions:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
The above copyright notice and this permission notice shall be included in
 | 
					 | 
				
			||||||
all copies or substantial portions of the Software.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
					 | 
				
			||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
					 | 
				
			||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 | 
					 | 
				
			||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
					 | 
				
			||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
					 | 
				
			||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
					 | 
				
			||||||
THE SOFTWARE.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#version 450
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
layout (local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "compiled.inc"
 | 
					 | 
				
			||||||
#include "std/math.glsl"
 | 
					 | 
				
			||||||
#include "std/gbuffer.glsl"
 | 
					 | 
				
			||||||
#include "std/imageatomic.glsl"
 | 
					 | 
				
			||||||
#include "std/conetrace.glsl"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
uniform sampler3D voxels;
 | 
					 | 
				
			||||||
uniform sampler3D voxelsSDF;
 | 
					 | 
				
			||||||
uniform sampler2D gbufferD;
 | 
					 | 
				
			||||||
uniform sampler2D gbuffer0;
 | 
					 | 
				
			||||||
uniform layout(r16) image2D voxels_shadows;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
uniform float clipmaps[voxelgiClipmapCount * 10];
 | 
					 | 
				
			||||||
uniform mat4 InvVP;
 | 
					 | 
				
			||||||
uniform vec2 cameraProj;
 | 
					 | 
				
			||||||
uniform vec3 eye;
 | 
					 | 
				
			||||||
uniform vec3 eyeLook;
 | 
					 | 
				
			||||||
uniform vec2 postprocess_resolution;
 | 
					 | 
				
			||||||
uniform vec3 lPos;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void main() {
 | 
					 | 
				
			||||||
	const vec2 pixel = gl_GlobalInvocationID.xy;
 | 
					 | 
				
			||||||
	vec2 uv = (pixel + 0.5) / postprocess_resolution;
 | 
					 | 
				
			||||||
	#ifdef _InvY
 | 
					 | 
				
			||||||
	uv.y = 1.0 - uv.y;
 | 
					 | 
				
			||||||
	#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	float depth = textureLod(gbufferD, uv, 0.0).r * 2.0 - 1.0;
 | 
					 | 
				
			||||||
	if (depth == 0) return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	float x = uv.x * 2 - 1;
 | 
					 | 
				
			||||||
	float y = uv.y * 2 - 1;
 | 
					 | 
				
			||||||
	vec4 v = vec4(x, y, 1.0, 1.0);
 | 
					 | 
				
			||||||
	v = vec4(InvVP * v);
 | 
					 | 
				
			||||||
	v.xyz /= v.w;
 | 
					 | 
				
			||||||
	vec3 viewRay = v.xyz - eye;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	vec3 P = getPos(eye, eyeLook, normalize(viewRay), depth, cameraProj);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	vec4 g0 = textureLod(gbuffer0, uv, 0.0);
 | 
					 | 
				
			||||||
	vec3 n;
 | 
					 | 
				
			||||||
	n.z = 1.0 - abs(g0.x) - abs(g0.y);
 | 
					 | 
				
			||||||
	n.xy = n.z >= 0.0 ? g0.xy : octahedronWrap(g0.xy);
 | 
					 | 
				
			||||||
	n = normalize(n);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	float occ = 1.0 - traceShadow(P, n, voxels, voxelsSDF, normalize(lPos - P), clipmaps, pixel);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	imageStore(voxels_shadows, ivec2(pixel), vec4(occ));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -29,18 +29,17 @@ layout (local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
 | 
				
			|||||||
#include "std/gbuffer.glsl"
 | 
					#include "std/gbuffer.glsl"
 | 
				
			||||||
#include "std/imageatomic.glsl"
 | 
					#include "std/imageatomic.glsl"
 | 
				
			||||||
#include "std/conetrace.glsl"
 | 
					#include "std/conetrace.glsl"
 | 
				
			||||||
 | 
					#include "std/brdf.glsl"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uniform sampler2D gbufferD;
 | 
					uniform sampler2D gbufferD;
 | 
				
			||||||
uniform sampler2D gbuffer0;
 | 
					uniform sampler2D gbuffer0;
 | 
				
			||||||
uniform sampler3D voxels;
 | 
					uniform sampler3D voxels;
 | 
				
			||||||
uniform sampler3D voxelsSDF;
 | 
					uniform sampler3D voxelsSDF;
 | 
				
			||||||
uniform layout(rgba16) image2D voxels_specular;
 | 
					uniform layout(rgba8) image2D voxels_specular;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uniform float clipmaps[voxelgiClipmapCount * 10];
 | 
					uniform float clipmaps[voxelgiClipmapCount * 10];
 | 
				
			||||||
uniform mat4 InvVP;
 | 
					uniform mat4 InvVP;
 | 
				
			||||||
uniform vec2 cameraProj;
 | 
					 | 
				
			||||||
uniform vec3 eye;
 | 
					uniform vec3 eye;
 | 
				
			||||||
uniform vec3 eyeLook;
 | 
					 | 
				
			||||||
uniform vec2 postprocess_resolution;
 | 
					uniform vec2 postprocess_resolution;
 | 
				
			||||||
uniform sampler2D sveloc;
 | 
					uniform sampler2D sveloc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -56,12 +55,10 @@ void main() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	float x = uv.x * 2 - 1;
 | 
						float x = uv.x * 2 - 1;
 | 
				
			||||||
	float y = uv.y * 2 - 1;
 | 
						float y = uv.y * 2 - 1;
 | 
				
			||||||
	vec4 v = vec4(x, y, 1.0, 1.0);
 | 
						vec4 clipPos = vec4(x, y, depth, 1.0);
 | 
				
			||||||
	v = vec4(InvVP * v);
 | 
					    vec4 worldPos = InvVP * clipPos;
 | 
				
			||||||
	v.xyz /= v.w;
 | 
					    vec3 P = worldPos.xyz / worldPos.w;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	vec3 viewRay = v.xyz - eye;
 | 
					 | 
				
			||||||
	vec3 P = getPos(eye, eyeLook, normalize(viewRay), depth, cameraProj);
 | 
					 | 
				
			||||||
	vec4 g0 = textureLod(gbuffer0, uv, 0.0);
 | 
						vec4 g0 = textureLod(gbuffer0, uv, 0.0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	vec3 n;
 | 
						vec3 n;
 | 
				
			||||||
 | 
				
			|||||||
@ -74,13 +74,9 @@ void main() {
 | 
				
			|||||||
	#endif
 | 
						#endif
 | 
				
			||||||
	#endif
 | 
						#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ivec3 src = ivec3(gl_GlobalInvocationID.xyz);
 | 
						int nor_count = 0;
 | 
				
			||||||
	#ifdef _VoxelGI
 | 
						vec3 avgNormal = vec3(0.0);
 | 
				
			||||||
	vec3 light = vec3(0.0);
 | 
						mat3 TBN = mat3(0.0);
 | 
				
			||||||
	light.r = float(imageLoad(voxelsLight, src)) / 255;
 | 
					 | 
				
			||||||
	light.g = float(imageLoad(voxelsLight, src + ivec3(0, 0, voxelgiResolution.x))) / 255;
 | 
					 | 
				
			||||||
	light.b = float(imageLoad(voxelsLight, src + ivec3(0, 0, voxelgiResolution.x * 2))) / 255;
 | 
					 | 
				
			||||||
	#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (int i = 0; i < 6 + DIFFUSE_CONE_COUNT; i++)
 | 
						for (int i = 0; i < 6 + DIFFUSE_CONE_COUNT; i++)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
@ -90,7 +86,7 @@ void main() {
 | 
				
			|||||||
		float aniso_colors[6];
 | 
							float aniso_colors[6];
 | 
				
			||||||
		#endif
 | 
							#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		src = ivec3(gl_GlobalInvocationID.xyz);
 | 
							ivec3 src = ivec3(gl_GlobalInvocationID.xyz);
 | 
				
			||||||
		src.x += i * res;
 | 
							src.x += i * res;
 | 
				
			||||||
		ivec3 dst = src;
 | 
							ivec3 dst = src;
 | 
				
			||||||
		dst.y += clipmapLevel * res;
 | 
							dst.y += clipmapLevel * res;
 | 
				
			||||||
@ -103,28 +99,47 @@ void main() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		if (i < 6) {
 | 
							if (i < 6) {
 | 
				
			||||||
			#ifdef _VoxelGI
 | 
								#ifdef _VoxelGI
 | 
				
			||||||
 | 
								int count = int(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 15)));
 | 
				
			||||||
 | 
								if (count > 0) {
 | 
				
			||||||
				vec4 basecol = vec4(0.0);
 | 
									vec4 basecol = vec4(0.0);
 | 
				
			||||||
				basecol.r = float(imageLoad(voxels, src)) / 255;
 | 
									basecol.r = float(imageLoad(voxels, src)) / 255;
 | 
				
			||||||
				basecol.g = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x))) / 255;
 | 
									basecol.g = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x))) / 255;
 | 
				
			||||||
				basecol.b = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 2))) / 255;
 | 
									basecol.b = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 2))) / 255;
 | 
				
			||||||
				basecol.a = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 3))) / 255;
 | 
									basecol.a = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 3))) / 255;
 | 
				
			||||||
			basecol /= 4;
 | 
									basecol /= count;
 | 
				
			||||||
				vec3 emission = vec3(0.0);
 | 
									vec3 emission = vec3(0.0);
 | 
				
			||||||
				emission.r = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 4))) / 255;
 | 
									emission.r = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 4))) / 255;
 | 
				
			||||||
				emission.g = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 5))) / 255;
 | 
									emission.g = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 5))) / 255;
 | 
				
			||||||
				emission.b = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 6))) / 255;
 | 
									emission.b = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 6))) / 255;
 | 
				
			||||||
			emission /= 3;
 | 
									emission /= count;
 | 
				
			||||||
				vec3 N = vec3(0.0);
 | 
									vec3 N = vec3(0.0);
 | 
				
			||||||
				N.r = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 7))) / 255;
 | 
									N.r = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 7))) / 255;
 | 
				
			||||||
				N.g = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 8))) / 255;
 | 
									N.g = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 8))) / 255;
 | 
				
			||||||
			N /= 2;
 | 
									N /= count;
 | 
				
			||||||
			vec3 wnormal = decode_oct(N.rg * 2 - 1);
 | 
									N = decode_oct(N.rg * 2.0 - 1.0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (abs(N.x) > 0)
 | 
				
			||||||
 | 
										avgNormal.x += N.x;
 | 
				
			||||||
 | 
									if (abs(N.y) > 0)
 | 
				
			||||||
 | 
										avgNormal.y += N.y;
 | 
				
			||||||
 | 
									if (abs(N.z) > 0)
 | 
				
			||||||
 | 
										avgNormal.z += N.z;
 | 
				
			||||||
 | 
									if (i == 5)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										avgNormal = normalize(avgNormal);
 | 
				
			||||||
 | 
										TBN = makeTangentBasis(avgNormal);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				vec3 envl = vec3(0.0);
 | 
									vec3 envl = vec3(0.0);
 | 
				
			||||||
				envl.r = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 9))) / 255;
 | 
									envl.r = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 9))) / 255;
 | 
				
			||||||
				envl.g = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 10))) / 255;
 | 
									envl.g = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 10))) / 255;
 | 
				
			||||||
				envl.b = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 11))) / 255;
 | 
									envl.b = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 11))) / 255;
 | 
				
			||||||
			envl /= 3;
 | 
									envl /= count;
 | 
				
			||||||
 | 
									vec3 light = vec3(0.0);
 | 
				
			||||||
 | 
									light.r = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 12))) / 255;
 | 
				
			||||||
 | 
									light.g = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 13))) / 255;
 | 
				
			||||||
 | 
									light.b = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 14))) / 255;
 | 
				
			||||||
 | 
									light /= count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				//clipmap to world
 | 
									//clipmap to world
 | 
				
			||||||
				vec3 wposition = (gl_GlobalInvocationID.xyz + 0.5) / voxelgiResolution.x;
 | 
									vec3 wposition = (gl_GlobalInvocationID.xyz + 0.5) / voxelgiResolution.x;
 | 
				
			||||||
@ -134,13 +149,17 @@ void main() {
 | 
				
			|||||||
				wposition += vec3(clipmaps[clipmapLevel * 10 + 4], clipmaps[clipmapLevel * 10 + 5], clipmaps[clipmapLevel * 10 + 6]);
 | 
									wposition += vec3(clipmaps[clipmapLevel * 10 + 4], clipmaps[clipmapLevel * 10 + 5], clipmaps[clipmapLevel * 10 + 6]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				radiance = basecol;
 | 
									radiance = basecol;
 | 
				
			||||||
			vec4 trace = traceDiffuse(wposition, wnormal, voxelsSampler, clipmaps);
 | 
									vec4 trace = traceDiffuse(wposition, N, voxelsSampler, clipmaps);
 | 
				
			||||||
				vec3 indirect = trace.rgb + envl.rgb * (1.0 - trace.a);
 | 
									vec3 indirect = trace.rgb + envl.rgb * (1.0 - trace.a);
 | 
				
			||||||
			radiance.rgb *= light / PI + indirect;
 | 
									radiance.rgb *= light + indirect;
 | 
				
			||||||
				radiance.rgb += emission.rgb;
 | 
									radiance.rgb += emission.rgb;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			#else
 | 
								#else
 | 
				
			||||||
 | 
								int count = int(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x)));
 | 
				
			||||||
 | 
								if (count > 0) {
 | 
				
			||||||
				opac = float(imageLoad(voxels, src)) / 255;
 | 
									opac = float(imageLoad(voxels, src)) / 255;
 | 
				
			||||||
 | 
									opac /= count;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			#endif
 | 
								#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			#ifdef _VoxelGI
 | 
								#ifdef _VoxelGI
 | 
				
			||||||
@ -194,7 +213,7 @@ void main() {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		else {
 | 
							else {
 | 
				
			||||||
			// precompute cone sampling:
 | 
								// precompute cone sampling:
 | 
				
			||||||
			vec3 coneDirection = DIFFUSE_CONE_DIRECTIONS[i - 6];
 | 
								vec3 coneDirection = TBN * DIFFUSE_CONE_DIRECTIONS[i - 6];
 | 
				
			||||||
			vec3 aniso_direction = -coneDirection;
 | 
								vec3 aniso_direction = -coneDirection;
 | 
				
			||||||
			uvec3 face_offsets = uvec3(
 | 
								uvec3 face_offsets = uvec3(
 | 
				
			||||||
				aniso_direction.x > 0 ? 0 : 1,
 | 
									aniso_direction.x > 0 ? 0 : 1,
 | 
				
			||||||
 | 
				
			|||||||
@ -12,6 +12,7 @@ class App {
 | 
				
			|||||||
	static var traitInits: Array<Void->Void> = [];
 | 
						static var traitInits: Array<Void->Void> = [];
 | 
				
			||||||
	static var traitUpdates: Array<Void->Void> = [];
 | 
						static var traitUpdates: Array<Void->Void> = [];
 | 
				
			||||||
	static var traitLateUpdates: Array<Void->Void> = [];
 | 
						static var traitLateUpdates: Array<Void->Void> = [];
 | 
				
			||||||
 | 
						static var traitFixedUpdates: Array<Void->Void> = [];
 | 
				
			||||||
	static var traitRenders: Array<kha.graphics4.Graphics->Void> = [];
 | 
						static var traitRenders: Array<kha.graphics4.Graphics->Void> = [];
 | 
				
			||||||
	static var traitRenders2D: Array<kha.graphics2.Graphics->Void> = [];
 | 
						static var traitRenders2D: Array<kha.graphics2.Graphics->Void> = [];
 | 
				
			||||||
	public static var framebuffer: kha.Framebuffer;
 | 
						public static var framebuffer: kha.Framebuffer;
 | 
				
			||||||
@ -23,6 +24,8 @@ class App {
 | 
				
			|||||||
	public static var renderPathTime: Float;
 | 
						public static var renderPathTime: Float;
 | 
				
			||||||
	public static var endFrameCallbacks: Array<Void->Void> = [];
 | 
						public static var endFrameCallbacks: Array<Void->Void> = [];
 | 
				
			||||||
	#end
 | 
						#end
 | 
				
			||||||
 | 
						static var last = 0.0;
 | 
				
			||||||
 | 
						static var time = 0.0;
 | 
				
			||||||
	static var lastw = -1;
 | 
						static var lastw = -1;
 | 
				
			||||||
	static var lasth = -1;
 | 
						static var lasth = -1;
 | 
				
			||||||
	public static var onResize: Void->Void = null;
 | 
						public static var onResize: Void->Void = null;
 | 
				
			||||||
@ -34,13 +37,14 @@ class App {
 | 
				
			|||||||
	function new(done: Void->Void) {
 | 
						function new(done: Void->Void) {
 | 
				
			||||||
		done();
 | 
							done();
 | 
				
			||||||
		kha.System.notifyOnFrames(render);
 | 
							kha.System.notifyOnFrames(render);
 | 
				
			||||||
		kha.Scheduler.addTimeTask(update, 0, iron.system.Time.delta);
 | 
							kha.Scheduler.addTimeTask(update, 0, iron.system.Time.step);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public static function reset() {
 | 
						public static function reset() {
 | 
				
			||||||
		traitInits = [];
 | 
							traitInits = [];
 | 
				
			||||||
		traitUpdates = [];
 | 
							traitUpdates = [];
 | 
				
			||||||
		traitLateUpdates = [];
 | 
							traitLateUpdates = [];
 | 
				
			||||||
 | 
							traitFixedUpdates = [];
 | 
				
			||||||
		traitRenders = [];
 | 
							traitRenders = [];
 | 
				
			||||||
		traitRenders2D = [];
 | 
							traitRenders2D = [];
 | 
				
			||||||
		if (onResets != null) for (f in onResets) f();
 | 
							if (onResets != null) for (f in onResets) f();
 | 
				
			||||||
@ -48,6 +52,24 @@ class App {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	static function update() {
 | 
						static function update() {
 | 
				
			||||||
		if (Scene.active == null || !Scene.active.ready) return;
 | 
							if (Scene.active == null || !Scene.active.ready) return;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							iron.system.Time.update();
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							if (lastw == -1) {
 | 
				
			||||||
 | 
								lastw = App.w();
 | 
				
			||||||
 | 
								lasth = App.h();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (lastw != App.w() || lasth != App.h()) {
 | 
				
			||||||
 | 
								if (onResize != null) onResize();
 | 
				
			||||||
 | 
								else {
 | 
				
			||||||
 | 
									if (Scene.active != null && Scene.active.camera != null) {
 | 
				
			||||||
 | 
										Scene.active.camera.buildProjection();
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							lastw = App.w();
 | 
				
			||||||
 | 
							lasth = App.h();
 | 
				
			||||||
 | 
							
 | 
				
			||||||
		if (pauseUpdates) return;
 | 
							if (pauseUpdates) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		#if lnx_debug
 | 
							#if lnx_debug
 | 
				
			||||||
@ -56,6 +78,14 @@ class App {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		Scene.active.updateFrame();
 | 
							Scene.active.updateFrame();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							time += iron.system.Time.delta;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							while (time >= iron.system.Time.fixedStep) {
 | 
				
			||||||
 | 
								for (f in traitFixedUpdates) f();
 | 
				
			||||||
 | 
								time -= iron.system.Time.fixedStep;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		var i = 0;
 | 
							var i = 0;
 | 
				
			||||||
		var l = traitUpdates.length;
 | 
							var l = traitUpdates.length;
 | 
				
			||||||
		while (i < l) {
 | 
							while (i < l) {
 | 
				
			||||||
@ -84,29 +114,13 @@ class App {
 | 
				
			|||||||
		for (cb in endFrameCallbacks) cb();
 | 
							for (cb in endFrameCallbacks) cb();
 | 
				
			||||||
		updateTime = kha.Scheduler.realTime() - startTime;
 | 
							updateTime = kha.Scheduler.realTime() - startTime;
 | 
				
			||||||
		#end
 | 
							#end
 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Rebuild projection on window resize
 | 
					 | 
				
			||||||
		if (lastw == -1) {
 | 
					 | 
				
			||||||
			lastw = App.w();
 | 
					 | 
				
			||||||
			lasth = App.h();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if (lastw != App.w() || lasth != App.h()) {
 | 
					 | 
				
			||||||
			if (onResize != null) onResize();
 | 
					 | 
				
			||||||
			else {
 | 
					 | 
				
			||||||
				if (Scene.active != null && Scene.active.camera != null) {
 | 
					 | 
				
			||||||
					Scene.active.camera.buildProjection();
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		lastw = App.w();
 | 
					 | 
				
			||||||
		lasth = App.h();
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static function render(frames: Array<kha.Framebuffer>) {
 | 
						static function render(frames: Array<kha.Framebuffer>) {
 | 
				
			||||||
		var frame = frames[0];
 | 
							var frame = frames[0];
 | 
				
			||||||
		framebuffer = frame;
 | 
							framebuffer = frame;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		iron.system.Time.update();
 | 
							iron.system.Time.render();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (Scene.active == null || !Scene.active.ready) {
 | 
							if (Scene.active == null || !Scene.active.ready) {
 | 
				
			||||||
			render2D(frame);
 | 
								render2D(frame);
 | 
				
			||||||
@ -172,6 +186,14 @@ class App {
 | 
				
			|||||||
		traitLateUpdates.remove(f);
 | 
							traitLateUpdates.remove(f);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static function notifyOnFixedUpdate(f: Void->Void) {
 | 
				
			||||||
 | 
							traitFixedUpdates.push(f);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static function removeFixedUpdate(f: Void->Void) {
 | 
				
			||||||
 | 
							traitFixedUpdates.remove(f);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public static function notifyOnRender(f: kha.graphics4.Graphics->Void) {
 | 
						public static function notifyOnRender(f: kha.graphics4.Graphics->Void) {
 | 
				
			||||||
		traitRenders.push(f);
 | 
							traitRenders.push(f);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
				
			|||||||
@ -331,15 +331,18 @@ class RenderPath {
 | 
				
			|||||||
		});
 | 
							});
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public static function sortMeshesShader(meshes: Array<MeshObject>) {
 | 
						public static function sortMeshesIndex(meshes: Array<MeshObject>) {
 | 
				
			||||||
		meshes.sort(function(a, b): Int {
 | 
							meshes.sort(function(a, b): Int {
 | 
				
			||||||
			#if rp_depth_texture
 | 
								#if rp_depth_texture
 | 
				
			||||||
			var depthDiff = boolToInt(a.depthRead) - boolToInt(b.depthRead);
 | 
								var depthDiff = boolToInt(a.depthRead) - boolToInt(b.depthRead);
 | 
				
			||||||
			if (depthDiff != 0) return depthDiff;
 | 
								if (depthDiff != 0) return depthDiff;
 | 
				
			||||||
			#end
 | 
								#end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			return a.materials[0].name >= b.materials[0].name ? 1 : -1;
 | 
								if (a.data.sortingIndex != b.data.sortingIndex) {
 | 
				
			||||||
		});
 | 
									return a.data.sortingIndex > b.data.sortingIndex ? 1 : -1;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return a.data.name >= b.data.name ? 1 : -1;		});
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public function drawMeshes(context: String) {
 | 
						public function drawMeshes(context: String) {
 | 
				
			||||||
@ -399,7 +402,7 @@ class RenderPath {
 | 
				
			|||||||
			#if lnx_batch
 | 
								#if lnx_batch
 | 
				
			||||||
			sortMeshesDistance(Scene.active.meshBatch.nonBatched);
 | 
								sortMeshesDistance(Scene.active.meshBatch.nonBatched);
 | 
				
			||||||
			#else
 | 
								#else
 | 
				
			||||||
			drawOrder == DrawOrder.Shader ? sortMeshesShader(meshes) : sortMeshesDistance(meshes);
 | 
								drawOrder == DrawOrder.Index ? sortMeshesIndex(meshes) : sortMeshesDistance(meshes);
 | 
				
			||||||
			#end
 | 
								#end
 | 
				
			||||||
			meshesSorted = true;
 | 
								meshesSorted = true;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@ -518,12 +521,44 @@ class RenderPath {
 | 
				
			|||||||
		return Reflect.field(kha.Shaders, handle + "_comp");
 | 
							return Reflect.field(kha.Shaders, handle + "_comp");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	#if (kha_krom && lnx_vr)
 | 
						#if lnx_vr
 | 
				
			||||||
	public function drawStereo(drawMeshes: Int->Void) {
 | 
						public function drawStereo(drawMeshes: Void->Void) {
 | 
				
			||||||
		for (eye in 0...2) {
 | 
							var vr = kha.vr.VrInterface.instance;
 | 
				
			||||||
			Krom.vrBeginRender(eye);
 | 
							var appw = iron.App.w();
 | 
				
			||||||
			drawMeshes(eye);
 | 
							var apph = iron.App.h();
 | 
				
			||||||
			Krom.vrEndRender(eye);
 | 
							var halfw = Std.int(appw / 2);
 | 
				
			||||||
 | 
							var g = currentG;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (vr != null && vr.IsPresenting()) {
 | 
				
			||||||
 | 
								// Left eye
 | 
				
			||||||
 | 
								Scene.active.camera.V.setFrom(Scene.active.camera.leftV);
 | 
				
			||||||
 | 
								Scene.active.camera.P.self = vr.GetProjectionMatrix(0);
 | 
				
			||||||
 | 
								g.viewport(0, 0, halfw, apph);
 | 
				
			||||||
 | 
								drawMeshes();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Right eye
 | 
				
			||||||
 | 
								begin(g, additionalTargets);
 | 
				
			||||||
 | 
								Scene.active.camera.V.setFrom(Scene.active.camera.rightV);
 | 
				
			||||||
 | 
								Scene.active.camera.P.self = vr.GetProjectionMatrix(1);
 | 
				
			||||||
 | 
								g.viewport(halfw, 0, halfw, apph);
 | 
				
			||||||
 | 
								drawMeshes();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else { // Simulate
 | 
				
			||||||
 | 
								Scene.active.camera.buildProjection(halfw / apph);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Left eye
 | 
				
			||||||
 | 
								g.viewport(0, 0, halfw, apph);
 | 
				
			||||||
 | 
								drawMeshes();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Right eye
 | 
				
			||||||
 | 
								begin(g, additionalTargets);
 | 
				
			||||||
 | 
								Scene.active.camera.transform.move(Scene.active.camera.right(), 0.032);
 | 
				
			||||||
 | 
								Scene.active.camera.buildMatrix();
 | 
				
			||||||
 | 
								g.viewport(halfw, 0, halfw, apph);
 | 
				
			||||||
 | 
								drawMeshes();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								Scene.active.camera.transform.move(Scene.active.camera.right(), -0.032);
 | 
				
			||||||
 | 
								Scene.active.camera.buildMatrix();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	#end
 | 
						#end
 | 
				
			||||||
@ -882,6 +917,6 @@ class CachedShaderContext {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@:enum abstract DrawOrder(Int) from Int {
 | 
					@:enum abstract DrawOrder(Int) from Int {
 | 
				
			||||||
	var Distance = 0; // Early-z
 | 
						var Distance = 0; // Early-z
 | 
				
			||||||
	var Shader = 1; // Less state changes
 | 
						var Index = 1; // Less state changes
 | 
				
			||||||
	// var Mix = 2; // Distance buckets sorted by shader
 | 
						// var Mix = 2; // Distance buckets sorted by shader
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -775,6 +775,7 @@ class Scene {
 | 
				
			|||||||
			// Attach particle systems
 | 
								// Attach particle systems
 | 
				
			||||||
			#if lnx_particles
 | 
								#if lnx_particles
 | 
				
			||||||
			if (o.particle_refs != null) {
 | 
								if (o.particle_refs != null) {
 | 
				
			||||||
 | 
									cast(object, MeshObject).render_emitter = o.render_emitter;
 | 
				
			||||||
				for (ref in o.particle_refs) cast(object, MeshObject).setupParticleSystem(sceneName, ref);
 | 
									for (ref in o.particle_refs) cast(object, MeshObject).setupParticleSystem(sceneName, ref);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			#end
 | 
								#end
 | 
				
			||||||
@ -782,6 +783,11 @@ class Scene {
 | 
				
			|||||||
			if (o.tilesheet_ref != null) {
 | 
								if (o.tilesheet_ref != null) {
 | 
				
			||||||
				cast(object, MeshObject).setupTilesheet(sceneName, o.tilesheet_ref, o.tilesheet_action_ref);
 | 
									cast(object, MeshObject).setupTilesheet(sceneName, o.tilesheet_ref, o.tilesheet_action_ref);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								if (o.camera_list != null){
 | 
				
			||||||
 | 
									cast(object, MeshObject).cameraList = o.camera_list;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			returnObject(object, o, done);
 | 
								returnObject(object, o, done);
 | 
				
			||||||
		});
 | 
							});
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -881,8 +887,12 @@ class Scene {
 | 
				
			|||||||
						var ptype: String = t.props[i * 3 + 1];
 | 
											var ptype: String = t.props[i * 3 + 1];
 | 
				
			||||||
						var pval: Dynamic = t.props[i * 3 + 2];
 | 
											var pval: Dynamic = t.props[i * 3 + 2];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
						if (StringTools.endsWith(ptype, "Object") && pval != "") {
 | 
											if (StringTools.endsWith(ptype, "Object") && pval != "" && pval != null) {
 | 
				
			||||||
							Reflect.setProperty(traitInst, pname, Scene.active.getChild(pval));
 | 
												Reflect.setProperty(traitInst, pname, Scene.active.getChild(pval));
 | 
				
			||||||
 | 
											} else if (ptype == "TSceneFormat" && pval != "") {
 | 
				
			||||||
 | 
												Data.getSceneRaw(pval, function (r: TSceneFormat) {
 | 
				
			||||||
 | 
													Reflect.setProperty(traitInst, pname, r);
 | 
				
			||||||
 | 
												});
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
						else {
 | 
											else {
 | 
				
			||||||
							switch (ptype) {
 | 
												switch (ptype) {
 | 
				
			||||||
 | 
				
			|||||||
@ -16,6 +16,7 @@ class Trait {
 | 
				
			|||||||
	var _remove: Array<Void->Void> = null;
 | 
						var _remove: Array<Void->Void> = null;
 | 
				
			||||||
	var _update: Array<Void->Void> = null;
 | 
						var _update: Array<Void->Void> = null;
 | 
				
			||||||
	var _lateUpdate: Array<Void->Void> = null;
 | 
						var _lateUpdate: Array<Void->Void> = null;
 | 
				
			||||||
 | 
						var _fixedUpdate: Array<Void->Void> = null;
 | 
				
			||||||
	var _render: Array<kha.graphics4.Graphics->Void> = null;
 | 
						var _render: Array<kha.graphics4.Graphics->Void> = null;
 | 
				
			||||||
	var _render2D: Array<kha.graphics2.Graphics->Void> = null;
 | 
						var _render2D: Array<kha.graphics2.Graphics->Void> = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -87,6 +88,23 @@ class Trait {
 | 
				
			|||||||
		App.removeLateUpdate(f);
 | 
							App.removeLateUpdate(f);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					      Add fixed game logic handler.
 | 
				
			||||||
 | 
					    **/
 | 
				
			||||||
 | 
						public function notifyOnFixedUpdate(f: Void->Void) {
 | 
				
			||||||
 | 
							if (_fixedUpdate == null) _fixedUpdate = [];
 | 
				
			||||||
 | 
							_fixedUpdate.push(f);
 | 
				
			||||||
 | 
							App.notifyOnFixedUpdate(f);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					      Remove fixed game logic handler.
 | 
				
			||||||
 | 
					    **/
 | 
				
			||||||
 | 
						public function removeFixedUpdate(f: Void->Void) {
 | 
				
			||||||
 | 
							_fixedUpdate.remove(f);
 | 
				
			||||||
 | 
							App.removeFixedUpdate(f);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
      Add render handler.
 | 
					      Add render handler.
 | 
				
			||||||
    **/
 | 
					    **/
 | 
				
			||||||
 | 
				
			|||||||
@ -9,6 +9,7 @@ import iron.data.SceneFormat;
 | 
				
			|||||||
class MeshData {
 | 
					class MeshData {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public var name: String;
 | 
						public var name: String;
 | 
				
			||||||
 | 
						public var sortingIndex: Int;
 | 
				
			||||||
	public var raw: TMeshData;
 | 
						public var raw: TMeshData;
 | 
				
			||||||
	public var format: TSceneFormat;
 | 
						public var format: TSceneFormat;
 | 
				
			||||||
	public var geom: Geometry;
 | 
						public var geom: Geometry;
 | 
				
			||||||
@ -23,6 +24,7 @@ class MeshData {
 | 
				
			|||||||
	public function new(raw: TMeshData, done: MeshData->Void) {
 | 
						public function new(raw: TMeshData, done: MeshData->Void) {
 | 
				
			||||||
		this.raw = raw;
 | 
							this.raw = raw;
 | 
				
			||||||
		this.name = raw.name;
 | 
							this.name = raw.name;
 | 
				
			||||||
 | 
							this.sortingIndex = raw.sorting_index;
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		if (raw.scale_pos != null) scalePos = raw.scale_pos;
 | 
							if (raw.scale_pos != null) scalePos = raw.scale_pos;
 | 
				
			||||||
		if (raw.scale_tex != null) scaleTex = raw.scale_tex;
 | 
							if (raw.scale_tex != null) scaleTex = raw.scale_tex;
 | 
				
			||||||
 | 
				
			|||||||
@ -49,6 +49,7 @@ typedef TMeshData = {
 | 
				
			|||||||
@:structInit class TMeshData {
 | 
					@:structInit class TMeshData {
 | 
				
			||||||
#end
 | 
					#end
 | 
				
			||||||
	public var name: String;
 | 
						public var name: String;
 | 
				
			||||||
 | 
						public var sorting_index: Int;
 | 
				
			||||||
	public var vertex_arrays: Array<TVertexArray>;
 | 
						public var vertex_arrays: Array<TVertexArray>;
 | 
				
			||||||
	public var index_arrays: Array<TIndexArray>;
 | 
						public var index_arrays: Array<TIndexArray>;
 | 
				
			||||||
	@:optional public var dynamic_usage: Null<Bool>;
 | 
						@:optional public var dynamic_usage: Null<Bool>;
 | 
				
			||||||
@ -222,6 +223,7 @@ typedef TShaderData = {
 | 
				
			|||||||
@:structInit class TShaderData {
 | 
					@:structInit class TShaderData {
 | 
				
			||||||
#end
 | 
					#end
 | 
				
			||||||
	public var name: String;
 | 
						public var name: String;
 | 
				
			||||||
 | 
						public var next_pass: String;
 | 
				
			||||||
	public var contexts: Array<TShaderContext>;
 | 
						public var contexts: Array<TShaderContext>;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -392,6 +394,9 @@ typedef TParticleData = {
 | 
				
			|||||||
#end
 | 
					#end
 | 
				
			||||||
	public var name: String;
 | 
						public var name: String;
 | 
				
			||||||
	public var type: Int; // 0 - Emitter, Hair
 | 
						public var type: Int; // 0 - Emitter, Hair
 | 
				
			||||||
 | 
						public var auto_start: Bool;
 | 
				
			||||||
 | 
						public var dynamic_emitter: Bool;
 | 
				
			||||||
 | 
						public var is_unique: Bool;
 | 
				
			||||||
	public var loop: Bool;
 | 
						public var loop: Bool;
 | 
				
			||||||
	public var count: Int;
 | 
						public var count: Int;
 | 
				
			||||||
	public var frame_start: FastFloat;
 | 
						public var frame_start: FastFloat;
 | 
				
			||||||
@ -439,6 +444,7 @@ typedef TObj = {
 | 
				
			|||||||
	@:optional public var traits: Array<TTrait>;
 | 
						@:optional public var traits: Array<TTrait>;
 | 
				
			||||||
	@:optional public var properties: Array<TProperty>;
 | 
						@:optional public var properties: Array<TProperty>;
 | 
				
			||||||
	@:optional public var vertex_groups: Array<TVertex_groups>;
 | 
						@:optional public var vertex_groups: Array<TVertex_groups>;
 | 
				
			||||||
 | 
						@:optional public var camera_list: Array<String>;
 | 
				
			||||||
	@:optional public var constraints: Array<TConstraint>;
 | 
						@:optional public var constraints: Array<TConstraint>;
 | 
				
			||||||
	@:optional public var dimensions: Float32Array; // Geometry objects
 | 
						@:optional public var dimensions: Float32Array; // Geometry objects
 | 
				
			||||||
	@:optional public var object_actions: Array<String>;
 | 
						@:optional public var object_actions: Array<String>;
 | 
				
			||||||
 | 
				
			|||||||
@ -22,6 +22,7 @@ using StringTools;
 | 
				
			|||||||
class ShaderData {
 | 
					class ShaderData {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public var name: String;
 | 
						public var name: String;
 | 
				
			||||||
 | 
						public var nextPass: String;
 | 
				
			||||||
	public var raw: TShaderData;
 | 
						public var raw: TShaderData;
 | 
				
			||||||
	public var contexts: Array<ShaderContext> = [];
 | 
						public var contexts: Array<ShaderContext> = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -33,6 +34,7 @@ class ShaderData {
 | 
				
			|||||||
	public function new(raw: TShaderData, done: ShaderData->Void, overrideContext: TShaderOverride = null) {
 | 
						public function new(raw: TShaderData, done: ShaderData->Void, overrideContext: TShaderOverride = null) {
 | 
				
			||||||
		this.raw = raw;
 | 
							this.raw = raw;
 | 
				
			||||||
		this.name = raw.name;
 | 
							this.name = raw.name;
 | 
				
			||||||
 | 
							this.nextPass = raw.next_pass;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (c in raw.contexts) contexts.push(null);
 | 
							for (c in raw.contexts) contexts.push(null);
 | 
				
			||||||
		var contextsLoaded = 0;
 | 
							var contextsLoaded = 0;
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										50
									
								
								leenkx/Sources/iron/format/bmp/Data.hx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								leenkx/Sources/iron/format/bmp/Data.hx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,50 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * format - Haxe File Formats
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  BMP File Format
 | 
				
			||||||
 | 
					 *  Copyright (C) 2007-2009 Trevor McCauley, Baluta Cristian (hx port) & Robert Sköld (format conversion)
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (c) 2009, The Haxe Project Contributors
 | 
				
			||||||
 | 
					 * All rights reserved.
 | 
				
			||||||
 | 
					 * Redistribution and use in source and binary forms, with or without
 | 
				
			||||||
 | 
					 * modification, are permitted provided that the following conditions are met:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *   - Redistributions of source code must retain the above copyright
 | 
				
			||||||
 | 
					 *     notice, this list of conditions and the following disclaimer.
 | 
				
			||||||
 | 
					 *   - Redistributions in binary form must reproduce the above copyright
 | 
				
			||||||
 | 
					 *     notice, this list of conditions and the following disclaimer in the
 | 
				
			||||||
 | 
					 *     documentation and/or other materials provided with the distribution.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
 | 
				
			||||||
 | 
					 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 | 
				
			||||||
 | 
					 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 | 
				
			||||||
 | 
					 * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
 | 
				
			||||||
 | 
					 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
				
			||||||
 | 
					 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
				
			||||||
 | 
					 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 | 
				
			||||||
 | 
					 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | 
				
			||||||
 | 
					 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 | 
				
			||||||
 | 
					 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 | 
				
			||||||
 | 
					 * DAMAGE.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					package iron.format.bmp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef Data = {
 | 
				
			||||||
 | 
					    var header : iron.format.bmp.Header;
 | 
				
			||||||
 | 
					    var pixels : haxe.io.Bytes;
 | 
				
			||||||
 | 
					#if (haxe_ver < 4)
 | 
				
			||||||
 | 
					    var colorTable : Null<haxe.io.Bytes>;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					    var ?colorTable : haxe.io.Bytes;
 | 
				
			||||||
 | 
					#end
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef Header = {
 | 
				
			||||||
 | 
					    var width : Int;          // real width (in pixels)
 | 
				
			||||||
 | 
					    var height : Int;         // real height (in pixels)
 | 
				
			||||||
 | 
					    var paddedStride : Int;   // number of bytes in a stride (including padding)
 | 
				
			||||||
 | 
					    var topToBottom : Bool;   // whether the bitmap is stored top to bottom
 | 
				
			||||||
 | 
					    var bpp : Int;            // bits per pixel
 | 
				
			||||||
 | 
					    var dataLength : Int;     // equal to `paddedStride` * `height`
 | 
				
			||||||
 | 
					    var compression : Int;    // which compression is being used, 0 for no compression
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										122
									
								
								leenkx/Sources/iron/format/bmp/Reader.hx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								leenkx/Sources/iron/format/bmp/Reader.hx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,122 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * format - Haxe File Formats
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  BMP File Format
 | 
				
			||||||
 | 
					 *  Copyright (C) 2007-2009 Robert Sköld
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (c) 2009, The Haxe Project Contributors
 | 
				
			||||||
 | 
					 * All rights reserved.
 | 
				
			||||||
 | 
					 * Redistribution and use in source and binary forms, with or without
 | 
				
			||||||
 | 
					 * modification, are permitted provided that the following conditions are met:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *   - Redistributions of source code must retain the above copyright
 | 
				
			||||||
 | 
					 *     notice, this list of conditions and the following disclaimer.
 | 
				
			||||||
 | 
					 *   - Redistributions in binary form must reproduce the above copyright
 | 
				
			||||||
 | 
					 *     notice, this list of conditions and the following disclaimer in the
 | 
				
			||||||
 | 
					 *     documentation and/or other materials provided with the distribution.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
 | 
				
			||||||
 | 
					 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 | 
				
			||||||
 | 
					 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 | 
				
			||||||
 | 
					 * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
 | 
				
			||||||
 | 
					 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
				
			||||||
 | 
					 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
				
			||||||
 | 
					 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 | 
				
			||||||
 | 
					 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | 
				
			||||||
 | 
					 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 | 
				
			||||||
 | 
					 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 | 
				
			||||||
 | 
					 * DAMAGE.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package iron.format.bmp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import iron.format.bmp.Data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Reader {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var input : haxe.io.Input;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public function new( i ) {
 | 
				
			||||||
 | 
							input = i;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** 
 | 
				
			||||||
 | 
						 * Only supports uncompressed 24bpp bitmaps (the most common format).
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * The returned bytes in `Data.pixels` will be in BGR order, and with padding (if present).
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @see https://msdn.microsoft.com/en-us/library/windows/desktop/dd318229(v=vs.85).aspx
 | 
				
			||||||
 | 
						 * @see https://en.wikipedia.org/wiki/BMP_file_format#Bitmap_file_header
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public function read() : format.bmp.Data {
 | 
				
			||||||
 | 
							// Read Header
 | 
				
			||||||
 | 
							for (b in ["B".code, "M".code]) {
 | 
				
			||||||
 | 
								if (input.readByte() != b) throw "Invalid header";
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
							var fileSize = input.readInt32();
 | 
				
			||||||
 | 
							input.readInt32();							// Reserved
 | 
				
			||||||
 | 
							var offset = input.readInt32();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Read InfoHeader
 | 
				
			||||||
 | 
							var infoHeaderSize = input.readInt32();		// InfoHeader size
 | 
				
			||||||
 | 
							if (infoHeaderSize != 40) {
 | 
				
			||||||
 | 
								throw 'Info headers with size $infoHeaderSize not supported.';
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							var width = input.readInt32();				// Image width (actual, not padded)
 | 
				
			||||||
 | 
							var height = input.readInt32();				// Image height
 | 
				
			||||||
 | 
							var numPlanes = input.readInt16();			// Number of planes
 | 
				
			||||||
 | 
							var bits = input.readInt16();				// Bits per pixel
 | 
				
			||||||
 | 
							var compression = input.readInt32();		// Compression type
 | 
				
			||||||
 | 
							var dataLength = input.readInt32();			// Image data size (includes padding!)
 | 
				
			||||||
 | 
							input.readInt32();							// Horizontal resolution
 | 
				
			||||||
 | 
							input.readInt32();							// Vertical resolution
 | 
				
			||||||
 | 
							var colorsUsed = input.readInt32();			// Colors used (0 when uncompressed)
 | 
				
			||||||
 | 
							input.readInt32();							// Important colors (0 when uncompressed)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// If there's no compression, the dataLength may be 0
 | 
				
			||||||
 | 
							if ( compression == 0 && dataLength == 0 ) dataLength = fileSize - offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var bytesRead = 54; // total read above
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							var colorTable : haxe.io.Bytes = null;
 | 
				
			||||||
 | 
							if ( bits <= 8 ) {
 | 
				
			||||||
 | 
								if ( colorsUsed == 0 ) {
 | 
				
			||||||
 | 
									colorsUsed = Tools.getNumColorsForBitDepth(bits);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								var colorTableLength = 4 * colorsUsed;
 | 
				
			||||||
 | 
								colorTable = haxe.io.Bytes.alloc( colorTableLength );
 | 
				
			||||||
 | 
								input.readFullBytes( colorTable, 0, colorTableLength );
 | 
				
			||||||
 | 
								bytesRead += colorTableLength;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							input.read( offset - bytesRead );
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							var p = haxe.io.Bytes.alloc( dataLength );	
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							// Read Raster Data
 | 
				
			||||||
 | 
							var paddedStride = Tools.computePaddedStride(width, bits);
 | 
				
			||||||
 | 
							var topToBottom = false;
 | 
				
			||||||
 | 
							if ( height < 0 ) { // if bitmap is stored top to bottom
 | 
				
			||||||
 | 
								topToBottom = true;
 | 
				
			||||||
 | 
								height = -height;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
							input.readFullBytes(p, 0, dataLength);
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
							return {
 | 
				
			||||||
 | 
								header: {
 | 
				
			||||||
 | 
									width: width,
 | 
				
			||||||
 | 
									height: height,
 | 
				
			||||||
 | 
									paddedStride: paddedStride,
 | 
				
			||||||
 | 
									topToBottom: topToBottom,
 | 
				
			||||||
 | 
									bpp: bits,
 | 
				
			||||||
 | 
									dataLength: dataLength,
 | 
				
			||||||
 | 
									compression: compression
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								pixels: p,
 | 
				
			||||||
 | 
								colorTable: colorTable
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										256
									
								
								leenkx/Sources/iron/format/bmp/Tools.hx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										256
									
								
								leenkx/Sources/iron/format/bmp/Tools.hx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,256 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * format - Haxe File Formats
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  BMP File Format
 | 
				
			||||||
 | 
					 *  Copyright (C) 2007-2009 Trevor McCauley, Baluta Cristian (hx port) & Robert Sköld (format conversion)
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (c) 2009, The Haxe Project Contributors
 | 
				
			||||||
 | 
					 * All rights reserved.
 | 
				
			||||||
 | 
					 * Redistribution and use in source and binary forms, with or without
 | 
				
			||||||
 | 
					 * modification, are permitted provided that the following conditions are met:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *   - Redistributions of source code must retain the above copyright
 | 
				
			||||||
 | 
					 *     notice, this list of conditions and the following disclaimer.
 | 
				
			||||||
 | 
					 *   - Redistributions in binary form must reproduce the above copyright
 | 
				
			||||||
 | 
					 *     notice, this list of conditions and the following disclaimer in the
 | 
				
			||||||
 | 
					 *     documentation and/or other materials provided with the distribution.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
 | 
				
			||||||
 | 
					 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 | 
				
			||||||
 | 
					 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 | 
				
			||||||
 | 
					 * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
 | 
				
			||||||
 | 
					 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
				
			||||||
 | 
					 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
				
			||||||
 | 
					 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 | 
				
			||||||
 | 
					 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | 
				
			||||||
 | 
					 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 | 
				
			||||||
 | 
					 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 | 
				
			||||||
 | 
					 * DAMAGE.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					package iron.format.bmp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Tools {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//												  a  r  g  b
 | 
				
			||||||
 | 
						static var ARGB_MAP(default, never):Array<Int> = [0, 1, 2, 3];
 | 
				
			||||||
 | 
						static var BGRA_MAP(default, never):Array<Int> = [3, 2, 1, 0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static var COLOR_SIZE(default, never):Int = 4;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
							Extract BMP pixel data (24bpp in BGR format) and expands it to BGRA, removing any padding in the process.
 | 
				
			||||||
 | 
						**/
 | 
				
			||||||
 | 
						inline static public function extractBGRA( bmp : iron.format.bmp.Data ) : haxe.io.Bytes {
 | 
				
			||||||
 | 
							return _extract32(bmp, BGRA_MAP, 0xFF);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
							Extract BMP pixel data (24bpp in BGR format) and converts it to ARGB.
 | 
				
			||||||
 | 
						**/
 | 
				
			||||||
 | 
						inline static public function extractARGB( bmp : iron.format.bmp.Data ) : haxe.io.Bytes {
 | 
				
			||||||
 | 
							return _extract32(bmp, ARGB_MAP, 0xFF);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
							Creates BMP data from bytes in BGRA format for each pixel.
 | 
				
			||||||
 | 
						**/
 | 
				
			||||||
 | 
						inline static public function buildFromBGRA( width : Int, height : Int, srcBytes : haxe.io.Bytes, topToBottom : Bool = false ) : Data {
 | 
				
			||||||
 | 
							return _buildFrom32(width, height, srcBytes, BGRA_MAP, topToBottom);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
							Creates BMP data from bytes in ARGB format for each pixel.
 | 
				
			||||||
 | 
						**/
 | 
				
			||||||
 | 
						inline static public function buildFromARGB( width : Int, height : Int, srcBytes : haxe.io.Bytes, topToBottom : Bool = false ) : Data {
 | 
				
			||||||
 | 
							return _buildFrom32(width, height, srcBytes, ARGB_MAP, topToBottom);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inline static public function computePaddedStride(width:Int, bpp:Int):Int {
 | 
				
			||||||
 | 
							return ((((width * bpp) + 31) & ~31) >> 3);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Gets number of colors for indexed palettes
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						inline static public function getNumColorsForBitDepth(bpp:Int):Int {
 | 
				
			||||||
 | 
							return switch (bpp) {
 | 
				
			||||||
 | 
								case 1: 2;
 | 
				
			||||||
 | 
								case 4: 16;
 | 
				
			||||||
 | 
								case 8: 256;
 | 
				
			||||||
 | 
								case 16: 65536;
 | 
				
			||||||
 | 
								default: throw 'Unsupported bpp $bpp';
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						// `channelMap` contains indices to map into ARGB (f.e. the mapping for ARGB is [0,1,2,3], while for BGRA is [3,2,1,0])
 | 
				
			||||||
 | 
						static function _extract32( bmp : iron.format.bmp.Data, channelMap : Array<Int>, alpha : Int = 0xFF) : haxe.io.Bytes {
 | 
				
			||||||
 | 
							var srcBytes = bmp.pixels;
 | 
				
			||||||
 | 
							var dstLen = bmp.header.width * bmp.header.height * 4;
 | 
				
			||||||
 | 
							var dstBytes = haxe.io.Bytes.alloc( dstLen );
 | 
				
			||||||
 | 
							var srcPaddedStride = bmp.header.paddedStride;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							var yDir = -1;
 | 
				
			||||||
 | 
							var dstPos = 0;
 | 
				
			||||||
 | 
							var srcPos = srcPaddedStride * (bmp.header.height - 1);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
							if ( bmp.header.topToBottom ) {
 | 
				
			||||||
 | 
								yDir = 1;
 | 
				
			||||||
 | 
								srcPos = 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if ( bmp.header.bpp < 8 || bmp.header.bpp == 16 ) {
 | 
				
			||||||
 | 
								throw 'bpp ${bmp.header.bpp} not supported';
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var colorTable:haxe.io.Bytes = null;
 | 
				
			||||||
 | 
							if ( bmp.header.bpp <= 8 ) {
 | 
				
			||||||
 | 
								var colorTableLength = getNumColorsForBitDepth(bmp.header.bpp);
 | 
				
			||||||
 | 
								colorTable = haxe.io.Bytes.alloc(colorTableLength * COLOR_SIZE);
 | 
				
			||||||
 | 
								var definedColorTableLength = Std.int( bmp.colorTable.length / COLOR_SIZE );
 | 
				
			||||||
 | 
								for( i in 0...definedColorTableLength ) {
 | 
				
			||||||
 | 
									var b = bmp.colorTable.get( i * COLOR_SIZE);
 | 
				
			||||||
 | 
									var g = bmp.colorTable.get( i * COLOR_SIZE + 1);
 | 
				
			||||||
 | 
									var r = bmp.colorTable.get( i * COLOR_SIZE + 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									colorTable.set(i * COLOR_SIZE + channelMap[0], alpha);
 | 
				
			||||||
 | 
									colorTable.set(i * COLOR_SIZE + channelMap[1], r);
 | 
				
			||||||
 | 
									colorTable.set(i * COLOR_SIZE + channelMap[2], g);
 | 
				
			||||||
 | 
									colorTable.set(i * COLOR_SIZE + channelMap[3], b);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								// We want to have the table the full length in case indices outside the range are present
 | 
				
			||||||
 | 
								colorTable.fill(definedColorTableLength, colorTableLength - definedColorTableLength, 0);
 | 
				
			||||||
 | 
								for( i in definedColorTableLength...colorTableLength ) {
 | 
				
			||||||
 | 
									colorTable.set(i * COLOR_SIZE + channelMap[0], alpha);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							switch bmp.header.compression {
 | 
				
			||||||
 | 
								case 0:
 | 
				
			||||||
 | 
									while( dstPos < dstLen ) {
 | 
				
			||||||
 | 
										for( i in 0...bmp.header.width ) {
 | 
				
			||||||
 | 
											if (bmp.header.bpp == 8) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
												var currentSrcPos = srcPos + i;
 | 
				
			||||||
 | 
												var index = srcBytes.get(currentSrcPos);
 | 
				
			||||||
 | 
												dstBytes.blit( dstPos, colorTable, index * COLOR_SIZE, COLOR_SIZE );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											} else if (bmp.header.bpp == 24) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
												var currentSrcPos = srcPos + i * 3;
 | 
				
			||||||
 | 
												var b = srcBytes.get(currentSrcPos);
 | 
				
			||||||
 | 
												var g = srcBytes.get(currentSrcPos + 1);
 | 
				
			||||||
 | 
												var r = srcBytes.get(currentSrcPos + 2);
 | 
				
			||||||
 | 
												
 | 
				
			||||||
 | 
												dstBytes.set(dstPos + channelMap[0], alpha);
 | 
				
			||||||
 | 
												dstBytes.set(dstPos + channelMap[1], r);
 | 
				
			||||||
 | 
												dstBytes.set(dstPos + channelMap[2], g);
 | 
				
			||||||
 | 
												dstBytes.set(dstPos + channelMap[3], b);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											} else if (bmp.header.bpp == 32) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
												var currentSrcPos = srcPos + i * 4;
 | 
				
			||||||
 | 
												var b = srcBytes.get(currentSrcPos);
 | 
				
			||||||
 | 
												var g = srcBytes.get(currentSrcPos + 1);
 | 
				
			||||||
 | 
												var r = srcBytes.get(currentSrcPos + 2);
 | 
				
			||||||
 | 
												
 | 
				
			||||||
 | 
												dstBytes.set(dstPos + channelMap[0], alpha);
 | 
				
			||||||
 | 
												dstBytes.set(dstPos + channelMap[1], r);
 | 
				
			||||||
 | 
												dstBytes.set(dstPos + channelMap[2], g);
 | 
				
			||||||
 | 
												dstBytes.set(dstPos + channelMap[3], b);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
											dstPos += 4;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										srcPos += yDir * srcPaddedStride;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								case 1:
 | 
				
			||||||
 | 
									srcPos = 0;
 | 
				
			||||||
 | 
									var x = 0;
 | 
				
			||||||
 | 
									var y = bmp.header.topToBottom ? 0 : bmp.header.height - 1;
 | 
				
			||||||
 | 
									while( srcPos < bmp.header.dataLength ) {
 | 
				
			||||||
 | 
										var count = srcBytes.get(srcPos++);
 | 
				
			||||||
 | 
										var index = srcBytes.get(srcPos++);
 | 
				
			||||||
 | 
										if ( count == 0 ) {
 | 
				
			||||||
 | 
											if ( index == 0 ) {
 | 
				
			||||||
 | 
												x = 0;
 | 
				
			||||||
 | 
												y += yDir;
 | 
				
			||||||
 | 
											} else if ( index == 1 ) {
 | 
				
			||||||
 | 
												break;
 | 
				
			||||||
 | 
											} else if ( index == 2 ) {
 | 
				
			||||||
 | 
												x += srcBytes.get(srcPos++);
 | 
				
			||||||
 | 
												y += srcBytes.get(srcPos++);
 | 
				
			||||||
 | 
											} else {
 | 
				
			||||||
 | 
												count = index;
 | 
				
			||||||
 | 
												for( i in 0...count ) {
 | 
				
			||||||
 | 
													index = srcBytes.get(srcPos++);
 | 
				
			||||||
 | 
													dstBytes.blit( COLOR_SIZE * ((x+i) + y * bmp.header.width), colorTable, index * COLOR_SIZE, COLOR_SIZE );
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
												if (srcPos % 2 != 0) srcPos++;
 | 
				
			||||||
 | 
												x += count;
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										} else {
 | 
				
			||||||
 | 
											for( i in 0...count ) {
 | 
				
			||||||
 | 
												dstBytes.blit( COLOR_SIZE * ((x+i) + y * bmp.header.width), colorTable, index * COLOR_SIZE, COLOR_SIZE );
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
											x += count;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									throw 'compression ${bmp.header.compression} not supported';
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return dstBytes;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						// `channelMap` contains indices to map into ARGB (f.e. the mapping for ARGB is [0,1,2,3], while for BGRA is [3,2,1,0])
 | 
				
			||||||
 | 
						static function _buildFrom32( width : Int, height : Int, srcBytes : haxe.io.Bytes, channelMap : Array<Int>, topToBottom : Bool = false ) : Data {
 | 
				
			||||||
 | 
							var bpp = 24;
 | 
				
			||||||
 | 
							var paddedStride = computePaddedStride(width, bpp);
 | 
				
			||||||
 | 
							var bytesBGR = haxe.io.Bytes.alloc(paddedStride * height);
 | 
				
			||||||
 | 
							var topToBottom = topToBottom;
 | 
				
			||||||
 | 
							var dataLength = bytesBGR.length;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							var dstStride = width * 3;
 | 
				
			||||||
 | 
							var srcLen = width * height * 4;
 | 
				
			||||||
 | 
							var yDir = -1;
 | 
				
			||||||
 | 
							var dstPos = dataLength - paddedStride;
 | 
				
			||||||
 | 
							var srcPos = 0;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							if ( topToBottom ) {
 | 
				
			||||||
 | 
								yDir = 1;
 | 
				
			||||||
 | 
								dstPos = 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							while( srcPos < srcLen ) {
 | 
				
			||||||
 | 
								var i = dstPos;
 | 
				
			||||||
 | 
								while( i < dstPos + dstStride ) {
 | 
				
			||||||
 | 
									var r = srcBytes.get(srcPos + channelMap[1]);
 | 
				
			||||||
 | 
									var g = srcBytes.get(srcPos + channelMap[2]);
 | 
				
			||||||
 | 
									var b = srcBytes.get(srcPos + channelMap[3]);
 | 
				
			||||||
 | 
									
 | 
				
			||||||
 | 
									bytesBGR.set(i++, b);
 | 
				
			||||||
 | 
									bytesBGR.set(i++, g);
 | 
				
			||||||
 | 
									bytesBGR.set(i++, r);
 | 
				
			||||||
 | 
									
 | 
				
			||||||
 | 
									srcPos += 4;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								dstPos += yDir * paddedStride;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							return {
 | 
				
			||||||
 | 
								header: {
 | 
				
			||||||
 | 
									width: width,
 | 
				
			||||||
 | 
									height: height,
 | 
				
			||||||
 | 
									paddedStride: paddedStride,
 | 
				
			||||||
 | 
									topToBottom: topToBottom,
 | 
				
			||||||
 | 
									bpp: bpp,
 | 
				
			||||||
 | 
									dataLength: dataLength,
 | 
				
			||||||
 | 
									compression: 0
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								pixels: bytesBGR,
 | 
				
			||||||
 | 
								colorTable: null
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										74
									
								
								leenkx/Sources/iron/format/bmp/Writer.hx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								leenkx/Sources/iron/format/bmp/Writer.hx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,74 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * format - Haxe File Formats
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  BMP File Format
 | 
				
			||||||
 | 
					 *  Copyright (C) 2007-2009 Robert Sköld
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (c) 2009, The Haxe Project Contributors
 | 
				
			||||||
 | 
					 * All rights reserved.
 | 
				
			||||||
 | 
					 * Redistribution and use in source and binary forms, with or without
 | 
				
			||||||
 | 
					 * modification, are permitted provided that the following conditions are met:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *   - Redistributions of source code must retain the above copyright
 | 
				
			||||||
 | 
					 *     notice, this list of conditions and the following disclaimer.
 | 
				
			||||||
 | 
					 *   - Redistributions in binary form must reproduce the above copyright
 | 
				
			||||||
 | 
					 *     notice, this list of conditions and the following disclaimer in the
 | 
				
			||||||
 | 
					 *     documentation and/or other materials provided with the distribution.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
 | 
				
			||||||
 | 
					 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 | 
				
			||||||
 | 
					 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 | 
				
			||||||
 | 
					 * DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
 | 
				
			||||||
 | 
					 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
				
			||||||
 | 
					 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
				
			||||||
 | 
					 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 | 
				
			||||||
 | 
					 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | 
				
			||||||
 | 
					 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 | 
				
			||||||
 | 
					 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 | 
				
			||||||
 | 
					 * DAMAGE.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package iron.format.bmp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import iron.format.bmp.Data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Writer {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static var DATA_OFFSET : Int = 0x36;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var output : haxe.io.Output;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public function new(o) {
 | 
				
			||||||
 | 
							output = o;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Specs: http://s223767089.online.de/en/file-format-bmp
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public function write( bmp : Data ) {
 | 
				
			||||||
 | 
							// Write Header (14 bytes)
 | 
				
			||||||
 | 
							output.writeString( "BM" );								// Signature
 | 
				
			||||||
 | 
							output.writeInt32(bmp.pixels.length + DATA_OFFSET );	// FileSize
 | 
				
			||||||
 | 
							output.writeInt32( 0 );									// Reserved
 | 
				
			||||||
 | 
							output.writeInt32( DATA_OFFSET );						// Offset
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Write InfoHeader (40 bytes)
 | 
				
			||||||
 | 
							output.writeInt32( 40 );								// InfoHeader size
 | 
				
			||||||
 | 
							output.writeInt32( bmp.header.width );					// Image width
 | 
				
			||||||
 | 
							var height = bmp.header.height;
 | 
				
			||||||
 | 
							if (bmp.header.topToBottom) height = -height; 
 | 
				
			||||||
 | 
							output.writeInt32( height );							// Image height
 | 
				
			||||||
 | 
							output.writeInt16( 1 );									// Number of planes
 | 
				
			||||||
 | 
							output.writeInt16( 24 );								// Bits per pixel (24bit RGB)
 | 
				
			||||||
 | 
							output.writeInt32( 0 );									// Compression type (no compression)
 | 
				
			||||||
 | 
							output.writeInt32( bmp.header.dataLength );				// Image data size (0 when uncompressed)
 | 
				
			||||||
 | 
							output.writeInt32( 0x2e30 );							// Horizontal resolution
 | 
				
			||||||
 | 
							output.writeInt32( 0x2e30 );							// Vertical resolution
 | 
				
			||||||
 | 
							output.writeInt32( 0 );									// Colors used (0 when uncompressed)
 | 
				
			||||||
 | 
							output.writeInt32( 0 );									// Important colors (0 when uncompressed)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Write Raster Data
 | 
				
			||||||
 | 
							output.write(bmp.pixels);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -159,9 +159,17 @@ class Animation {
 | 
				
			|||||||
			if(markerEvents.get(sampler) != null){
 | 
								if(markerEvents.get(sampler) != null){
 | 
				
			||||||
				for (i in 0...anim.marker_frames.length) {
 | 
									for (i in 0...anim.marker_frames.length) {
 | 
				
			||||||
					if (frameIndex == anim.marker_frames[i]) {
 | 
										if (frameIndex == anim.marker_frames[i]) {
 | 
				
			||||||
						var marketAct = markerEvents.get(sampler);
 | 
											var markerAct = markerEvents.get(sampler);
 | 
				
			||||||
						var ar = marketAct.get(anim.marker_names[i]);
 | 
											var ar = markerAct.get(anim.marker_names[i]);
 | 
				
			||||||
						if (ar != null) for (f in ar) f();
 | 
											if (ar != null) for (f in ar) f();
 | 
				
			||||||
 | 
										} else {
 | 
				
			||||||
 | 
											for (j in 0...(frameIndex - lastFrameIndex)) {
 | 
				
			||||||
 | 
												if (lastFrameIndex + j + 1 == anim.marker_frames[i]) {
 | 
				
			||||||
 | 
													var markerAct = markerEvents.get(sampler);
 | 
				
			||||||
 | 
													var ar = markerAct.get(anim.marker_names[i]);
 | 
				
			||||||
 | 
													if (ar != null) for (f in ar) f();
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				lastFrameIndex = frameIndex;
 | 
									lastFrameIndex = frameIndex;
 | 
				
			||||||
 | 
				
			|||||||
@ -31,11 +31,21 @@ class CameraObject extends Object {
 | 
				
			|||||||
	static var vcenter = new Vec4();
 | 
						static var vcenter = new Vec4();
 | 
				
			||||||
	static var vup = new Vec4();
 | 
						static var vup = new Vec4();
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
 | 
						#if lnx_vr
 | 
				
			||||||
 | 
						var helpMat = Mat4.identity();
 | 
				
			||||||
 | 
						public var leftV = Mat4.identity();
 | 
				
			||||||
 | 
						public var rightV = Mat4.identity();
 | 
				
			||||||
 | 
						#end
 | 
				
			||||||
 | 
						
 | 
				
			||||||
	public function new(data: CameraData) {
 | 
						public function new(data: CameraData) {
 | 
				
			||||||
		super();
 | 
							super();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		this.data = data;
 | 
							this.data = data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							#if lnx_vr
 | 
				
			||||||
 | 
							iron.system.VR.initButton();
 | 
				
			||||||
 | 
							#end
 | 
				
			||||||
 | 
							
 | 
				
			||||||
		buildProjection();
 | 
							buildProjection();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		V = Mat4.identity();
 | 
							V = Mat4.identity();
 | 
				
			||||||
@ -117,6 +127,26 @@ class CameraObject extends Object {
 | 
				
			|||||||
		V.getInverse(transform.world);
 | 
							V.getInverse(transform.world);
 | 
				
			||||||
		VP.multmats(P, V);
 | 
							VP.multmats(P, V);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							#if lnx_vr
 | 
				
			||||||
 | 
							var vr = kha.vr.VrInterface.instance;
 | 
				
			||||||
 | 
							if (vr != null && vr.IsPresenting()) {
 | 
				
			||||||
 | 
								leftV.setFrom(V);
 | 
				
			||||||
 | 
								helpMat.self = vr.GetViewMatrix(0);
 | 
				
			||||||
 | 
								leftV.multmat(helpMat);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								rightV.setFrom(V);
 | 
				
			||||||
 | 
								helpMat.self = vr.GetViewMatrix(1);
 | 
				
			||||||
 | 
								rightV.multmat(helpMat);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else {
 | 
				
			||||||
 | 
								leftV.setFrom(V);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							VP.multmats(P, leftV);
 | 
				
			||||||
 | 
							#else
 | 
				
			||||||
 | 
							VP.multmats(P, V);
 | 
				
			||||||
 | 
							#end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (data.raw.frustum_culling) {
 | 
							if (data.raw.frustum_culling) {
 | 
				
			||||||
			buildViewFrustum(VP, frustumPlanes);
 | 
								buildViewFrustum(VP, frustumPlanes);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
				
			|||||||
@ -155,7 +155,12 @@ class LightObject extends Object {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public function setCascade(camera: CameraObject, cascade: Int) {
 | 
						public function setCascade(camera: CameraObject, cascade: Int) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							#if lnx_vr
 | 
				
			||||||
 | 
							m.setFrom(camera.leftV);
 | 
				
			||||||
 | 
							#else
 | 
				
			||||||
		m.setFrom(camera.V);
 | 
							m.setFrom(camera.V);
 | 
				
			||||||
 | 
							#end
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		#if lnx_csm
 | 
							#if lnx_csm
 | 
				
			||||||
		if (camSlicedP == null) {
 | 
							if (camSlicedP == null) {
 | 
				
			||||||
 | 
				
			|||||||
@ -21,8 +21,10 @@ class MeshObject extends Object {
 | 
				
			|||||||
	public var particleChildren: Array<MeshObject> = null;
 | 
						public var particleChildren: Array<MeshObject> = null;
 | 
				
			||||||
	public var particleOwner: MeshObject = null; // Particle object
 | 
						public var particleOwner: MeshObject = null; // Particle object
 | 
				
			||||||
	public var particleIndex = -1;
 | 
						public var particleIndex = -1;
 | 
				
			||||||
 | 
						public var render_emitter = true;
 | 
				
			||||||
	#end
 | 
						#end
 | 
				
			||||||
	public var cameraDistance: Float;
 | 
						public var cameraDistance: Float;
 | 
				
			||||||
 | 
						public var cameraList: Array<String> = null;
 | 
				
			||||||
	public var screenSize = 0.0;
 | 
						public var screenSize = 0.0;
 | 
				
			||||||
	public var frustumCulling = true;
 | 
						public var frustumCulling = true;
 | 
				
			||||||
	public var activeTilesheet: Tilesheet = null;
 | 
						public var activeTilesheet: Tilesheet = null;
 | 
				
			||||||
@ -234,6 +236,8 @@ class MeshObject extends Object {
 | 
				
			|||||||
		if (cullMesh(context, Scene.active.camera, RenderPath.active.light)) return;
 | 
							if (cullMesh(context, Scene.active.camera, RenderPath.active.light)) return;
 | 
				
			||||||
		var meshContext = raw != null ? context == "mesh" : false;
 | 
							var meshContext = raw != null ? context == "mesh" : false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (cameraList != null && cameraList.indexOf(Scene.active.camera.name) < 0) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		#if lnx_particles
 | 
							#if lnx_particles
 | 
				
			||||||
		if (raw != null && raw.is_particle && particleOwner == null) return; // Instancing not yet set-up by particle system owner
 | 
							if (raw != null && raw.is_particle && particleOwner == null) return; // Instancing not yet set-up by particle system owner
 | 
				
			||||||
		if (particleSystems != null && meshContext) {
 | 
							if (particleSystems != null && meshContext) {
 | 
				
			||||||
@ -244,6 +248,7 @@ class MeshObject extends Object {
 | 
				
			|||||||
					Scene.active.spawnObject(psys.data.raw.instance_object, null, function(o: Object) {
 | 
										Scene.active.spawnObject(psys.data.raw.instance_object, null, function(o: Object) {
 | 
				
			||||||
						if (o != null) {
 | 
											if (o != null) {
 | 
				
			||||||
							var c: MeshObject = cast o;
 | 
												var c: MeshObject = cast o;
 | 
				
			||||||
 | 
					    						c.cameraList = this.cameraList;
 | 
				
			||||||
							particleChildren.push(c);
 | 
												particleChildren.push(c);
 | 
				
			||||||
							c.particleOwner = this;
 | 
												c.particleOwner = this;
 | 
				
			||||||
							c.particleIndex = particleChildren.length - 1;
 | 
												c.particleIndex = particleChildren.length - 1;
 | 
				
			||||||
@ -255,11 +260,11 @@ class MeshObject extends Object {
 | 
				
			|||||||
				particleSystems[i].update(particleChildren[i], this);
 | 
									particleSystems[i].update(particleChildren[i], this);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (particleSystems != null && particleSystems.length > 0 && !raw.render_emitter) return;
 | 
							if (particleSystems != null && particleSystems.length > 0 && !render_emitter) return;
 | 
				
			||||||
		#end
 | 
					        if (particleSystems == null && cullMaterial(context)) return;
 | 
				
			||||||
 | 
					        #else
 | 
				
			||||||
        if (cullMaterial(context)) return;
 | 
					        if (cullMaterial(context)) return;
 | 
				
			||||||
 | 
							#end
 | 
				
			||||||
		// Get lod
 | 
							// Get lod
 | 
				
			||||||
		var mats = materials;
 | 
							var mats = materials;
 | 
				
			||||||
		var lod = this;
 | 
							var lod = this;
 | 
				
			||||||
@ -297,6 +302,10 @@ class MeshObject extends Object {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		// Render mesh
 | 
							// Render mesh
 | 
				
			||||||
		var ldata = lod.data;
 | 
							var ldata = lod.data;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							// Next pass rendering first (inverse order)
 | 
				
			||||||
 | 
							renderNextPass(g, context, bindParams, lod);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
		for (i in 0...ldata.geom.indexBuffers.length) {
 | 
							for (i in 0...ldata.geom.indexBuffers.length) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			var mi = ldata.geom.materialIndices[i];
 | 
								var mi = ldata.geom.materialIndices[i];
 | 
				
			||||||
@ -400,4 +409,85 @@ class MeshObject extends Object {
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						function renderNextPass(g: Graphics, context: String, bindParams: Array<String>, lod: MeshObject) {
 | 
				
			||||||
 | 
							var ldata = lod.data;
 | 
				
			||||||
 | 
							for (i in 0...ldata.geom.indexBuffers.length) {
 | 
				
			||||||
 | 
								var mi = ldata.geom.materialIndices[i];
 | 
				
			||||||
 | 
								if (mi >= materials.length) continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var currentMaterial: MaterialData = materials[mi];
 | 
				
			||||||
 | 
								if (currentMaterial == null || currentMaterial.shader == null) continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var nextPassName: String = currentMaterial.shader.nextPass;
 | 
				
			||||||
 | 
								if (nextPassName == null || nextPassName == "") continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var nextMaterial: MaterialData = null;
 | 
				
			||||||
 | 
								for (mat in materials) {
 | 
				
			||||||
 | 
									// First try exact match
 | 
				
			||||||
 | 
									if (mat.name == nextPassName) {
 | 
				
			||||||
 | 
										nextMaterial = mat;
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									// If no exact match, try to match base name for linked materials
 | 
				
			||||||
 | 
									if (mat.name.indexOf("_") > 0 && mat.name.substr(mat.name.length - 6) == ".blend") {
 | 
				
			||||||
 | 
										var baseName = mat.name.substring(0, mat.name.indexOf("_"));
 | 
				
			||||||
 | 
										if (baseName == nextPassName) {
 | 
				
			||||||
 | 
											nextMaterial = mat;
 | 
				
			||||||
 | 
											break;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (nextMaterial == null) continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var nextMaterialContext: MaterialContext = null;
 | 
				
			||||||
 | 
								var nextShaderContext: ShaderContext = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								for (j in 0...nextMaterial.raw.contexts.length) {
 | 
				
			||||||
 | 
									if (nextMaterial.raw.contexts[j].name.substr(0, context.length) == context) {
 | 
				
			||||||
 | 
										nextMaterialContext = nextMaterial.contexts[j];
 | 
				
			||||||
 | 
										nextShaderContext = nextMaterial.shader.getContext(context);
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (nextShaderContext == null) continue;
 | 
				
			||||||
 | 
								if (skipContext(context, nextMaterial)) continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var elems = nextShaderContext.raw.vertex_elements;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Uniforms
 | 
				
			||||||
 | 
								if (nextShaderContext.pipeState != lastPipeline) {
 | 
				
			||||||
 | 
									g.setPipeline(nextShaderContext.pipeState);
 | 
				
			||||||
 | 
									lastPipeline = nextShaderContext.pipeState;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								Uniforms.setContextConstants(g, nextShaderContext, bindParams);
 | 
				
			||||||
 | 
								Uniforms.setObjectConstants(g, nextShaderContext, this);
 | 
				
			||||||
 | 
								Uniforms.setMaterialConstants(g, nextShaderContext, nextMaterialContext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// VB / IB
 | 
				
			||||||
 | 
								#if lnx_deinterleaved
 | 
				
			||||||
 | 
								g.setVertexBuffers(ldata.geom.get(elems));
 | 
				
			||||||
 | 
								#else
 | 
				
			||||||
 | 
								if (ldata.geom.instancedVB != null) {
 | 
				
			||||||
 | 
									g.setVertexBuffers([ldata.geom.get(elems), ldata.geom.instancedVB]);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else {
 | 
				
			||||||
 | 
									g.setVertexBuffer(ldata.geom.get(elems));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								#end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								g.setIndexBuffer(ldata.geom.indexBuffers[i]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Draw next pass for this specific geometry section
 | 
				
			||||||
 | 
								if (ldata.geom.instanced) {
 | 
				
			||||||
 | 
									g.drawIndexedVerticesInstanced(ldata.geom.instanceCount, ldata.geom.start, ldata.geom.count);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else {
 | 
				
			||||||
 | 
									g.drawIndexedVertices(ldata.geom.start, ldata.geom.count);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -172,6 +172,10 @@ class Object {
 | 
				
			|||||||
			for (f in t._init) App.removeInit(f);
 | 
								for (f in t._init) App.removeInit(f);
 | 
				
			||||||
			t._init = null;
 | 
								t._init = null;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							if (t._fixedUpdate != null) {
 | 
				
			||||||
 | 
								for (f in t._fixedUpdate) App.removeFixedUpdate(f);
 | 
				
			||||||
 | 
								t._fixedUpdate = null;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		if (t._update != null) {
 | 
							if (t._update != null) {
 | 
				
			||||||
			for (f in t._update) App.removeUpdate(f);
 | 
								for (f in t._update) App.removeUpdate(f);
 | 
				
			||||||
			t._update = null;
 | 
								t._update = null;
 | 
				
			||||||
 | 
				
			|||||||
@ -24,6 +24,9 @@ class ObjectAnimation extends Animation {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	public var transformMap: Map<String, FastFloat>;
 | 
						public var transformMap: Map<String, FastFloat>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var defaultSampler: ActionSampler = null;
 | 
				
			||||||
 | 
						static inline var DEFAULT_SAMPLER_ID = "__object_default_action__";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public static var trackNames: Array<String> = [	"xloc", "yloc", "zloc",
 | 
						public static var trackNames: Array<String> = [	"xloc", "yloc", "zloc",
 | 
				
			||||||
											   		"xrot", "yrot", "zrot",
 | 
																   		"xrot", "yrot", "zrot",
 | 
				
			||||||
											   		"qwrot", "qxrot", "qyrot", "qzrot",
 | 
																   		"qwrot", "qxrot", "qyrot", "qzrot",
 | 
				
			||||||
@ -39,7 +42,6 @@ class ObjectAnimation extends Animation {
 | 
				
			|||||||
		isSkinned = false;
 | 
							isSkinned = false;
 | 
				
			||||||
		super();
 | 
							super();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	function getAction(action: String): TObj {
 | 
						function getAction(action: String): TObj {
 | 
				
			||||||
		for (a in oactions) if (a != null && a.objects[0].name == action) return a.objects[0];
 | 
							for (a in oactions) if (a != null && a.objects[0].name == action) return a.objects[0];
 | 
				
			||||||
		return null;
 | 
							return null;
 | 
				
			||||||
@ -47,10 +49,29 @@ class ObjectAnimation extends Animation {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	override public function play(action = "", onComplete: Void->Void = null, blendTime = 0.0, speed = 1.0, loop = true) {
 | 
						override public function play(action = "", onComplete: Void->Void = null, blendTime = 0.0, speed = 1.0, loop = true) {
 | 
				
			||||||
		super.play(action, onComplete, blendTime, speed, loop);
 | 
							super.play(action, onComplete, blendTime, speed, loop);
 | 
				
			||||||
		if (this.action == "" && oactions[0] != null) this.action = oactions[0].objects[0].name;
 | 
							if (this.action == "" && oactions != null && oactions[0] != null){
 | 
				
			||||||
 | 
								this.action = oactions[0].objects[0].name;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		oaction = getAction(this.action);
 | 
							oaction = getAction(this.action);
 | 
				
			||||||
		if (oaction != null) {
 | 
							if (oaction != null) {
 | 
				
			||||||
			isSampled = oaction.sampled != null && oaction.sampled;
 | 
								isSampled = oaction.sampled != null && oaction.sampled;
 | 
				
			||||||
 | 
								if (defaultSampler != null) {
 | 
				
			||||||
 | 
									deRegisterAction(DEFAULT_SAMPLER_ID);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								var callbacks = onComplete != null ? [onComplete] : null;
 | 
				
			||||||
 | 
								defaultSampler = new ActionSampler(this.action, speed, loop, false, callbacks);
 | 
				
			||||||
 | 
								registerAction(DEFAULT_SAMPLER_ID, defaultSampler);
 | 
				
			||||||
 | 
								if (paused) defaultSampler.paused = true;
 | 
				
			||||||
 | 
								updateAnimation = function(map: Map<String, FastFloat>) {
 | 
				
			||||||
 | 
									sampleAction(defaultSampler, map);
 | 
				
			||||||
 | 
								};
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else {
 | 
				
			||||||
 | 
								if (defaultSampler != null) {
 | 
				
			||||||
 | 
									deRegisterAction(DEFAULT_SAMPLER_ID);
 | 
				
			||||||
 | 
									defaultSampler = null;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								updateAnimation = null;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -61,12 +82,13 @@ class ObjectAnimation extends Animation {
 | 
				
			|||||||
		Animation.beginProfile();
 | 
							Animation.beginProfile();
 | 
				
			||||||
		#end
 | 
							#end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if(transformMap == null) transformMap = new Map();
 | 
							if (transformMap == null) transformMap = new Map();
 | 
				
			||||||
		transformMap = initTransformMap();
 | 
							transformMap = initTransformMap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		super.update(delta);
 | 
							super.update(delta);
 | 
				
			||||||
 | 
							if (defaultSampler != null) defaultSampler.paused = paused;
 | 
				
			||||||
		if (paused) return;
 | 
							if (paused) return;
 | 
				
			||||||
		if(updateAnimation == null) return;
 | 
							if (updateAnimation == null) return;
 | 
				
			||||||
		if (!isSkinned) updateObjectAnimation();
 | 
							if (!isSkinned) updateObjectAnimation();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		#if lnx_debug
 | 
							#if lnx_debug
 | 
				
			||||||
 | 
				
			|||||||
@ -2,11 +2,14 @@ package iron.object;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#if lnx_particles
 | 
					#if lnx_particles
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import kha.FastFloat;
 | 
				
			||||||
import kha.graphics4.Usage;
 | 
					import kha.graphics4.Usage;
 | 
				
			||||||
import kha.arrays.Float32Array;
 | 
					import kha.arrays.Float32Array;
 | 
				
			||||||
import iron.data.Data;
 | 
					import iron.data.Data;
 | 
				
			||||||
import iron.data.ParticleData;
 | 
					import iron.data.ParticleData;
 | 
				
			||||||
import iron.data.SceneFormat;
 | 
					import iron.data.SceneFormat;
 | 
				
			||||||
 | 
					import iron.data.Geometry;
 | 
				
			||||||
 | 
					import iron.data.MeshData;
 | 
				
			||||||
import iron.system.Time;
 | 
					import iron.system.Time;
 | 
				
			||||||
import iron.math.Mat4;
 | 
					import iron.math.Mat4;
 | 
				
			||||||
import iron.math.Quat;
 | 
					import iron.math.Quat;
 | 
				
			||||||
@ -16,10 +19,13 @@ import iron.math.Vec4;
 | 
				
			|||||||
class ParticleSystem {
 | 
					class ParticleSystem {
 | 
				
			||||||
	public var data: ParticleData;
 | 
						public var data: ParticleData;
 | 
				
			||||||
	public var speed = 1.0;
 | 
						public var speed = 1.0;
 | 
				
			||||||
 | 
						public var dynamicEmitter: Bool = true;
 | 
				
			||||||
 | 
						var currentSpeed = 0.0;
 | 
				
			||||||
	var particles: Array<Particle>;
 | 
						var particles: Array<Particle>;
 | 
				
			||||||
	var ready: Bool;
 | 
						var ready: Bool;
 | 
				
			||||||
	var frameRate = 24;
 | 
						var frameRate = 24;
 | 
				
			||||||
	var lifetime = 0.0;
 | 
						var lifetime = 0.0;
 | 
				
			||||||
 | 
						var looptime = 0.0;
 | 
				
			||||||
	var animtime = 0.0;
 | 
						var animtime = 0.0;
 | 
				
			||||||
	var time = 0.0;
 | 
						var time = 0.0;
 | 
				
			||||||
	var spawnRate = 0.0;
 | 
						var spawnRate = 0.0;
 | 
				
			||||||
@ -47,14 +53,30 @@ class ParticleSystem {
 | 
				
			|||||||
	var ownerRot = new Quat();
 | 
						var ownerRot = new Quat();
 | 
				
			||||||
	var ownerScl = new Vec4();
 | 
						var ownerScl = new Vec4();
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
 | 
						var random = 0.0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var tmpV4 = new Vec4();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var instancedData: Float32Array = null;
 | 
				
			||||||
 | 
						var lastSpawnedCount: Int = 0;
 | 
				
			||||||
 | 
						var hasUniqueGeom: Bool = false; 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public function new(sceneName: String, pref: TParticleReference) {
 | 
						public function new(sceneName: String, pref: TParticleReference) {
 | 
				
			||||||
		seed = pref.seed;
 | 
							seed = pref.seed;
 | 
				
			||||||
 | 
							currentSpeed = speed;
 | 
				
			||||||
 | 
							speed = 0;
 | 
				
			||||||
		particles = [];
 | 
							particles = [];
 | 
				
			||||||
		ready = false;
 | 
							ready = false;
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		Data.getParticle(sceneName, pref.particle, function(b: ParticleData) {
 | 
							Data.getParticle(sceneName, pref.particle, function(b: ParticleData) {
 | 
				
			||||||
			data = b;
 | 
								data = b;
 | 
				
			||||||
			r = data.raw;
 | 
								r = data.raw;
 | 
				
			||||||
 | 
								var dyn: Null<Bool> = r.dynamic_emitter;
 | 
				
			||||||
 | 
								var dynValue: Bool = true;
 | 
				
			||||||
 | 
								if (dyn != null) {
 | 
				
			||||||
 | 
									dynValue = dyn;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								dynamicEmitter = dynValue;
 | 
				
			||||||
			if (Scene.active.raw.gravity != null) {
 | 
								if (Scene.active.raw.gravity != null) {
 | 
				
			||||||
				gx = Scene.active.raw.gravity[0] * r.weight_gravity;
 | 
									gx = Scene.active.raw.gravity[0] * r.weight_gravity;
 | 
				
			||||||
				gy = Scene.active.raw.gravity[1] * r.weight_gravity;
 | 
									gy = Scene.active.raw.gravity[1] * r.weight_gravity;
 | 
				
			||||||
@ -65,38 +87,73 @@ class ParticleSystem {
 | 
				
			|||||||
				gy = 0;
 | 
									gy = 0;
 | 
				
			||||||
				gz = -9.81 * r.weight_gravity;
 | 
									gz = -9.81 * r.weight_gravity;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			alignx = r.object_align_factor[0] / 2;
 | 
								alignx = r.object_align_factor[0];
 | 
				
			||||||
			aligny = r.object_align_factor[1] / 2;
 | 
								aligny = r.object_align_factor[1];
 | 
				
			||||||
			alignz = r.object_align_factor[2] / 2;
 | 
								alignz = r.object_align_factor[2];
 | 
				
			||||||
 | 
								looptime = (r.frame_end - r.frame_start) / frameRate;
 | 
				
			||||||
			lifetime = r.lifetime / frameRate;
 | 
								lifetime = r.lifetime / frameRate;
 | 
				
			||||||
			animtime = (r.frame_end - r.frame_start) / frameRate;
 | 
								animtime = r.loop ? looptime : looptime + lifetime;
 | 
				
			||||||
			spawnRate = ((r.frame_end - r.frame_start) / r.count) / frameRate;
 | 
								spawnRate = ((r.frame_end - r.frame_start) / r.count) / frameRate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			for (i in 0...r.count) {
 | 
								for (i in 0...r.count) {
 | 
				
			||||||
				var particle = new Particle(i);
 | 
									particles.push(new Particle(i));
 | 
				
			||||||
				particle.sr = 1 - Math.random() * r.size_random;
 | 
					 | 
				
			||||||
				particles.push(particle);
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			ready = true;
 | 
								ready = true;
 | 
				
			||||||
 | 
								if (r.auto_start){
 | 
				
			||||||
 | 
									start();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		});
 | 
							});
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public function start() {
 | 
				
			||||||
 | 
							if (r.is_unique) random = Math.random();
 | 
				
			||||||
 | 
							lifetime = r.lifetime / frameRate;
 | 
				
			||||||
 | 
							time = 0;
 | 
				
			||||||
 | 
							lap = 0;
 | 
				
			||||||
 | 
							lapTime = 0;
 | 
				
			||||||
 | 
							speed = currentSpeed;
 | 
				
			||||||
 | 
							lastSpawnedCount = 0;
 | 
				
			||||||
 | 
							instancedData = null;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public function pause() {
 | 
						public function pause() {
 | 
				
			||||||
		lifetime = 0;
 | 
							speed = 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public function resume() {
 | 
						public function resume() {
 | 
				
			||||||
		lifetime = r.lifetime / frameRate;
 | 
							lifetime = r.lifetime / frameRate;
 | 
				
			||||||
 | 
							speed = currentSpeed;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TODO: interrupt smoothly
 | 
				
			||||||
 | 
						public function stop() {
 | 
				
			||||||
 | 
							end();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						function end() {
 | 
				
			||||||
 | 
							lifetime = 0;
 | 
				
			||||||
 | 
							speed = 0;
 | 
				
			||||||
 | 
							lap = 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	public function update(object: MeshObject, owner: MeshObject) {
 | 
						public function update(object: MeshObject, owner: MeshObject) {
 | 
				
			||||||
		if (!ready || object == null || speed == 0.0) return;
 | 
							if (!ready || object == null || speed == 0.0) return;
 | 
				
			||||||
 | 
							if (iron.App.pauseUpdates) return;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							var prevLap = lap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Copy owner world transform but discard scale
 | 
							// Copy owner world transform but discard scale
 | 
				
			||||||
		owner.transform.world.decompose(ownerLoc, ownerRot, ownerScl);
 | 
							owner.transform.world.decompose(ownerLoc, ownerRot, ownerScl);
 | 
				
			||||||
 | 
							if (dynamicEmitter) {
 | 
				
			||||||
 | 
								object.transform.loc.x = 0; object.transform.loc.y = 0; object.transform.loc.z = 0;
 | 
				
			||||||
 | 
								object.transform.rot = new Quat();
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
			object.transform.loc = ownerLoc;
 | 
								object.transform.loc = ownerLoc;
 | 
				
			||||||
			object.transform.rot = ownerRot;
 | 
								object.transform.rot = ownerRot;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Set particle size per particle system
 | 
							// Set particle size per particle system
 | 
				
			||||||
		object.transform.scale = new Vec4(r.particle_size, r.particle_size, r.particle_size, 1);
 | 
							object.transform.scale = new Vec4(r.particle_size, r.particle_size, r.particle_size, 1);
 | 
				
			||||||
@ -115,16 +172,25 @@ class ParticleSystem {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Animate
 | 
							// Animate
 | 
				
			||||||
		time += Time.delta * speed;
 | 
							time += Time.renderDelta * speed; // realDelta to renderDelta
 | 
				
			||||||
		lap = Std.int(time / animtime);
 | 
							lap = Std.int(time / animtime);
 | 
				
			||||||
		lapTime = time - lap * animtime;
 | 
							lapTime = time - lap * animtime;
 | 
				
			||||||
		count = Std.int(lapTime / spawnRate);
 | 
							count = Std.int(lapTime / spawnRate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (lap > prevLap && !r.loop) {
 | 
				
			||||||
 | 
								end();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (lap > prevLap && r.loop) {
 | 
				
			||||||
 | 
								lastSpawnedCount = 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
		updateGpu(object, owner);
 | 
							updateGpu(object, owner);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public function getData(): Mat4 {
 | 
						public function getData(): Mat4 {
 | 
				
			||||||
		var hair = r.type == 1;
 | 
							var hair = r.type == 1;
 | 
				
			||||||
 | 
							// Store loop flag in the sign: positive -> loop, negative -> no loop
 | 
				
			||||||
		m._00 = r.loop ? animtime : -animtime;
 | 
							m._00 = r.loop ? animtime : -animtime;
 | 
				
			||||||
		m._01 = hair ? 1 / particles.length : spawnRate;
 | 
							m._01 = hair ? 1 / particles.length : spawnRate;
 | 
				
			||||||
		m._02 = hair ? 1 : lifetime;
 | 
							m._02 = hair ? 1 : lifetime;
 | 
				
			||||||
@ -133,9 +199,9 @@ class ParticleSystem {
 | 
				
			|||||||
		m._11 = hair ? 0 : aligny;
 | 
							m._11 = hair ? 0 : aligny;
 | 
				
			||||||
		m._12 = hair ? 0 : alignz;
 | 
							m._12 = hair ? 0 : alignz;
 | 
				
			||||||
		m._13 = hair ? 0 : r.factor_random;
 | 
							m._13 = hair ? 0 : r.factor_random;
 | 
				
			||||||
		m._20 = hair ? 0 : gx * r.mass;
 | 
							m._20 = hair ? 0 : gx;
 | 
				
			||||||
		m._21 = hair ? 0 : gy * r.mass;
 | 
							m._21 = hair ? 0 : gy;
 | 
				
			||||||
		m._22 = hair ? 0 : gz * r.mass;
 | 
							m._22 = hair ? 0 : gz;
 | 
				
			||||||
		m._23 = hair ? 0 : r.lifetime_random;
 | 
							m._23 = hair ? 0 : r.lifetime_random;
 | 
				
			||||||
		m._30 = tilesx;
 | 
							m._30 = tilesx;
 | 
				
			||||||
		m._31 = tilesy;
 | 
							m._31 = tilesy;
 | 
				
			||||||
@ -144,13 +210,34 @@ class ParticleSystem {
 | 
				
			|||||||
		return m;
 | 
							return m;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public function getSizeRandom(): FastFloat {
 | 
				
			||||||
 | 
							return r.size_random;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public inline function getRandom(): FastFloat {
 | 
				
			||||||
 | 
							return random;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public inline function getSize(): FastFloat {
 | 
				
			||||||
 | 
							return r.particle_size;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	function updateGpu(object: MeshObject, owner: MeshObject) {
 | 
						function updateGpu(object: MeshObject, owner: MeshObject) {
 | 
				
			||||||
 | 
							if (dynamicEmitter) {
 | 
				
			||||||
 | 
								if (!hasUniqueGeom) ensureUniqueGeom(object);
 | 
				
			||||||
 | 
								var needSetup = instancedData == null || object.data.geom.instancedVB == null;
 | 
				
			||||||
 | 
								if (needSetup) setupGeomGpuDynamic(object, owner);
 | 
				
			||||||
 | 
								updateSpawnedInstances(object, owner);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else {
 | 
				
			||||||
 | 
								if (!hasUniqueGeom) ensureUniqueGeom(object);
 | 
				
			||||||
			if (!object.data.geom.instanced) setupGeomGpu(object, owner);
 | 
								if (!object.data.geom.instanced) setupGeomGpu(object, owner);
 | 
				
			||||||
		// GPU particles transform is attached to owner object
 | 
							}
 | 
				
			||||||
 | 
							// GPU particles transform is attached to owner object in static mode
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	function setupGeomGpu(object: MeshObject, owner: MeshObject) {
 | 
						function setupGeomGpu(object: MeshObject, owner: MeshObject) {
 | 
				
			||||||
		var instancedData = new Float32Array(particles.length * 6);
 | 
							var instancedData = new Float32Array(particles.length * 3);
 | 
				
			||||||
		var i = 0;
 | 
							var i = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		var normFactor = 1 / 32767; // pa.values are not normalized
 | 
							var normFactor = 1 / 32767; // pa.values are not normalized
 | 
				
			||||||
@ -169,10 +256,6 @@ class ParticleSystem {
 | 
				
			|||||||
					instancedData.set(i, pa.values[j * pa.size    ] * normFactor * scaleFactor.x); i++;
 | 
										instancedData.set(i, pa.values[j * pa.size    ] * normFactor * scaleFactor.x); i++;
 | 
				
			||||||
					instancedData.set(i, pa.values[j * pa.size + 1] * normFactor * scaleFactor.y); i++;
 | 
										instancedData.set(i, pa.values[j * pa.size + 1] * normFactor * scaleFactor.y); i++;
 | 
				
			||||||
					instancedData.set(i, pa.values[j * pa.size + 2] * normFactor * scaleFactor.z); i++;
 | 
										instancedData.set(i, pa.values[j * pa.size + 2] * normFactor * scaleFactor.z); i++;
 | 
				
			||||||
 | 
					 | 
				
			||||||
					instancedData.set(i, p.sr); i++;
 | 
					 | 
				
			||||||
					instancedData.set(i, p.sr); i++;
 | 
					 | 
				
			||||||
					instancedData.set(i, p.sr); i++;
 | 
					 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			case 1: // Face
 | 
								case 1: // Face
 | 
				
			||||||
@ -196,10 +279,6 @@ class ParticleSystem {
 | 
				
			|||||||
					instancedData.set(i, pos.x * normFactor * scaleFactor.x); i++;
 | 
										instancedData.set(i, pos.x * normFactor * scaleFactor.x); i++;
 | 
				
			||||||
					instancedData.set(i, pos.y * normFactor * scaleFactor.y); i++;
 | 
										instancedData.set(i, pos.y * normFactor * scaleFactor.y); i++;
 | 
				
			||||||
					instancedData.set(i, pos.z * normFactor * scaleFactor.z); i++;
 | 
										instancedData.set(i, pos.z * normFactor * scaleFactor.z); i++;
 | 
				
			||||||
 | 
					 | 
				
			||||||
					instancedData.set(i, p.sr); i++;
 | 
					 | 
				
			||||||
					instancedData.set(i, p.sr); i++;
 | 
					 | 
				
			||||||
					instancedData.set(i, p.sr); i++;
 | 
					 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			case 2: // Volume
 | 
								case 2: // Volume
 | 
				
			||||||
@ -210,21 +289,133 @@ class ParticleSystem {
 | 
				
			|||||||
					instancedData.set(i, (Math.random() * 2.0 - 1.0) * scaleFactorVolume.x); i++;
 | 
										instancedData.set(i, (Math.random() * 2.0 - 1.0) * scaleFactorVolume.x); i++;
 | 
				
			||||||
					instancedData.set(i, (Math.random() * 2.0 - 1.0) * scaleFactorVolume.y); i++;
 | 
										instancedData.set(i, (Math.random() * 2.0 - 1.0) * scaleFactorVolume.y); i++;
 | 
				
			||||||
					instancedData.set(i, (Math.random() * 2.0 - 1.0) * scaleFactorVolume.z); i++;
 | 
										instancedData.set(i, (Math.random() * 2.0 - 1.0) * scaleFactorVolume.z); i++;
 | 
				
			||||||
 | 
					 | 
				
			||||||
					instancedData.set(i, p.sr); i++;
 | 
					 | 
				
			||||||
					instancedData.set(i, p.sr); i++;
 | 
					 | 
				
			||||||
					instancedData.set(i, p.sr); i++;
 | 
					 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		object.data.geom.setupInstanced(instancedData, 3, Usage.StaticUsage);
 | 
							object.data.geom.setupInstanced(instancedData, 1, Usage.StaticUsage);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	function fhash(n: Int): Float {
 | 
						// allocate instanced VB once for this object 
 | 
				
			||||||
 | 
						function setupGeomGpuDynamic(object: MeshObject, owner: MeshObject) {
 | 
				
			||||||
 | 
							if (instancedData == null) instancedData = new Float32Array(particles.length * 3);
 | 
				
			||||||
 | 
							lastSpawnedCount = 0; 
 | 
				
			||||||
 | 
							// Create instanced VB once if missing (seed with our instancedData)
 | 
				
			||||||
 | 
							if (object.data.geom.instancedVB == null) {
 | 
				
			||||||
 | 
								object.data.geom.setupInstanced(instancedData, 1, Usage.DynamicUsage);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						function ensureUniqueGeom(object: MeshObject) {
 | 
				
			||||||
 | 
							if (hasUniqueGeom) return;
 | 
				
			||||||
 | 
							var newData: MeshData = null;
 | 
				
			||||||
 | 
							new MeshData(object.data.raw, function(dat: MeshData) {
 | 
				
			||||||
 | 
								dat.scalePos = object.data.scalePos;
 | 
				
			||||||
 | 
								dat.scaleTex = object.data.scaleTex;
 | 
				
			||||||
 | 
								dat.format = object.data.format;
 | 
				
			||||||
 | 
								newData = dat;
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
							if (newData != null) object.setData(newData);
 | 
				
			||||||
 | 
							hasUniqueGeom = true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						function updateSpawnedInstances(object: MeshObject, owner: MeshObject) {
 | 
				
			||||||
 | 
							if (instancedData == null) return;
 | 
				
			||||||
 | 
							var targetCount = count;
 | 
				
			||||||
 | 
							if (targetCount > particles.length) targetCount = particles.length;
 | 
				
			||||||
 | 
							if (targetCount <= lastSpawnedCount) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var normFactor = 1 / 32767;
 | 
				
			||||||
 | 
							var scalePosOwner = owner.data.scalePos;
 | 
				
			||||||
 | 
							var scalePosParticle = object.data.scalePos;
 | 
				
			||||||
 | 
							var particleSize = r.particle_size;
 | 
				
			||||||
 | 
							var base = 1.0 / (particleSize * scalePosParticle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							switch (r.emit_from) {
 | 
				
			||||||
 | 
								case 0: // Vert
 | 
				
			||||||
 | 
									var pa = owner.data.geom.positions;
 | 
				
			||||||
 | 
									var osx = owner.transform.scale.x;
 | 
				
			||||||
 | 
									var osy = owner.transform.scale.y;
 | 
				
			||||||
 | 
									var osz = owner.transform.scale.z;
 | 
				
			||||||
 | 
									var pCount = Std.int(pa.values.length / pa.size);
 | 
				
			||||||
 | 
									for (idx in lastSpawnedCount...targetCount) {
 | 
				
			||||||
 | 
										var j = Std.int(fhash(idx) * pCount);
 | 
				
			||||||
 | 
										var lx = pa.values[j * pa.size    ] * normFactor * scalePosOwner * osx;
 | 
				
			||||||
 | 
										var ly = pa.values[j * pa.size + 1] * normFactor * scalePosOwner * osy;
 | 
				
			||||||
 | 
										var lz = pa.values[j * pa.size + 2] * normFactor * scalePosOwner * osz;
 | 
				
			||||||
 | 
										tmpV4.x = lx; tmpV4.y = ly; tmpV4.z = lz; tmpV4.w = 1;
 | 
				
			||||||
 | 
										tmpV4.applyQuat(ownerRot);
 | 
				
			||||||
 | 
										var o = idx * 3;
 | 
				
			||||||
 | 
										instancedData.set(o    , (tmpV4.x + ownerLoc.x) * base);
 | 
				
			||||||
 | 
										instancedData.set(o + 1, (tmpV4.y + ownerLoc.y) * base);
 | 
				
			||||||
 | 
										instancedData.set(o + 2, (tmpV4.z + ownerLoc.z) * base);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								case 1: // Face
 | 
				
			||||||
 | 
									var positions = owner.data.geom.positions.values;
 | 
				
			||||||
 | 
									var osx1 = owner.transform.scale.x;
 | 
				
			||||||
 | 
									var osy1 = owner.transform.scale.y;
 | 
				
			||||||
 | 
									var osz1 = owner.transform.scale.z;
 | 
				
			||||||
 | 
									for (idx in lastSpawnedCount...targetCount) {
 | 
				
			||||||
 | 
										var ia = owner.data.geom.indices[Std.random(owner.data.geom.indices.length)];
 | 
				
			||||||
 | 
										var faceIndex = Std.random(Std.int(ia.length / 3));
 | 
				
			||||||
 | 
										var i0 = ia[faceIndex * 3 + 0];
 | 
				
			||||||
 | 
										var i1 = ia[faceIndex * 3 + 1];
 | 
				
			||||||
 | 
										var i2 = ia[faceIndex * 3 + 2];
 | 
				
			||||||
 | 
										var v0x = positions[i0 * 4    ], v0y = positions[i0 * 4 + 1], v0z = positions[i0 * 4 + 2];
 | 
				
			||||||
 | 
										var v1x = positions[i1 * 4    ], v1y = positions[i1 * 4 + 1], v1z = positions[i1 * 4 + 2];
 | 
				
			||||||
 | 
										var v2x = positions[i2 * 4    ], v2y = positions[i2 * 4 + 1], v2z = positions[i2 * 4 + 2];
 | 
				
			||||||
 | 
										var rx = Math.random(); var ry = Math.random(); if (rx + ry > 1) { rx = 1 - rx; ry = 1 - ry; }
 | 
				
			||||||
 | 
										var pxs = v0x + rx * (v1x - v0x) + ry * (v2x - v0x);
 | 
				
			||||||
 | 
										var pys = v0y + rx * (v1y - v0y) + ry * (v2y - v0y);
 | 
				
			||||||
 | 
										var pzs = v0z + rx * (v1z - v0z) + ry * (v2z - v0z);
 | 
				
			||||||
 | 
										var px = pxs * normFactor * scalePosOwner * osx1;
 | 
				
			||||||
 | 
										var py = pys * normFactor * scalePosOwner * osy1;
 | 
				
			||||||
 | 
										var pz = pzs * normFactor * scalePosOwner * osz1;
 | 
				
			||||||
 | 
										tmpV4.x = px; tmpV4.y = py; tmpV4.z = pz; tmpV4.w = 1;
 | 
				
			||||||
 | 
										tmpV4.applyQuat(ownerRot);
 | 
				
			||||||
 | 
										var o1 = idx * 3;
 | 
				
			||||||
 | 
										instancedData.set(o1    , (tmpV4.x + ownerLoc.x) * base);
 | 
				
			||||||
 | 
										instancedData.set(o1 + 1, (tmpV4.y + ownerLoc.y) * base);
 | 
				
			||||||
 | 
										instancedData.set(o1 + 2, (tmpV4.z + ownerLoc.z) * base);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								case 2: // Volume
 | 
				
			||||||
 | 
									var dim = object.transform.dim;
 | 
				
			||||||
 | 
									for (idx in lastSpawnedCount...targetCount) {
 | 
				
			||||||
 | 
										tmpV4.x = (Math.random() * 2.0 - 1.0) * (dim.x * 0.5);
 | 
				
			||||||
 | 
										tmpV4.y = (Math.random() * 2.0 - 1.0) * (dim.y * 0.5);
 | 
				
			||||||
 | 
										tmpV4.z = (Math.random() * 2.0 - 1.0) * (dim.z * 0.5);
 | 
				
			||||||
 | 
										tmpV4.w = 1;
 | 
				
			||||||
 | 
										tmpV4.applyQuat(ownerRot);
 | 
				
			||||||
 | 
										var o2 = idx * 3;
 | 
				
			||||||
 | 
										instancedData.set(o2    , (tmpV4.x + ownerLoc.x) * base);
 | 
				
			||||||
 | 
										instancedData.set(o2 + 1, (tmpV4.y + ownerLoc.y) * base);
 | 
				
			||||||
 | 
										instancedData.set(o2 + 2, (tmpV4.z + ownerLoc.z) * base);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Upload full active range [0..targetCount) to this object's instanced VB
 | 
				
			||||||
 | 
							var geom = object.data.geom;
 | 
				
			||||||
 | 
							if (geom.instancedVB == null) {
 | 
				
			||||||
 | 
								geom.setupInstanced(instancedData, 1, Usage.DynamicUsage);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							var vb = geom.instancedVB.lock();
 | 
				
			||||||
 | 
							var totalFloats = targetCount * 3; // xyz per instance
 | 
				
			||||||
 | 
							var i = 0;
 | 
				
			||||||
 | 
							while (i < totalFloats) {
 | 
				
			||||||
 | 
								vb.setFloat32(i * 4, instancedData[i]);
 | 
				
			||||||
 | 
								i++;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							geom.instancedVB.unlock();
 | 
				
			||||||
 | 
							geom.instanceCount = targetCount;
 | 
				
			||||||
 | 
							lastSpawnedCount = targetCount;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inline function fhash(n: Int): Float {
 | 
				
			||||||
    var s = n + 1.0;
 | 
					    var s = n + 1.0;
 | 
				
			||||||
    s *= 9301.0 % s;
 | 
					    s *= 9301.0 % s;
 | 
				
			||||||
    s = (s * 9301.0 + 49297.0) % 233280.0;
 | 
					    s = (s * 9301.0 + 49297.0) % 233280.0;
 | 
				
			||||||
    return s / 233280.0;
 | 
					    return s / 233280.0;
 | 
				
			||||||
	}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public function remove() {}
 | 
						public function remove() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -255,10 +446,11 @@ class ParticleSystem {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
class Particle {
 | 
					class Particle {
 | 
				
			||||||
	public var i: Int;
 | 
						public var i: Int;
 | 
				
			||||||
	public var px = 0.0;
 | 
						
 | 
				
			||||||
	public var py = 0.0;
 | 
						public var x = 0.0;
 | 
				
			||||||
	public var pz = 0.0;
 | 
						public var y = 0.0;
 | 
				
			||||||
	public var sr = 1.0; // Size random
 | 
						public var z = 0.0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public var cameraDistance: Float;
 | 
						public var cameraDistance: Float;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public function new(i: Int) {
 | 
						public function new(i: Int) {
 | 
				
			||||||
 | 
				
			|||||||
@ -80,7 +80,7 @@ class Tilesheet {
 | 
				
			|||||||
	function update() {
 | 
						function update() {
 | 
				
			||||||
		if (!ready || paused || action.start >= action.end) return;
 | 
							if (!ready || paused || action.start >= action.end) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		time += Time.realDelta;
 | 
							time += Time.renderDelta;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		var frameTime = 1 / raw.framerate;
 | 
							var frameTime = 1 / raw.framerate;
 | 
				
			||||||
		var framesToAdvance = 0;
 | 
							var framesToAdvance = 0;
 | 
				
			||||||
 | 
				
			|||||||
@ -181,11 +181,15 @@ class Uniforms {
 | 
				
			|||||||
						// Multiple voxel volumes, always set params
 | 
											// Multiple voxel volumes, always set params
 | 
				
			||||||
						g.setImageTexture(context.textureUnits[j], rt.image); // image2D/3D
 | 
											g.setImageTexture(context.textureUnits[j], rt.image); // image2D/3D
 | 
				
			||||||
						if (rt.raw.name.startsWith("voxels_")) {
 | 
											if (rt.raw.name.startsWith("voxels_")) {
 | 
				
			||||||
							g.setTextureParameters(context.textureUnits[j], TextureAddressing.Clamp, TextureAddressing.Clamp, TextureFilter.LinearFilter, TextureFilter.LinearFilter, MipMapFilter.NoMipFilter);
 | 
												g.setTextureParameters(context.textureUnits[j], TextureAddressing.Clamp, TextureAddressing.Clamp, TextureFilter.LinearFilter, TextureFilter.LinearFilter, MipMapFilter.LinearMipFilter);
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
											else if (rt.raw.name.startsWith("voxelsSDF"))
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												g.setTexture3DParameters(context.textureUnits[j], TextureAddressing.Clamp, TextureAddressing.Clamp, TextureAddressing.Clamp, TextureFilter.PointFilter, TextureFilter.PointFilter, MipMapFilter.NoMipFilter);
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
						else if (rt.raw.name.startsWith("voxels"))
 | 
											else if (rt.raw.name.startsWith("voxels"))
 | 
				
			||||||
						{
 | 
											{
 | 
				
			||||||
							g.setTexture3DParameters(context.textureUnits[j], TextureAddressing.Clamp, TextureAddressing.Clamp, TextureAddressing.Clamp, TextureFilter.LinearFilter, TextureFilter.LinearFilter, MipMapFilter.NoMipFilter);
 | 
												g.setTexture3DParameters(context.textureUnits[j], TextureAddressing.Clamp, TextureAddressing.Clamp, TextureAddressing.Clamp, TextureFilter.LinearFilter, TextureFilter.LinearFilter, MipMapFilter.PointMipFilter);
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
						else
 | 
											else
 | 
				
			||||||
						{
 | 
											{
 | 
				
			||||||
@ -1109,6 +1113,26 @@ class Uniforms {
 | 
				
			|||||||
				case "_texUnpack": {
 | 
									case "_texUnpack": {
 | 
				
			||||||
					f = texUnpack != null ? texUnpack : 1.0;
 | 
										f = texUnpack != null ? texUnpack : 1.0;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
									#if lnx_particles
 | 
				
			||||||
 | 
									case "_particleSizeRandom": {
 | 
				
			||||||
 | 
										var mo = cast(object, MeshObject);
 | 
				
			||||||
 | 
										if (mo.particleOwner != null && mo.particleOwner.particleSystems != null) {
 | 
				
			||||||
 | 
											f = mo.particleOwner.particleSystems[mo.particleIndex].getSizeRandom();
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									case "_particleRandom": {
 | 
				
			||||||
 | 
										var mo = cast(object, MeshObject);
 | 
				
			||||||
 | 
										if (mo.particleOwner != null && mo.particleOwner.particleSystems != null) {
 | 
				
			||||||
 | 
											f = mo.particleOwner.particleSystems[mo.particleIndex].getRandom();
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									case "_particleSize": {
 | 
				
			||||||
 | 
										var mo = cast(object, MeshObject);
 | 
				
			||||||
 | 
										if (mo.particleOwner != null && mo.particleOwner.particleSystems != null) {
 | 
				
			||||||
 | 
											f = mo.particleOwner.particleSystems[mo.particleIndex].getSize();
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									#end
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (f == null && externalFloatLinks != null) {
 | 
								if (f == null && externalFloatLinks != null) {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,12 @@
 | 
				
			|||||||
package iron.system;
 | 
					package iron.system;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Time {
 | 
					class Time {
 | 
				
			||||||
 | 
						public static var scale = 1.0;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						static var frequency: Null<Int> = null;
 | 
				
			||||||
 | 
						static function initFrequency() {
 | 
				
			||||||
 | 
							frequency = kha.Display.primary != null ? kha.Display.primary.frequency : 60;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	public static var step(get, never): Float;
 | 
						public static var step(get, never): Float;
 | 
				
			||||||
	static function get_step(): Float {
 | 
						static function get_step(): Float {
 | 
				
			||||||
@ -8,30 +14,45 @@ class Time {
 | 
				
			|||||||
		return 1 / frequency;
 | 
							return 1 / frequency;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	public static var scale = 1.0;
 | 
						static var _fixedStep: Null<Float> = 1/60;
 | 
				
			||||||
 | 
						public static var fixedStep(get, never): Float;
 | 
				
			||||||
 | 
						static function get_fixedStep(): Float {
 | 
				
			||||||
 | 
							return _fixedStep;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						public static function initFixedStep(value: Float = 1 / 60) {
 | 
				
			||||||
 | 
							_fixedStep = value;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static var lastTime = 0.0;
 | 
				
			||||||
 | 
						static var _delta = 0.0;
 | 
				
			||||||
	public static var delta(get, never): Float;
 | 
						public static var delta(get, never): Float;
 | 
				
			||||||
	static function get_delta(): Float {
 | 
						static function get_delta(): Float {
 | 
				
			||||||
		if (frequency == null) initFrequency();
 | 
							return _delta;
 | 
				
			||||||
		return (1 / frequency) * scale;
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						static var lastRenderTime = 0.0;
 | 
				
			||||||
 | 
						static var _renderDelta = 0.0;
 | 
				
			||||||
 | 
						public static var renderDelta(get, never): Float;
 | 
				
			||||||
 | 
						static function get_renderDelta(): Float {
 | 
				
			||||||
 | 
							return _renderDelta;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
	static var last = 0.0;
 | 
					 | 
				
			||||||
	public static var realDelta = 0.0;
 | 
					 | 
				
			||||||
	public static inline function time(): Float {
 | 
						public static inline function time(): Float {
 | 
				
			||||||
		return kha.Scheduler.time();
 | 
							return kha.Scheduler.time() * scale;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
	public static inline function realTime(): Float {
 | 
						public static inline function realTime(): Float {
 | 
				
			||||||
		return kha.Scheduler.realTime();
 | 
							return kha.Scheduler.realTime() * scale;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	static var frequency: Null<Int> = null;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	static function initFrequency() {
 | 
					 | 
				
			||||||
		frequency = kha.Display.primary != null ? kha.Display.primary.frequency : 60;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public static function update() {
 | 
						public static function update() {
 | 
				
			||||||
		realDelta = realTime() - last;
 | 
							_delta = realTime() - lastTime;
 | 
				
			||||||
		last = realTime();
 | 
							lastTime = realTime();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static function render() {
 | 
				
			||||||
 | 
							_renderDelta = realTime() - lastRenderTime;
 | 
				
			||||||
 | 
							lastRenderTime = realTime();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -94,34 +94,34 @@ class Tween {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
				// Way too much Reflect trickery..
 | 
									// Way too much Reflect trickery..
 | 
				
			||||||
				var ps = Reflect.fields(a.props);
 | 
									var ps = Reflect.fields(a.props);
 | 
				
			||||||
				for (i in 0...ps.length) {
 | 
									for (j in 0...ps.length) {
 | 
				
			||||||
					var p = ps[i];
 | 
										var p = ps[j];
 | 
				
			||||||
					var k = a._time / a.duration;
 | 
										var k = a._time / a.duration;
 | 
				
			||||||
					if (k > 1) k = 1;
 | 
										if (k > 1) k = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					if (a._comps[i] == 1) {
 | 
										if (a._comps[j] == 1) {
 | 
				
			||||||
						var fromVal: Float = a._x[i];
 | 
											var fromVal: Float = a._x[j];
 | 
				
			||||||
						var toVal: Float = Reflect.getProperty(a.props, p);
 | 
											var toVal: Float = Reflect.getProperty(a.props, p);
 | 
				
			||||||
						var val: Float = fromVal + (toVal - fromVal) * eases[a.ease](k);
 | 
											var val: Float = fromVal + (toVal - fromVal) * eases[a.ease](k);
 | 
				
			||||||
						Reflect.setProperty(a.target, p, val);
 | 
											Reflect.setProperty(a.target, p, val);
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
					else { // _comps[i] == 4
 | 
										else { // _comps[j] == 4
 | 
				
			||||||
						var obj = Reflect.getProperty(a.props, p);
 | 
											var obj = Reflect.getProperty(a.props, p);
 | 
				
			||||||
						var toX: Float = Reflect.getProperty(obj, "x");
 | 
											var toX: Float = Reflect.getProperty(obj, "x");
 | 
				
			||||||
						var toY: Float = Reflect.getProperty(obj, "y");
 | 
											var toY: Float = Reflect.getProperty(obj, "y");
 | 
				
			||||||
						var toZ: Float = Reflect.getProperty(obj, "z");
 | 
											var toZ: Float = Reflect.getProperty(obj, "z");
 | 
				
			||||||
						var toW: Float = Reflect.getProperty(obj, "w");
 | 
											var toW: Float = Reflect.getProperty(obj, "w");
 | 
				
			||||||
						if (a._normalize[i]) {
 | 
											if (a._normalize[j]) {
 | 
				
			||||||
							var qdot = (a._x[i] * toX) + (a._y[i] * toY) + (a._z[i] * toZ) + (a._w[i] * toW);
 | 
												var qdot = (a._x[j] * toX) + (a._y[j] * toY) + (a._z[j] * toZ) + (a._w[j] * toW);
 | 
				
			||||||
							if (qdot < 0.0) {
 | 
												if (qdot < 0.0) {
 | 
				
			||||||
								toX = -toX; toY = -toY; toZ = -toZ; toW = -toW;
 | 
													toX = -toX; toY = -toY; toZ = -toZ; toW = -toW;
 | 
				
			||||||
							}
 | 
												}
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
						var x: Float = a._x[i] + (toX - a._x[i]) * eases[a.ease](k);
 | 
											var x: Float = a._x[j] + (toX - a._x[j]) * eases[a.ease](k);
 | 
				
			||||||
						var y: Float = a._y[i] + (toY - a._y[i]) * eases[a.ease](k);
 | 
											var y: Float = a._y[j] + (toY - a._y[j]) * eases[a.ease](k);
 | 
				
			||||||
						var z: Float = a._z[i] + (toZ - a._z[i]) * eases[a.ease](k);
 | 
											var z: Float = a._z[j] + (toZ - a._z[j]) * eases[a.ease](k);
 | 
				
			||||||
						var w: Float = a._w[i] + (toW - a._w[i]) * eases[a.ease](k);
 | 
											var w: Float = a._w[j] + (toW - a._w[j]) * eases[a.ease](k);
 | 
				
			||||||
						if (a._normalize[i]) {
 | 
											if (a._normalize[j]) {
 | 
				
			||||||
							var l = Math.sqrt(x * x + y * y + z * z + w * w);
 | 
												var l = Math.sqrt(x * x + y * y + z * z + w * w);
 | 
				
			||||||
							if (l > 0.0) {
 | 
												if (l > 0.0) {
 | 
				
			||||||
								l = 1.0 / l;
 | 
													l = 1.0 / l;
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										52
									
								
								leenkx/Sources/iron/system/VR.hx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								leenkx/Sources/iron/system/VR.hx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,52 @@
 | 
				
			|||||||
 | 
					package iron.system;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import iron.math.Mat4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if lnx_vr
 | 
				
			||||||
 | 
					class VR {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static var undistortionMatrix: Mat4 = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public function new() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static function getUndistortionMatrix(): Mat4 {
 | 
				
			||||||
 | 
							if (undistortionMatrix == null) {
 | 
				
			||||||
 | 
								undistortionMatrix = Mat4.identity();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return undistortionMatrix;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static function getMaxRadiusSq(): Float {
 | 
				
			||||||
 | 
							return 0.0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static function initButton() {
 | 
				
			||||||
 | 
							function vrDownListener(index: Int, x: Float, y: Float) {
 | 
				
			||||||
 | 
								var vr = kha.vr.VrInterface.instance;
 | 
				
			||||||
 | 
								if (vr == null || !vr.IsVrEnabled() || vr.IsPresenting()) return;
 | 
				
			||||||
 | 
								var w: Float = iron.App.w();
 | 
				
			||||||
 | 
								var h: Float = iron.App.h();
 | 
				
			||||||
 | 
								if (x < w - 150 || y < h - 150) return;
 | 
				
			||||||
 | 
								vr.onVRRequestPresent();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							function vrRender2D(g: kha.graphics2.Graphics) {
 | 
				
			||||||
 | 
								var vr = kha.vr.VrInterface.instance;
 | 
				
			||||||
 | 
								if (vr == null || !vr.IsVrEnabled() || vr.IsPresenting()) return;
 | 
				
			||||||
 | 
								var w: Float = iron.App.w();
 | 
				
			||||||
 | 
								var h: Float = iron.App.h();
 | 
				
			||||||
 | 
								g.color = 0xffff0000;
 | 
				
			||||||
 | 
								g.fillRect(w - 150, h - 150, 140, 140);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							kha.input.Mouse.get().notify(vrDownListener, null, null, null);
 | 
				
			||||||
 | 
							iron.App.notifyOnRender2D(vrRender2D);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var vr = kha.vr.VrInterface.instance; // Straight to VR (Oculus Carmel)
 | 
				
			||||||
 | 
							if (vr != null && vr.IsVrEnabled()) {
 | 
				
			||||||
 | 
								vr.onVRRequestPresent();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#end
 | 
				
			||||||
@ -20,6 +20,7 @@ class Config {
 | 
				
			|||||||
		var path = iron.data.Data.dataPath + "config.lnx";
 | 
							var path = iron.data.Data.dataPath + "config.lnx";
 | 
				
			||||||
		var bytes = haxe.io.Bytes.ofString(haxe.Json.stringify(raw));
 | 
							var bytes = haxe.io.Bytes.ofString(haxe.Json.stringify(raw));
 | 
				
			||||||
		#if kha_krom
 | 
							#if kha_krom
 | 
				
			||||||
 | 
							if (iron.data.Data.dataPath == '') path = Krom.getFilesLocation() + "/config.lnx";
 | 
				
			||||||
		Krom.fileSaveBytes(path, bytes.getData());
 | 
							Krom.fileSaveBytes(path, bytes.getData());
 | 
				
			||||||
		#elseif kha_kore
 | 
							#elseif kha_kore
 | 
				
			||||||
		sys.io.File.saveBytes(path, bytes);
 | 
							sys.io.File.saveBytes(path, bytes);
 | 
				
			||||||
@ -47,6 +48,7 @@ typedef TConfig = {
 | 
				
			|||||||
	@:optional var rp_ssr: Null<Bool>;
 | 
						@:optional var rp_ssr: Null<Bool>;
 | 
				
			||||||
	@:optional var rp_ssrefr: Null<Bool>;
 | 
						@:optional var rp_ssrefr: Null<Bool>;
 | 
				
			||||||
	@:optional var rp_bloom: Null<Bool>;
 | 
						@:optional var rp_bloom: Null<Bool>;
 | 
				
			||||||
 | 
						@:optional var rp_chromatic_aberration: Null<Bool>;
 | 
				
			||||||
	@:optional var rp_motionblur: Null<Bool>;
 | 
						@:optional var rp_motionblur: Null<Bool>;
 | 
				
			||||||
	@:optional var rp_gi: Null<Bool>; // voxelao
 | 
						@:optional var rp_gi: Null<Bool>; // voxelao
 | 
				
			||||||
	@:optional var rp_dynres: Null<Bool>; // dynamic resolution scaling
 | 
						@:optional var rp_dynres: Null<Bool>; // dynamic resolution scaling
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										99
									
								
								leenkx/Sources/leenkx/logicnode/AddParticleToObjectNode.hx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								leenkx/Sources/leenkx/logicnode/AddParticleToObjectNode.hx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,99 @@
 | 
				
			|||||||
 | 
					package leenkx.logicnode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import iron.data.SceneFormat.TSceneFormat;
 | 
				
			||||||
 | 
					import iron.data.Data;
 | 
				
			||||||
 | 
					import iron.object.Object;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AddParticleToObjectNode extends LogicNode {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public var property0: String;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public function new(tree: LogicTree) {
 | 
				
			||||||
 | 
							super(tree);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						override function run(from: Int) {
 | 
				
			||||||
 | 
							#if lnx_particles
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (property0 == 'Scene Active'){		
 | 
				
			||||||
 | 
								var objFrom: Object = inputs[1].get();
 | 
				
			||||||
 | 
								var slot: Int = inputs[2].get();
 | 
				
			||||||
 | 
								var objTo: Object = inputs[3].get();
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
								if (objFrom == null || objTo == null) return;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
								var mobjFrom = cast(objFrom, iron.object.MeshObject);
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
								var psys = mobjFrom.particleSystems != null ? mobjFrom.particleSystems[slot] : 
 | 
				
			||||||
 | 
									mobjFrom.particleOwner != null && mobjFrom.particleOwner.particleSystems != null ? mobjFrom.particleOwner.particleSystems[slot] : null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (psys == null) return;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
								var mobjTo = cast(objTo, iron.object.MeshObject);
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
								mobjTo.setupParticleSystem(iron.Scene.active.raw.name, {name: 'LnxPS', seed: 0, particle: @:privateAccess psys.r.name});
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								mobjTo.render_emitter = inputs[4].get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								iron.Scene.active.spawnObject(psys.data.raw.instance_object, null, function(o: Object) {
 | 
				
			||||||
 | 
									if (o != null) {
 | 
				
			||||||
 | 
										var c: iron.object.MeshObject = cast o;
 | 
				
			||||||
 | 
										if (mobjTo.particleChildren == null) mobjTo.particleChildren = [];
 | 
				
			||||||
 | 
										mobjTo.particleChildren.push(c);
 | 
				
			||||||
 | 
										c.particleOwner = mobjTo;
 | 
				
			||||||
 | 
										c.particleIndex = mobjTo.particleChildren.length - 1;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
								var oslot: Int = mobjTo.particleSystems.length-1;
 | 
				
			||||||
 | 
								var opsys = mobjTo.particleSystems[oslot];
 | 
				
			||||||
 | 
								@:privateAccess opsys.setupGeomGpu(mobjTo.particleChildren[oslot], mobjTo);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								var sceneName: String = inputs[1].get();
 | 
				
			||||||
 | 
								var objectName: String = inputs[2].get();
 | 
				
			||||||
 | 
								var slot: Int = inputs[3].get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var mobjTo: Object = inputs[4].get();
 | 
				
			||||||
 | 
								var mobjTo = cast(mobjTo, iron.object.MeshObject);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								#if lnx_json
 | 
				
			||||||
 | 
									sceneName += ".json";
 | 
				
			||||||
 | 
								#elseif lnx_compress
 | 
				
			||||||
 | 
									sceneName += ".lz4";
 | 
				
			||||||
 | 
								#end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								Data.getSceneRaw(sceneName, (rawScene: TSceneFormat) -> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								for (obj in rawScene.objects) {
 | 
				
			||||||
 | 
									if (obj.name == objectName) {
 | 
				
			||||||
 | 
										mobjTo.setupParticleSystem(sceneName, obj.particle_refs[slot]);
 | 
				
			||||||
 | 
										mobjTo.render_emitter = inputs[5].get();					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										iron.Scene.active.spawnObject(rawScene.particle_datas[slot].instance_object, null, function(o: Object) {
 | 
				
			||||||
 | 
											if (o != null) {
 | 
				
			||||||
 | 
												var c: iron.object.MeshObject = cast o;
 | 
				
			||||||
 | 
												if (mobjTo.particleChildren == null) mobjTo.particleChildren = [];
 | 
				
			||||||
 | 
												mobjTo.particleChildren.push(c);
 | 
				
			||||||
 | 
												c.particleOwner = mobjTo;
 | 
				
			||||||
 | 
												c.particleIndex = mobjTo.particleChildren.length - 1;
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										}, true, rawScene);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										var oslot: Int = mobjTo.particleSystems.length-1;
 | 
				
			||||||
 | 
										var opsys = mobjTo.particleSystems[oslot];
 | 
				
			||||||
 | 
										@:privateAccess opsys.setupGeomGpu(mobjTo.particleChildren[oslot], mobjTo);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							#end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							runOutput(0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										48
									
								
								leenkx/Sources/leenkx/logicnode/AnyContactNode.hx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								leenkx/Sources/leenkx/logicnode/AnyContactNode.hx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,48 @@
 | 
				
			|||||||
 | 
					package leenkx.logicnode;
 | 
				
			||||||
 | 
					import iron.object.Object;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if lnx_physics
 | 
				
			||||||
 | 
					import leenkx.trait.physics.PhysicsCache;
 | 
				
			||||||
 | 
					import leenkx.trait.physics.RigidBody;
 | 
				
			||||||
 | 
					#end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AnyContactNode extends LogicNode {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public var property0: String; 
 | 
				
			||||||
 | 
						var lastContact = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public function new(tree: LogicTree) {
 | 
				
			||||||
 | 
							super(tree);
 | 
				
			||||||
 | 
							tree.notifyOnUpdate(update);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						function update() {
 | 
				
			||||||
 | 
							var object1: Object = inputs[0].get();
 | 
				
			||||||
 | 
							if (object1 == null) object1 = tree.object;
 | 
				
			||||||
 | 
							if (object1 == null) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var contact = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							#if lnx_physics
 | 
				
			||||||
 | 
							var rb1 = PhysicsCache.getCachedRigidBody(object1);
 | 
				
			||||||
 | 
							if (rb1 != null) {
 | 
				
			||||||
 | 
								var rbs = PhysicsCache.getCachedContacts(rb1);
 | 
				
			||||||
 | 
								contact = (rbs != null && rbs.length > 0);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							#end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var shouldTrigger = false;
 | 
				
			||||||
 | 
							switch (property0) {
 | 
				
			||||||
 | 
							case "begin":
 | 
				
			||||||
 | 
								shouldTrigger = contact && !lastContact;
 | 
				
			||||||
 | 
							case "overlap":
 | 
				
			||||||
 | 
								shouldTrigger = contact;
 | 
				
			||||||
 | 
							case "end":
 | 
				
			||||||
 | 
								shouldTrigger = !contact && lastContact;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							lastContact = contact;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (shouldTrigger) runOutput(0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										16
									
								
								leenkx/Sources/leenkx/logicnode/AutoExposureGetNode.hx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								leenkx/Sources/leenkx/logicnode/AutoExposureGetNode.hx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					package leenkx.logicnode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AutoExposureGetNode extends LogicNode {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public function new(tree:LogicTree) {
 | 
				
			||||||
 | 
							super(tree);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						override function get(from:Int):Dynamic {
 | 
				
			||||||
 | 
							return switch (from) {
 | 
				
			||||||
 | 
								case 0: leenkx.renderpath.Postprocess.auto_exposure_uniforms[0];
 | 
				
			||||||
 | 
								case 1: leenkx.renderpath.Postprocess.auto_exposure_uniforms[1];
 | 
				
			||||||
 | 
								default: 0.0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										15
									
								
								leenkx/Sources/leenkx/logicnode/AutoExposureSetNode.hx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								leenkx/Sources/leenkx/logicnode/AutoExposureSetNode.hx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,15 @@
 | 
				
			|||||||
 | 
					package leenkx.logicnode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AutoExposureSetNode extends LogicNode {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public function new(tree:LogicTree) {
 | 
				
			||||||
 | 
							super(tree);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						override function run(from:Int) {
 | 
				
			||||||
 | 
					        leenkx.renderpath.Postprocess.auto_exposure_uniforms[0] = inputs[1].get();
 | 
				
			||||||
 | 
					        leenkx.renderpath.Postprocess.auto_exposure_uniforms[1] = inputs[2].get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							runOutput(0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -2,25 +2,48 @@ package leenkx.logicnode;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
class CameraSetNode extends LogicNode {
 | 
					class CameraSetNode extends LogicNode {
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
 | 
						public var property0: String;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
	public function new(tree:LogicTree) {
 | 
						public function new(tree:LogicTree) {
 | 
				
			||||||
		super(tree);
 | 
							super(tree);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	override function run(from:Int) {
 | 
						override function run(from:Int) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							switch (property0) {
 | 
				
			||||||
 | 
								case 'F-stop':
 | 
				
			||||||
				leenkx.renderpath.Postprocess.camera_uniforms[0] = inputs[1].get();//Camera: F-Number
 | 
									leenkx.renderpath.Postprocess.camera_uniforms[0] = inputs[1].get();//Camera: F-Number
 | 
				
			||||||
		leenkx.renderpath.Postprocess.camera_uniforms[1] = inputs[2].get();//Camera: Shutter time
 | 
								case 'Shutter Time':	
 | 
				
			||||||
		leenkx.renderpath.Postprocess.camera_uniforms[2] = inputs[3].get();//Camera: ISO
 | 
									leenkx.renderpath.Postprocess.camera_uniforms[1] = inputs[1].get();//Camera: Shutter time
 | 
				
			||||||
		leenkx.renderpath.Postprocess.camera_uniforms[3] = inputs[4].get();//Camera: Exposure Compensation
 | 
								case 'ISO':
 | 
				
			||||||
		leenkx.renderpath.Postprocess.camera_uniforms[4] = inputs[5].get();//Fisheye Distortion
 | 
									leenkx.renderpath.Postprocess.camera_uniforms[2] = inputs[1].get();//Camera: ISO
 | 
				
			||||||
		leenkx.renderpath.Postprocess.camera_uniforms[5] = inputs[6].get();//DoF AutoFocus §§ If true, it ignores the DoF Distance setting
 | 
								case 'Exposure Compensation':
 | 
				
			||||||
		leenkx.renderpath.Postprocess.camera_uniforms[6] = inputs[7].get();//DoF Distance
 | 
									leenkx.renderpath.Postprocess.camera_uniforms[3] = inputs[1].get();//Camera: Exposure Compensation
 | 
				
			||||||
		leenkx.renderpath.Postprocess.camera_uniforms[7] = inputs[8].get();//DoF Focal Length mm
 | 
								case 'Fisheye Distortion':
 | 
				
			||||||
		leenkx.renderpath.Postprocess.camera_uniforms[8] = inputs[9].get();//DoF F-Stop
 | 
									leenkx.renderpath.Postprocess.camera_uniforms[4] = inputs[1].get();//Fisheye Distortion
 | 
				
			||||||
		leenkx.renderpath.Postprocess.camera_uniforms[9] = inputs[10].get();//Tonemapping Method
 | 
								case 'Auto Focus':
 | 
				
			||||||
		leenkx.renderpath.Postprocess.camera_uniforms[10] = inputs[11].get();//Distort
 | 
									leenkx.renderpath.Postprocess.camera_uniforms[5] = inputs[1].get();//DoF AutoFocus §§ If true, it ignores the DoF Distance setting
 | 
				
			||||||
		leenkx.renderpath.Postprocess.camera_uniforms[11] = inputs[12].get();//Film Grain
 | 
								case 'DoF Distance':
 | 
				
			||||||
		leenkx.renderpath.Postprocess.camera_uniforms[12] = inputs[13].get();//Sharpen
 | 
									leenkx.renderpath.Postprocess.camera_uniforms[6] = inputs[1].get();//DoF Distance
 | 
				
			||||||
		leenkx.renderpath.Postprocess.camera_uniforms[13] = inputs[14].get();//Vignette
 | 
								case 'DoF Length':
 | 
				
			||||||
 | 
									leenkx.renderpath.Postprocess.camera_uniforms[7] = inputs[1].get();//DoF Focal Length mm
 | 
				
			||||||
 | 
								case 'DoF F-Stop':
 | 
				
			||||||
 | 
									leenkx.renderpath.Postprocess.camera_uniforms[8] = inputs[1].get();//DoF F-Stop
 | 
				
			||||||
 | 
								case 'Tonemapping':
 | 
				
			||||||
 | 
									leenkx.renderpath.Postprocess.camera_uniforms[9] = inputs[1].get();//Tonemapping Method
 | 
				
			||||||
 | 
								case 'Distort':
 | 
				
			||||||
 | 
									leenkx.renderpath.Postprocess.camera_uniforms[10] = inputs[1].get();//Distort
 | 
				
			||||||
 | 
								case 'Film Grain':
 | 
				
			||||||
 | 
									leenkx.renderpath.Postprocess.camera_uniforms[11] = inputs[1].get();//Film Grain
 | 
				
			||||||
 | 
								case 'Sharpen':
 | 
				
			||||||
 | 
									leenkx.renderpath.Postprocess.camera_uniforms[12] = inputs[1].get();//Sharpen
 | 
				
			||||||
 | 
								case 'Vignette':
 | 
				
			||||||
 | 
									leenkx.renderpath.Postprocess.camera_uniforms[13] = inputs[1].get();//Vignette
 | 
				
			||||||
 | 
								case 'Exposure':
 | 
				
			||||||
 | 
									leenkx.renderpath.Postprocess.exposure_uniforms[0] = inputs[1].get();//Exposure
 | 
				
			||||||
 | 
								default: 
 | 
				
			||||||
 | 
									null;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		runOutput(0);
 | 
							runOutput(0);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
				
			|||||||
@ -10,6 +10,7 @@ class ChromaticAberrationGetNode extends LogicNode {
 | 
				
			|||||||
		return switch (from) {
 | 
							return switch (from) {
 | 
				
			||||||
			case 0: leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[0];
 | 
								case 0: leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[0];
 | 
				
			||||||
			case 1: leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[1];
 | 
								case 1: leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[1];
 | 
				
			||||||
 | 
								case 2: leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[2];
 | 
				
			||||||
			default: 0.0;
 | 
								default: 0.0;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
				
			|||||||
@ -10,6 +10,7 @@ class ChromaticAberrationSetNode extends LogicNode {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[0] = inputs[1].get();
 | 
					        leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[0] = inputs[1].get();
 | 
				
			||||||
        leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[1] = inputs[2].get();
 | 
					        leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[1] = inputs[2].get();
 | 
				
			||||||
 | 
							leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[2] = inputs[3].get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		runOutput(0);
 | 
							runOutput(0);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
				
			|||||||
@ -2,6 +2,9 @@ package leenkx.logicnode;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import iron.Scene;
 | 
					import iron.Scene;
 | 
				
			||||||
import iron.object.CameraObject;
 | 
					import iron.object.CameraObject;
 | 
				
			||||||
 | 
					import iron.math.Vec4;
 | 
				
			||||||
 | 
					import iron.math.Quat;
 | 
				
			||||||
 | 
					import leenkx.math.Helper;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import leenkx.renderpath.RenderPathCreator;
 | 
					import leenkx.renderpath.RenderPathCreator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -27,11 +30,19 @@ class DrawCameraTextureNode extends LogicNode {
 | 
				
			|||||||
				final c = inputs[2].get();
 | 
									final c = inputs[2].get();
 | 
				
			||||||
				assert(Error, Std.isOfType(c, CameraObject), "Camera must be a camera object!");
 | 
									assert(Error, Std.isOfType(c, CameraObject), "Camera must be a camera object!");
 | 
				
			||||||
				cam = cast(c, CameraObject);
 | 
									cam = cast(c, CameraObject);
 | 
				
			||||||
				rt = kha.Image.createRenderTarget(iron.App.w(), iron.App.h());
 | 
									rt = kha.Image.createRenderTarget(iron.App.w(), iron.App.h(),
 | 
				
			||||||
 | 
										kha.graphics4.TextureFormat.RGBA32,
 | 
				
			||||||
 | 
										kha.graphics4.DepthStencilFormat.NoDepthAndStencil);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				assert(Error, mo.materials[matSlot].contexts[0].textures != null, 'Object "${mo.name}" has no diffuse texture to render to');
 | 
									assert(Error, mo.materials[matSlot].contexts[0].textures != null, 'Object "${mo.name}" has no diffuse texture to render to');
 | 
				
			||||||
				mo.materials[matSlot].contexts[0].textures[0] = rt; // Override diffuse texture
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                final n = inputs[5].get();
 | 
				
			||||||
 | 
									for (i => node in mo.materials[matSlot].contexts[0].raw.bind_textures){
 | 
				
			||||||
 | 
										if (node.name == n){
 | 
				
			||||||
 | 
											mo.materials[matSlot].contexts[0].textures[i] = rt; // Override diffuse texture
 | 
				
			||||||
 | 
											break;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
				tree.notifyOnRender(render);
 | 
									tree.notifyOnRender(render);
 | 
				
			||||||
				runOutput(0);
 | 
									runOutput(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -48,8 +59,20 @@ class DrawCameraTextureNode extends LogicNode {
 | 
				
			|||||||
		iron.Scene.active.camera = cam;
 | 
							iron.Scene.active.camera = cam;
 | 
				
			||||||
		cam.renderTarget = rt;
 | 
							cam.renderTarget = rt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							#if kha_html5
 | 
				
			||||||
 | 
							var q: Quat = new Quat();
 | 
				
			||||||
 | 
							q.fromAxisAngle(new Vec4(0, 0, 1, 1), Helper.degToRad(180));
 | 
				
			||||||
 | 
							cam.transform.rot.mult(q);
 | 
				
			||||||
 | 
							cam.transform.buildMatrix();
 | 
				
			||||||
 | 
							#end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		cam.renderFrame(g);
 | 
							cam.renderFrame(g);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							#if kha_html5
 | 
				
			||||||
 | 
							cam.transform.rot.mult(q);
 | 
				
			||||||
 | 
							cam.transform.buildMatrix();
 | 
				
			||||||
 | 
							#end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		cam.renderTarget = oldRT;
 | 
							cam.renderTarget = oldRT;
 | 
				
			||||||
		iron.Scene.active.camera = sceneCam;
 | 
							iron.Scene.active.camera = sceneCam;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
				
			|||||||
@ -99,8 +99,6 @@ class DrawImageSequenceNode extends LogicNode {
 | 
				
			|||||||
		final colorVec = inputs[4].get();
 | 
							final colorVec = inputs[4].get();
 | 
				
			||||||
		g.color = Color.fromFloats(colorVec.x, colorVec.y, colorVec.z, colorVec.w);
 | 
							g.color = Color.fromFloats(colorVec.x, colorVec.y, colorVec.z, colorVec.w);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		trace(currentImgIdx);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		g.drawScaledImage(images[currentImgIdx], inputs[5].get(), inputs[6].get(), inputs[7].get(), inputs[8].get());
 | 
							g.drawScaledImage(images[currentImgIdx], inputs[5].get(), inputs[6].get(), inputs[7].get(), inputs[8].get());
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -62,7 +62,7 @@ class DrawStringNode extends LogicNode {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	override function get(from: Int): Dynamic {
 | 
						override function get(from: Int): Dynamic {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return from == 1 ? RenderToTexture.g.font.height(RenderToTexture.g.fontSize) : RenderToTexture.g.font.width(RenderToTexture.g.fontSize, string);
 | 
							return from == 1 ? RenderToTexture.g.font.width(RenderToTexture.g.fontSize, string) : RenderToTexture.g.font.height(RenderToTexture.g.fontSize);
 | 
				
			||||||
			
 | 
								
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										59
									
								
								leenkx/Sources/leenkx/logicnode/DrawSubImageNode.hx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								leenkx/Sources/leenkx/logicnode/DrawSubImageNode.hx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,59 @@
 | 
				
			|||||||
 | 
					package leenkx.logicnode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import iron.math.Vec4;
 | 
				
			||||||
 | 
					import kha.Image;
 | 
				
			||||||
 | 
					import kha.Color;
 | 
				
			||||||
 | 
					import leenkx.renderpath.RenderToTexture;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DrawSubImageNode extends LogicNode {
 | 
				
			||||||
 | 
					    var img: Image;
 | 
				
			||||||
 | 
					    var lastImgName = "";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function new(tree: LogicTree) {
 | 
				
			||||||
 | 
					        super(tree);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override function run(from: Int) {
 | 
				
			||||||
 | 
					        RenderToTexture.ensure2DContext("DrawImageNode");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        final imgName: String = inputs[1].get();
 | 
				
			||||||
 | 
					        final colorVec: Vec4 = inputs[2].get();
 | 
				
			||||||
 | 
					        final anchorH: Int = inputs[3].get();
 | 
				
			||||||
 | 
					        final anchorV: Int = inputs[4].get();
 | 
				
			||||||
 | 
					        final x: Float = inputs[5].get();
 | 
				
			||||||
 | 
					        final y: Float = inputs[6].get();
 | 
				
			||||||
 | 
					        final width: Float = inputs[7].get();
 | 
				
			||||||
 | 
					        final height: Float = inputs[8].get();
 | 
				
			||||||
 | 
					        final sx: Float = inputs[9].get();
 | 
				
			||||||
 | 
					        final sy: Float = inputs[10].get();
 | 
				
			||||||
 | 
					        final swidth: Float = inputs[11].get();
 | 
				
			||||||
 | 
					        final sheight: Float = inputs[12].get();
 | 
				
			||||||
 | 
					        final angle: Float = inputs[13].get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        final drawx = x - 0.5 * width * anchorH;
 | 
				
			||||||
 | 
					        final drawy = y - 0.5 * height * anchorV;
 | 
				
			||||||
 | 
					        final sdrawx = sx - 0.5 * swidth * anchorH;
 | 
				
			||||||
 | 
					        final sdrawy = sy - 0.5 * sheight * anchorV;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        RenderToTexture.g.rotate(angle, x, y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (imgName != lastImgName) {
 | 
				
			||||||
 | 
					            // Load new image
 | 
				
			||||||
 | 
					            lastImgName = imgName;
 | 
				
			||||||
 | 
					            iron.data.Data.getImage(imgName, (image: Image) -> {
 | 
				
			||||||
 | 
					                img = image;
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (img == null) {
 | 
				
			||||||
 | 
					            runOutput(0);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        RenderToTexture.g.color = Color.fromFloats(colorVec.x, colorVec.y, colorVec.z, colorVec.w);
 | 
				
			||||||
 | 
					        RenderToTexture.g.drawScaledSubImage(img, sdrawx, sdrawy, swidth, sheight, drawx, drawy, width, height);
 | 
				
			||||||
 | 
					        RenderToTexture.g.rotate(-angle, x, y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        runOutput(0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										17
									
								
								leenkx/Sources/leenkx/logicnode/GetAudioPositionNode.hx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								leenkx/Sources/leenkx/logicnode/GetAudioPositionNode.hx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					package leenkx.logicnode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import aura.Aura;
 | 
				
			||||||
 | 
					import aura.Types;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class GetAudioPositionNode extends LogicNode {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public function new(tree: LogicTree) {
 | 
				
			||||||
 | 
							super(tree);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						override function get(from: Int): Dynamic {
 | 
				
			||||||
 | 
							var audio = inputs[0].get();
 | 
				
			||||||
 | 
							if (audio == null || audio.channel == null) return 0.0;
 | 
				
			||||||
 | 
							return audio.channel.floatPosition / audio.channel.sampleRate;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										19
									
								
								leenkx/Sources/leenkx/logicnode/GetCameraRenderFilterNode.hx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								leenkx/Sources/leenkx/logicnode/GetCameraRenderFilterNode.hx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					package leenkx.logicnode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import iron.object.MeshObject;
 | 
				
			||||||
 | 
					import iron.object.CameraObject;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class GetCameraRenderFilterNode extends LogicNode {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public function new(tree: LogicTree) {
 | 
				
			||||||
 | 
							super(tree);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						override function get(from: Int): Dynamic {
 | 
				
			||||||
 | 
							var mo: MeshObject = cast inputs[0].get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (mo == null) return null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return mo.cameraList;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -8,7 +8,7 @@ class GetFPSNode extends LogicNode {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    override function get(from: Int): Dynamic {
 | 
					    override function get(from: Int): Dynamic {
 | 
				
			||||||
        if (from == 0) {
 | 
					        if (from == 0) {
 | 
				
			||||||
            var fps = Math.round(1 / iron.system.Time.realDelta);
 | 
					            var fps = Math.round(1 / iron.system.Time.renderDelta);
 | 
				
			||||||
            if ((fps == Math.POSITIVE_INFINITY) || (fps == Math.NEGATIVE_INFINITY) || (Math.isNaN(fps))) {
 | 
					            if ((fps == Math.POSITIVE_INFINITY) || (fps == Math.NEGATIVE_INFINITY) || (Math.isNaN(fps))) {
 | 
				
			||||||
                return 0;
 | 
					                return 0;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										72
									
								
								leenkx/Sources/leenkx/logicnode/GetParticleDataNode.hx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								leenkx/Sources/leenkx/logicnode/GetParticleDataNode.hx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,72 @@
 | 
				
			|||||||
 | 
					package leenkx.logicnode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import iron.object.Object;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class GetParticleDataNode extends LogicNode {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public function new(tree: LogicTree) {
 | 
				
			||||||
 | 
							super(tree);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						override function get(from: Int): Dynamic {
 | 
				
			||||||
 | 
							var object: Object = inputs[0].get();
 | 
				
			||||||
 | 
							var slot: Int = inputs[1].get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (object == null) return null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#if lnx_particles
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var mo = cast(object, iron.object.MeshObject);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var psys = mo.particleSystems != null ? mo.particleSystems[slot] : 
 | 
				
			||||||
 | 
								mo.particleOwner != null && mo.particleOwner.particleSystems != null ? mo.particleOwner.particleSystems[slot] : null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (psys == null) return null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return switch (from) {
 | 
				
			||||||
 | 
								case 0:
 | 
				
			||||||
 | 
									@:privateAccess psys.r.name;
 | 
				
			||||||
 | 
								case 1:
 | 
				
			||||||
 | 
									@:privateAccess psys.r.particle_size;
 | 
				
			||||||
 | 
								case 2:
 | 
				
			||||||
 | 
									@:privateAccess psys.r.frame_start;
 | 
				
			||||||
 | 
								case 3:
 | 
				
			||||||
 | 
									@:privateAccess psys.r.frame_end;
 | 
				
			||||||
 | 
								case 4:
 | 
				
			||||||
 | 
									@:privateAccess psys.lifetime;
 | 
				
			||||||
 | 
								case 5:
 | 
				
			||||||
 | 
									@:privateAccess psys.r.lifetime;
 | 
				
			||||||
 | 
								case 6:
 | 
				
			||||||
 | 
									@:privateAccess psys.r.emit_from;
 | 
				
			||||||
 | 
								case 7:
 | 
				
			||||||
 | 
									@:privateAccess psys.r.auto_start;
 | 
				
			||||||
 | 
								case 8:
 | 
				
			||||||
 | 
									@:privateAccess psys.r.is_unique;
 | 
				
			||||||
 | 
								case 9:
 | 
				
			||||||
 | 
									@:privateAccess psys.r.loop;
 | 
				
			||||||
 | 
								case 10:
 | 
				
			||||||
 | 
									new iron.math.Vec3(@:privateAccess psys.alignx, @:privateAccess psys.aligny, @:privateAccess psys.alignz);
 | 
				
			||||||
 | 
								case 11:
 | 
				
			||||||
 | 
									@:privateAccess psys.r.factor_random;
 | 
				
			||||||
 | 
								case 12:
 | 
				
			||||||
 | 
									new iron.math.Vec3(@:privateAccess psys.gx, @:privateAccess psys.gy, @:privateAccess psys.gz);
 | 
				
			||||||
 | 
								case 13:
 | 
				
			||||||
 | 
									@:privateAccess psys.r.weight_gravity;
 | 
				
			||||||
 | 
								case 14:
 | 
				
			||||||
 | 
									psys.speed;
 | 
				
			||||||
 | 
								case 15:
 | 
				
			||||||
 | 
									@:privateAccess psys.time;
 | 
				
			||||||
 | 
								case 16:
 | 
				
			||||||
 | 
									@:privateAccess psys.lap;
 | 
				
			||||||
 | 
								case 17:
 | 
				
			||||||
 | 
									@:privateAccess psys.lapTime;
 | 
				
			||||||
 | 
								case 18:
 | 
				
			||||||
 | 
									@:privateAccess psys.count;
 | 
				
			||||||
 | 
								default: 
 | 
				
			||||||
 | 
									null;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						#end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return null;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										38
									
								
								leenkx/Sources/leenkx/logicnode/GetParticleNode.hx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								leenkx/Sources/leenkx/logicnode/GetParticleNode.hx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,38 @@
 | 
				
			|||||||
 | 
					package leenkx.logicnode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import iron.object.Object;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class GetParticleNode extends LogicNode {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public function new(tree: LogicTree) {
 | 
				
			||||||
 | 
							super(tree);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						override function get(from: Int): Dynamic {
 | 
				
			||||||
 | 
							var object: Object = inputs[0].get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (object == null) return null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#if lnx_particles
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var mo = cast(object, iron.object.MeshObject);
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
							switch (from) {
 | 
				
			||||||
 | 
								case 0:
 | 
				
			||||||
 | 
									var names: Array<String> = [];
 | 
				
			||||||
 | 
									if (mo.particleSystems != null)
 | 
				
			||||||
 | 
										for (psys in mo.particleSystems)
 | 
				
			||||||
 | 
											names.push(@:privateAccess psys.r.name);
 | 
				
			||||||
 | 
									return names;
 | 
				
			||||||
 | 
								case 1:
 | 
				
			||||||
 | 
									return mo.particleSystems != null ? mo.particleSystems.length : 0;
 | 
				
			||||||
 | 
								case 2:
 | 
				
			||||||
 | 
									return mo.render_emitter;
 | 
				
			||||||
 | 
								default: 
 | 
				
			||||||
 | 
									null;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						#end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return null;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										33
									
								
								leenkx/Sources/leenkx/logicnode/GetPositionSpeakerNode.hx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								leenkx/Sources/leenkx/logicnode/GetPositionSpeakerNode.hx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,33 @@
 | 
				
			|||||||
 | 
					package leenkx.logicnode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if lnx_audio
 | 
				
			||||||
 | 
					import iron.object.SpeakerObject;
 | 
				
			||||||
 | 
					import kha.audio1.AudioChannel;
 | 
				
			||||||
 | 
					#end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class GetPositionSpeakerNode extends LogicNode {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public function new(tree: LogicTree) {
 | 
				
			||||||
 | 
							super(tree);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						override function get(from: Int): Dynamic {
 | 
				
			||||||
 | 
							#if lnx_audio
 | 
				
			||||||
 | 
							var object: SpeakerObject = cast(inputs[0].get(), SpeakerObject);
 | 
				
			||||||
 | 
							if (object == null || object.sound == null) return 0.0;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							if (object.channels.length == 0) return 0.0;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							var channel = object.channels[0];
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							var position = 0.0;
 | 
				
			||||||
 | 
							if (channel != null) {
 | 
				
			||||||
 | 
								position = @:privateAccess channel.get_position();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							return position;
 | 
				
			||||||
 | 
							#else
 | 
				
			||||||
 | 
							return 0.0;
 | 
				
			||||||
 | 
							#end
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,26 +1,12 @@
 | 
				
			|||||||
package leenkx.logicnode;
 | 
					package leenkx.logicnode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import iron.object.Object;
 | 
					 | 
				
			||||||
import iron.math.Vec4;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class GetWorldNode extends LogicNode {
 | 
					class GetWorldNode extends LogicNode {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public var property0: String;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public function new(tree: LogicTree) {
 | 
						public function new(tree: LogicTree) {
 | 
				
			||||||
		super(tree);
 | 
							super(tree);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	override function get(from: Int): Dynamic {
 | 
						override function get(from: Int): Dynamic {
 | 
				
			||||||
		var object: Object = inputs[0].get();
 | 
							return iron.Scene.active.raw.world_ref;
 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (object == null) return null;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return switch (property0) {
 | 
					 | 
				
			||||||
			case "Right": object.transform.world.right();
 | 
					 | 
				
			||||||
			case "Look": object.transform.world.look();
 | 
					 | 
				
			||||||
			case "Up": object.transform.world.up();
 | 
					 | 
				
			||||||
			default: null;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										26
									
								
								leenkx/Sources/leenkx/logicnode/GetWorldOrientationNode.hx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								leenkx/Sources/leenkx/logicnode/GetWorldOrientationNode.hx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					package leenkx.logicnode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import iron.object.Object;
 | 
				
			||||||
 | 
					import iron.math.Vec4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class GetWorldOrientationNode extends LogicNode {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public var property0: String;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public function new(tree: LogicTree) {
 | 
				
			||||||
 | 
							super(tree);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						override function get(from: Int): Dynamic {
 | 
				
			||||||
 | 
							var object: Object = inputs[0].get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (object == null) return null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return switch (property0) {
 | 
				
			||||||
 | 
								case "Right": object.transform.world.right();
 | 
				
			||||||
 | 
								case "Look": object.transform.world.look();
 | 
				
			||||||
 | 
								case "Up": object.transform.world.up();
 | 
				
			||||||
 | 
								default: null;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,7 +1,10 @@
 | 
				
			|||||||
package leenkx.logicnode;
 | 
					package leenkx.logicnode;
 | 
				
			||||||
 | 
					 | 
				
			||||||
import iron.object.Object;
 | 
					import iron.object.Object;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if lnx_physics
 | 
				
			||||||
 | 
					import leenkx.trait.physics.PhysicsCache;
 | 
				
			||||||
import leenkx.trait.physics.RigidBody;
 | 
					import leenkx.trait.physics.RigidBody;
 | 
				
			||||||
 | 
					#end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class HasContactNode extends LogicNode {
 | 
					class HasContactNode extends LogicNode {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -15,12 +18,15 @@ class HasContactNode extends LogicNode {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		if (object1 == null || object2 == null) return false;
 | 
							if (object1 == null || object2 == null) return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if lnx_physics
 | 
							#if lnx_physics
 | 
				
			||||||
		var physics = leenkx.trait.physics.PhysicsWorld.active;
 | 
							var rb1 = PhysicsCache.getCachedRigidBody(object1);
 | 
				
			||||||
		var rb2 = object2.getTrait(RigidBody);
 | 
							var rb2 = PhysicsCache.getCachedRigidBody(object2);
 | 
				
			||||||
		var rbs = physics.getContacts(object1.getTrait(RigidBody));
 | 
							
 | 
				
			||||||
		if (rbs != null) for (rb in rbs) if (rb == rb2) return true;
 | 
							if (rb1 != null && rb2 != null) {
 | 
				
			||||||
#end
 | 
								var rbs = PhysicsCache.getCachedContacts(rb1);
 | 
				
			||||||
 | 
								return PhysicsCache.hasContactWith(rbs, rb2);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							#end
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										233
									
								
								leenkx/Sources/leenkx/logicnode/MouseLookNode.hx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										233
									
								
								leenkx/Sources/leenkx/logicnode/MouseLookNode.hx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,233 @@
 | 
				
			|||||||
 | 
					package leenkx.logicnode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import iron.math.Vec4;
 | 
				
			||||||
 | 
					import iron.system.Input;
 | 
				
			||||||
 | 
					import iron.object.Object;
 | 
				
			||||||
 | 
					import kha.System;
 | 
				
			||||||
 | 
					import kha.FastFloat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * MouseLookNode - FPS-style mouse look camera controller
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * This node provides smooth, resolution-independent mouse look functionality for 
 | 
				
			||||||
 | 
					 * first-person perspective controls. It supports separate body and head objects,
 | 
				
			||||||
 | 
					 * allowing for realistic FPS camera movement where the body rotates horizontally
 | 
				
			||||||
 | 
					 * and the head/camera rotates vertically.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * Key Features:
 | 
				
			||||||
 | 
					 * - Resolution-adaptive scaling for consistent feel across different screen sizes
 | 
				
			||||||
 | 
					 * - Configurable axis orientations (X, Y, Z as front)
 | 
				
			||||||
 | 
					 * - Optional mouse cursor locking and hiding
 | 
				
			||||||
 | 
					 * - Invertible X/Y axes
 | 
				
			||||||
 | 
					 * - Rotation capping/limiting for both horizontal and vertical movement
 | 
				
			||||||
 | 
					 * - Smoothing support for smoother camera movement
 | 
				
			||||||
 | 
					 * - Physics integration with automatic rigid body synchronization
 | 
				
			||||||
 | 
					 * - Support for both local and world space head rotation
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					class MouseLookNode extends LogicNode {
 | 
				
			||||||
 | 
						// Configuration properties (set from Blender node interface)
 | 
				
			||||||
 | 
						public var property0: String;  // Front axis: "X", "Y", or "Z"
 | 
				
			||||||
 | 
						public var property1: Bool;    // Hide Locked: auto-lock mouse cursor
 | 
				
			||||||
 | 
						public var property2: Bool;    // Invert X: invert horizontal mouse movement
 | 
				
			||||||
 | 
						public var property3: Bool;    // Invert Y: invert vertical mouse movement
 | 
				
			||||||
 | 
						public var property4: Bool;    // Cap Left/Right: limit horizontal rotation
 | 
				
			||||||
 | 
						public var property5: Bool;    // Cap Up/Down: limit vertical rotation
 | 
				
			||||||
 | 
						public var property6: Bool;    // Head Local Space: use local space for head rotation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Smoothing state variables - maintain previous frame values for interpolation
 | 
				
			||||||
 | 
						var smoothX: Float = 0.0;      // Smoothed horizontal mouse delta
 | 
				
			||||||
 | 
						var smoothY: Float = 0.0;      // Smoothed vertical mouse delta
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						// Rotation limits (in radians)
 | 
				
			||||||
 | 
						var maxHorizontal: Float = Math.PI;      // Maximum horizontal rotation (180 degrees)
 | 
				
			||||||
 | 
						var maxVertical: Float = Math.PI / 2;    // Maximum vertical rotation (90 degrees)
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						// Current rotation tracking for capping calculations
 | 
				
			||||||
 | 
						var currentHorizontal: Float = 0.0;      // Accumulated horizontal rotation
 | 
				
			||||||
 | 
						var currentVertical: Float = 0.0;        // Accumulated vertical rotation
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						// Resolution scaling reference - base resolution for consistent sensitivity
 | 
				
			||||||
 | 
						var baseResolutionWidth: Float = 1920.0;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						// Sensitivity scaling constants
 | 
				
			||||||
 | 
						static inline var BASE_SCALE: Float = 1500.0;              // Base sensitivity scale factor
 | 
				
			||||||
 | 
						static var RADIAN_SCALING_FACTOR: Float = Math.PI * 50.0 / 180.0;  // Degrees to radians conversion with sensitivity scaling
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public function new(tree: LogicTree) {
 | 
				
			||||||
 | 
							super(tree);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Main execution function called every frame when the node is active
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * Input connections:
 | 
				
			||||||
 | 
						 * [0] - Action trigger (not used in current implementation)
 | 
				
			||||||
 | 
						 * [1] - Body Object: the main object that rotates horizontally
 | 
				
			||||||
 | 
						 * [2] - Head Object: optional object that rotates vertically (typically camera)
 | 
				
			||||||
 | 
						 * [3] - Sensitivity: mouse sensitivity multiplier
 | 
				
			||||||
 | 
						 * [4] - Smoothing: movement smoothing factor (0.0 = no smoothing, 0.99 = maximum smoothing)
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						override function run(from: Int) {
 | 
				
			||||||
 | 
							// Get input values from connected nodes
 | 
				
			||||||
 | 
							var bodyObject: Object = inputs[1].get();
 | 
				
			||||||
 | 
							var headObject: Object = inputs[2].get();
 | 
				
			||||||
 | 
							var sensitivity: FastFloat = inputs[3].get();
 | 
				
			||||||
 | 
							var smoothing: FastFloat = inputs[4].get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Early exit if no body object is provided
 | 
				
			||||||
 | 
							if (bodyObject == null) {
 | 
				
			||||||
 | 
								runOutput(0);
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Get mouse input state
 | 
				
			||||||
 | 
							var mouse = Input.getMouse();
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							// Handle automatic mouse cursor locking for FPS controls
 | 
				
			||||||
 | 
							if (property1) {
 | 
				
			||||||
 | 
								if (mouse.started() && !mouse.locked) {
 | 
				
			||||||
 | 
									mouse.lock();  // Center and hide cursor, enable unlimited movement
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Only process mouse look when cursor is locked or mouse button is held
 | 
				
			||||||
 | 
							// This prevents unwanted camera movement when UI elements are being used
 | 
				
			||||||
 | 
							if (!mouse.locked && !mouse.down()) {
 | 
				
			||||||
 | 
								runOutput(0);
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Get raw mouse movement delta (pixels moved since last frame)
 | 
				
			||||||
 | 
							var deltaX: Float = mouse.movementX;
 | 
				
			||||||
 | 
							var deltaY: Float = mouse.movementY;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Apply axis inversion if configured
 | 
				
			||||||
 | 
							if (property2) deltaX = -deltaX;  // Invert horizontal movement
 | 
				
			||||||
 | 
							if (property3) deltaY = -deltaY;  // Invert vertical movement
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Calculate resolution-adaptive scaling to maintain consistent sensitivity
 | 
				
			||||||
 | 
							// across different screen resolutions. Higher resolutions will have proportionally
 | 
				
			||||||
 | 
							// higher scaling to compensate for increased pixel density.
 | 
				
			||||||
 | 
							var resolutionMultiplier: Float = System.windowWidth() / baseResolutionWidth;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Apply movement smoothing if enabled
 | 
				
			||||||
 | 
							// This creates a weighted average between current and previous movement values
 | 
				
			||||||
 | 
							// to reduce jittery camera movement, especially useful for low framerates
 | 
				
			||||||
 | 
							if (smoothing > 0.0) {
 | 
				
			||||||
 | 
								var smoothingFactor: Float = Math.min(smoothing, 0.99);  // Cap smoothing to prevent complete freeze
 | 
				
			||||||
 | 
								smoothX = smoothX * smoothingFactor + deltaX * (1.0 - smoothingFactor);
 | 
				
			||||||
 | 
								smoothY = smoothY * smoothingFactor + deltaY * (1.0 - smoothingFactor);
 | 
				
			||||||
 | 
								deltaX = smoothX;
 | 
				
			||||||
 | 
								deltaY = smoothY;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Define rotation axes based on the configured front axis
 | 
				
			||||||
 | 
							// These determine which 3D axes are used for horizontal and vertical rotation
 | 
				
			||||||
 | 
							var horizontalAxis = new Vec4();  // Axis for left/right body rotation
 | 
				
			||||||
 | 
							var verticalAxis = new Vec4();    // Axis for up/down head rotation
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							switch (property0) {
 | 
				
			||||||
 | 
								case "X":  // X-axis forward (e.g., for side-scrolling or specific orientations)
 | 
				
			||||||
 | 
									horizontalAxis.set(0, 0, 1);  // Z-axis for horizontal rotation
 | 
				
			||||||
 | 
									verticalAxis.set(0, 1, 0);    // Y-axis for vertical rotation
 | 
				
			||||||
 | 
								case "Y":  // Y-axis forward (most common for 3D games)
 | 
				
			||||||
 | 
									#if lnx_yaxisup
 | 
				
			||||||
 | 
									// Y-up coordinate system (Blender default)
 | 
				
			||||||
 | 
									horizontalAxis.set(0, 0, 1);  // Z-axis for horizontal rotation
 | 
				
			||||||
 | 
									verticalAxis.set(1, 0, 0);    // X-axis for vertical rotation
 | 
				
			||||||
 | 
									#else
 | 
				
			||||||
 | 
									// Z-up coordinate system
 | 
				
			||||||
 | 
									horizontalAxis.set(0, 0, 1);  // Z-axis for horizontal rotation
 | 
				
			||||||
 | 
									verticalAxis.set(1, 0, 0);    // X-axis for vertical rotation
 | 
				
			||||||
 | 
									#end
 | 
				
			||||||
 | 
								case "Z":  // Z-axis forward (top-down or specific orientations)
 | 
				
			||||||
 | 
									horizontalAxis.set(0, 1, 0);  // Y-axis for horizontal rotation
 | 
				
			||||||
 | 
									verticalAxis.set(1, 0, 0);    // X-axis for vertical rotation
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Calculate final sensitivity scaling combining base scale and resolution adaptation
 | 
				
			||||||
 | 
							var finalScale: Float = BASE_SCALE * resolutionMultiplier;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Apply user-defined sensitivity multiplier
 | 
				
			||||||
 | 
							deltaX *= sensitivity;
 | 
				
			||||||
 | 
							deltaY *= sensitivity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Convert pixel movement to rotation angles (radians)
 | 
				
			||||||
 | 
							// Negative values ensure natural movement direction (moving mouse right rotates right)
 | 
				
			||||||
 | 
							var horizontalRotation: Float = (-deltaX / finalScale) * RADIAN_SCALING_FACTOR;
 | 
				
			||||||
 | 
							var verticalRotation: Float = (-deltaY / finalScale) * RADIAN_SCALING_FACTOR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Apply horizontal rotation capping if enabled
 | 
				
			||||||
 | 
							// This prevents the character from rotating beyond specified limits
 | 
				
			||||||
 | 
							if (property4) {
 | 
				
			||||||
 | 
								currentHorizontal += horizontalRotation;
 | 
				
			||||||
 | 
								// Clamp rotation to maximum horizontal range and adjust current frame rotation
 | 
				
			||||||
 | 
								if (currentHorizontal > maxHorizontal) {
 | 
				
			||||||
 | 
									horizontalRotation -= (currentHorizontal - maxHorizontal);
 | 
				
			||||||
 | 
									currentHorizontal = maxHorizontal;
 | 
				
			||||||
 | 
								} else if (currentHorizontal < -maxHorizontal) {
 | 
				
			||||||
 | 
									horizontalRotation -= (currentHorizontal + maxHorizontal);
 | 
				
			||||||
 | 
									currentHorizontal = -maxHorizontal;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Apply vertical rotation capping if enabled
 | 
				
			||||||
 | 
							// This prevents looking too far up or down (like human neck limitations)
 | 
				
			||||||
 | 
							if (property5) {
 | 
				
			||||||
 | 
								currentVertical += verticalRotation;
 | 
				
			||||||
 | 
								// Clamp rotation to maximum vertical range and adjust current frame rotation
 | 
				
			||||||
 | 
								if (currentVertical > maxVertical) {
 | 
				
			||||||
 | 
									verticalRotation -= (currentVertical - maxVertical);
 | 
				
			||||||
 | 
									currentVertical = maxVertical;
 | 
				
			||||||
 | 
								} else if (currentVertical < -maxVertical) {
 | 
				
			||||||
 | 
									verticalRotation -= (currentVertical + maxVertical);
 | 
				
			||||||
 | 
									currentVertical = -maxVertical;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Apply horizontal rotation to body object (character turning left/right)
 | 
				
			||||||
 | 
							if (horizontalRotation != 0.0) {
 | 
				
			||||||
 | 
								bodyObject.transform.rotate(horizontalAxis, horizontalRotation);
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								// Synchronize physics rigid body if present
 | 
				
			||||||
 | 
								// This ensures physics simulation stays in sync with visual transform
 | 
				
			||||||
 | 
								#if lnx_physics
 | 
				
			||||||
 | 
								var rigidBody = bodyObject.getTrait(leenkx.trait.physics.RigidBody);
 | 
				
			||||||
 | 
								if (rigidBody != null) rigidBody.syncTransform();
 | 
				
			||||||
 | 
								#end
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Apply vertical rotation to head object (camera looking up/down)
 | 
				
			||||||
 | 
							if (headObject != null && verticalRotation != 0.0) {
 | 
				
			||||||
 | 
								if (property6) {
 | 
				
			||||||
 | 
									// Local space rotation - recommended when head is a child of body
 | 
				
			||||||
 | 
									// This prevents gimbal lock and rotation inheritance issues
 | 
				
			||||||
 | 
									headObject.transform.rotate(verticalAxis, verticalRotation);
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									// World space rotation - uses head object's current right vector
 | 
				
			||||||
 | 
									// More accurate for independent head objects but can cause issues with parenting
 | 
				
			||||||
 | 
									var headVerticalAxis = headObject.transform.world.right();
 | 
				
			||||||
 | 
									headObject.transform.rotate(headVerticalAxis, verticalRotation);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								// Synchronize head physics rigid body if present
 | 
				
			||||||
 | 
								#if lnx_physics
 | 
				
			||||||
 | 
								var headRigidBody = headObject.getTrait(leenkx.trait.physics.RigidBody);
 | 
				
			||||||
 | 
								if (headRigidBody != null) headRigidBody.syncTransform();
 | 
				
			||||||
 | 
								#end
 | 
				
			||||||
 | 
							} else if (headObject == null && verticalRotation != 0.0) {
 | 
				
			||||||
 | 
								// Fallback: if no separate head object, apply vertical rotation to body
 | 
				
			||||||
 | 
								// This creates a simpler single-object camera control
 | 
				
			||||||
 | 
								bodyObject.transform.rotate(verticalAxis, verticalRotation);
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								// Synchronize body physics rigid body
 | 
				
			||||||
 | 
								#if lnx_physics
 | 
				
			||||||
 | 
								var rigidBody = bodyObject.getTrait(leenkx.trait.physics.RigidBody);
 | 
				
			||||||
 | 
								if (rigidBody != null) rigidBody.syncTransform();
 | 
				
			||||||
 | 
								#end
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Continue to next connected node in the logic tree
 | 
				
			||||||
 | 
							runOutput(0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					} 
 | 
				
			||||||
@ -1,7 +1,11 @@
 | 
				
			|||||||
package leenkx.logicnode;
 | 
					package leenkx.logicnode;
 | 
				
			||||||
 | 
					 | 
				
			||||||
import iron.object.Object;
 | 
					import iron.object.Object;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if lnx_physics
 | 
				
			||||||
 | 
					import leenkx.trait.physics.PhysicsCache;
 | 
				
			||||||
import leenkx.trait.physics.RigidBody;
 | 
					import leenkx.trait.physics.RigidBody;
 | 
				
			||||||
 | 
					#end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class OnContactNode extends LogicNode {
 | 
					class OnContactNode extends LogicNode {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -23,22 +27,15 @@ class OnContactNode extends LogicNode {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		var contact = false;
 | 
							var contact = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if lnx_physics
 | 
							#if lnx_physics
 | 
				
			||||||
		var physics = leenkx.trait.physics.PhysicsWorld.active;
 | 
								var rb1 = PhysicsCache.getCachedRigidBody(object1);
 | 
				
			||||||
		var rb1 = object1.getTrait(RigidBody);
 | 
								var rb2 = PhysicsCache.getCachedRigidBody(object2);
 | 
				
			||||||
		if (rb1 != null) {
 | 
								
 | 
				
			||||||
			var rbs = physics.getContacts(rb1);
 | 
								if (rb1 != null && rb2 != null) {
 | 
				
			||||||
			if (rbs != null) {
 | 
									var rbs = PhysicsCache.getCachedContacts(rb1);
 | 
				
			||||||
				var rb2 = object2.getTrait(RigidBody);
 | 
									contact = PhysicsCache.hasContactWith(rbs, rb2);
 | 
				
			||||||
				for (rb in rbs) {
 | 
					 | 
				
			||||||
					if (rb == rb2) {
 | 
					 | 
				
			||||||
						contact = true;
 | 
					 | 
				
			||||||
						break;
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
				}
 | 
							#end
 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
#end
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		var b = false;
 | 
							var b = false;
 | 
				
			||||||
		switch (property0) {
 | 
							switch (property0) {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										23
									
								
								leenkx/Sources/leenkx/logicnode/OnceNode.hx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								leenkx/Sources/leenkx/logicnode/OnceNode.hx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					package leenkx.logicnode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class OnceNode extends LogicNode {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var triggered:Bool = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function new(tree: LogicTree) {
 | 
				
			||||||
 | 
					        super(tree);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override function run(from: Int) {
 | 
				
			||||||
 | 
							if(from == 1){
 | 
				
			||||||
 | 
								triggered = false;
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!triggered) {
 | 
				
			||||||
 | 
								triggered = true;
 | 
				
			||||||
 | 
					            runOutput(0);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -9,19 +9,38 @@ import iron.Scene;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
class PlayAnimationTreeNode extends LogicNode {
 | 
					class PlayAnimationTreeNode extends LogicNode {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var object: Object;
 | 
				
			||||||
 | 
						var action: Dynamic;
 | 
				
			||||||
 | 
						var init: Bool = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public function new(tree: LogicTree) {
 | 
						public function new(tree: LogicTree) {
 | 
				
			||||||
		super(tree);
 | 
							super(tree);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	override function run(from: Int) {
 | 
						override function run(from: Int) {
 | 
				
			||||||
		var object: Object = inputs[1].get();
 | 
							object = inputs[1].get();
 | 
				
			||||||
		var action: Dynamic = inputs[2].get();
 | 
							action = inputs[2].get();
 | 
				
			||||||
 | 
					 | 
				
			||||||
		assert(Error, object != null, "The object input not be null");
 | 
							assert(Error, object != null, "The object input not be null");
 | 
				
			||||||
 | 
							init = true;
 | 
				
			||||||
 | 
							tree.notifyOnUpdate(playAnim);
 | 
				
			||||||
 | 
							// TO DO: Investigate AnimAction get and PlayAnimationTree notifiers
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						function playAnim() {
 | 
				
			||||||
 | 
							if (init = false) return;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							init = false;
 | 
				
			||||||
 | 
							tree.removeUpdate(playAnim);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
		var animation = object.animation;
 | 
							var animation = object.animation;
 | 
				
			||||||
		if(animation == null) {
 | 
							if(animation == null) {
 | 
				
			||||||
			#if lnx_skin
 | 
								#if lnx_skin
 | 
				
			||||||
			animation = object.getBoneAnimation(object.uid);
 | 
								animation = object.getBoneAnimation(object.uid);
 | 
				
			||||||
 | 
								if (animation == null) {
 | 
				
			||||||
 | 
									tree.notifyOnUpdate(playAnim);
 | 
				
			||||||
 | 
									init = true;
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			cast(animation, BoneAnimation).setAnimationLoop(function f(mats) {
 | 
								cast(animation, BoneAnimation).setAnimationLoop(function f(mats) {
 | 
				
			||||||
				action(mats);
 | 
									action(mats);
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
@ -32,7 +51,6 @@ class PlayAnimationTreeNode extends LogicNode {
 | 
				
			|||||||
				action(mats);
 | 
									action(mats);
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		
 | 
					 | 
				
			||||||
		runOutput(0);
 | 
							runOutput(0);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										41
									
								
								leenkx/Sources/leenkx/logicnode/ProbabilisticIndexNode.hx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								leenkx/Sources/leenkx/logicnode/ProbabilisticIndexNode.hx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,41 @@
 | 
				
			|||||||
 | 
					package leenkx.logicnode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ProbabilisticIndexNode extends LogicNode {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public function new(tree: LogicTree) {
 | 
				
			||||||
 | 
							super(tree);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						override function get(from: Int): Dynamic {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var probs: Array<Float> = [];
 | 
				
			||||||
 | 
							var probs_acum: Array<Float> = [];
 | 
				
			||||||
 | 
							var sum: Float = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (p in 0...inputs.length){
 | 
				
			||||||
 | 
								probs.push(inputs[p].get());
 | 
				
			||||||
 | 
								sum += probs[p];
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (sum > 1){
 | 
				
			||||||
 | 
								for (p in 0...probs.length)
 | 
				
			||||||
 | 
									probs[p] /= sum;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							sum = 0;
 | 
				
			||||||
 | 
							for (p in 0...probs.length){
 | 
				
			||||||
 | 
								sum += probs[p];
 | 
				
			||||||
 | 
								probs_acum.push(sum);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var rand: Float = Math.random();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (p in 0...probs.length){
 | 
				
			||||||
 | 
								if (p == 0 && rand <= probs_acum[p]) return p;
 | 
				
			||||||
 | 
								else if (0 < p && p < probs.length-1 && probs_acum[p-1] < rand && rand <= probs_acum[p]) return p;
 | 
				
			||||||
 | 
								else if (p == probs.length-1 && probs_acum[p-1] < rand) return p;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return null;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -18,7 +18,6 @@ class ProbabilisticOutputNode extends LogicNode {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (sum > 1){
 | 
							if (sum > 1){
 | 
				
			||||||
			trace(sum);
 | 
					 | 
				
			||||||
			for (p in 0...probs.length)
 | 
								for (p in 0...probs.length)
 | 
				
			||||||
				probs[p] /= sum;
 | 
									probs[p] /= sum;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,64 @@
 | 
				
			|||||||
 | 
					package leenkx.logicnode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import iron.object.Object;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RemoveParticleFromObjectNode extends LogicNode {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public var property0: String;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public function new(tree: LogicTree) {
 | 
				
			||||||
 | 
							super(tree);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						override function run(from: Int) {
 | 
				
			||||||
 | 
							#if lnx_particles
 | 
				
			||||||
 | 
							var object: Object = inputs[1].get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (object == null) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var mo = cast(object, iron.object.MeshObject);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (mo.particleSystems == null) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (property0 == 'All'){
 | 
				
			||||||
 | 
								mo.particleSystems = null;
 | 
				
			||||||
 | 
								for (c in mo.particleChildren) c.remove();
 | 
				
			||||||
 | 
								mo.particleChildren = null;
 | 
				
			||||||
 | 
								mo.particleOwner = null;
 | 
				
			||||||
 | 
								mo.render_emitter = true;
 | 
				
			||||||
 | 
							} 
 | 
				
			||||||
 | 
							else {
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								var slot: Int = -1;
 | 
				
			||||||
 | 
								if (property0 == 'Name'){
 | 
				
			||||||
 | 
									var name: String = inputs[2].get();
 | 
				
			||||||
 | 
									for (i => psys in mo.particleSystems){
 | 
				
			||||||
 | 
										if (@:privateAccess psys.r.name == name){ slot = i; break; }
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								} 
 | 
				
			||||||
 | 
								else slot = inputs[2].get();
 | 
				
			||||||
 | 
									
 | 
				
			||||||
 | 
								if (mo.particleSystems.length > slot){
 | 
				
			||||||
 | 
									for (i in slot+1...mo.particleSystems.length){
 | 
				
			||||||
 | 
										var mi = cast(mo.particleChildren[i], iron.object.MeshObject);
 | 
				
			||||||
 | 
										mi.particleIndex = mi.particleIndex - 1;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									mo.particleSystems.splice(slot, 1);
 | 
				
			||||||
 | 
									mo.particleChildren[slot].remove();
 | 
				
			||||||
 | 
									mo.particleChildren.splice(slot, 1);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (slot == 0){
 | 
				
			||||||
 | 
									mo.particleSystems = null;
 | 
				
			||||||
 | 
									mo.particleChildren = null;
 | 
				
			||||||
 | 
									mo.particleOwner = null;
 | 
				
			||||||
 | 
									mo.render_emitter = true;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							#end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							runOutput(0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										16
									
								
								leenkx/Sources/leenkx/logicnode/ResolutionGetNode.hx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								leenkx/Sources/leenkx/logicnode/ResolutionGetNode.hx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					package leenkx.logicnode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ResolutionGetNode extends LogicNode {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public function new(tree:LogicTree) {
 | 
				
			||||||
 | 
							super(tree);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						override function get(from:Int):Dynamic {
 | 
				
			||||||
 | 
							return switch (from) {
 | 
				
			||||||
 | 
								case 0: leenkx.renderpath.Postprocess.resolution_uniforms[0];
 | 
				
			||||||
 | 
								case 1: leenkx.renderpath.Postprocess.resolution_uniforms[1];
 | 
				
			||||||
 | 
								default: 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										33
									
								
								leenkx/Sources/leenkx/logicnode/ResolutionSetNode.hx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								leenkx/Sources/leenkx/logicnode/ResolutionSetNode.hx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,33 @@
 | 
				
			|||||||
 | 
					package leenkx.logicnode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import kha.graphics4.TextureFilter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ResolutionSetNode extends LogicNode {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public function new(tree:LogicTree) {
 | 
				
			||||||
 | 
							super(tree);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						override function run(from:Int) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var size: Int = inputs[1].get();
 | 
				
			||||||
 | 
							var filter: Int = inputs[2].get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#if rp_resolution_filter 
 | 
				
			||||||
 | 
							if (filter == 0)
 | 
				
			||||||
 | 
								iron.object.Uniforms.defaultFilter = TextureFilter.LinearFilter;
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								iron.object.Uniforms.defaultFilter = TextureFilter.PointFilter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							leenkx.renderpath.Postprocess.resolution_uniforms[0] = size;
 | 
				
			||||||
 | 
							leenkx.renderpath.Postprocess.resolution_uniforms[1] = filter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var npath = leenkx.renderpath.RenderPathCreator.get();
 | 
				
			||||||
 | 
							var world = iron.Scene.active.raw.world_ref;
 | 
				
			||||||
 | 
							npath.loadShader("shader_datas/World_" + world + "/World_" + world);
 | 
				
			||||||
 | 
							iron.RenderPath.setActive(npath);
 | 
				
			||||||
 | 
					    #end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							runOutput(0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -20,6 +20,8 @@ class RpConfigNode extends LogicNode {
 | 
				
			|||||||
			on ? leenkx.data.Config.raw.rp_ssrefr = true : leenkx.data.Config.raw.rp_ssrefr = false;
 | 
								on ? leenkx.data.Config.raw.rp_ssrefr = true : leenkx.data.Config.raw.rp_ssrefr = false;
 | 
				
			||||||
        case "Bloom":
 | 
					        case "Bloom":
 | 
				
			||||||
			on ? leenkx.data.Config.raw.rp_bloom = true : leenkx.data.Config.raw.rp_bloom = false;
 | 
								on ? leenkx.data.Config.raw.rp_bloom = true : leenkx.data.Config.raw.rp_bloom = false;
 | 
				
			||||||
 | 
							case "CA":
 | 
				
			||||||
 | 
								on ? leenkx.data.Config.raw.rp_chromatic_aberration = true : leenkx.data.Config.raw.rp_chromatic_aberration = false;
 | 
				
			||||||
        case "GI":
 | 
					        case "GI":
 | 
				
			||||||
			on ? leenkx.data.Config.raw.rp_gi = true : leenkx.data.Config.raw.rp_gi = false;
 | 
								on ? leenkx.data.Config.raw.rp_gi = true : leenkx.data.Config.raw.rp_gi = false;
 | 
				
			||||||
		case "Motion Blur":
 | 
							case "Motion Blur":
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										23
									
								
								leenkx/Sources/leenkx/logicnode/SetAudioPositionNode.hx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								leenkx/Sources/leenkx/logicnode/SetAudioPositionNode.hx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					package leenkx.logicnode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import aura.Aura;
 | 
				
			||||||
 | 
					import aura.Types;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SetAudioPositionNode extends LogicNode {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public function new(tree: LogicTree) {
 | 
				
			||||||
 | 
							super(tree);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						override function run(from: Int) {
 | 
				
			||||||
 | 
							var audio = inputs[1].get();
 | 
				
			||||||
 | 
							if (audio == null) return;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							var positionInSeconds:Float = inputs[2].get();
 | 
				
			||||||
 | 
							if (positionInSeconds < 0.0) positionInSeconds = 0.0;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							audio.channel.floatPosition = positionInSeconds * audio.channel.sampleRate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							runOutput(0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										38
									
								
								leenkx/Sources/leenkx/logicnode/SetCameraRenderFilterNode.hx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								leenkx/Sources/leenkx/logicnode/SetCameraRenderFilterNode.hx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,38 @@
 | 
				
			|||||||
 | 
					package leenkx.logicnode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import iron.object.MeshObject;
 | 
				
			||||||
 | 
					import iron.object.CameraObject;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SetCameraRenderFilterNode extends LogicNode {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public var property0: String;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public function new(tree: LogicTree) {
 | 
				
			||||||
 | 
							super(tree);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						override function run(from: Int) {
 | 
				
			||||||
 | 
							var mo: MeshObject = cast inputs[1].get();
 | 
				
			||||||
 | 
							var camera: CameraObject = inputs[2].get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							assert(Error, Std.isOfType(camera, CameraObject), "Camera must be a camera object!");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (camera == null || mo == null) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (property0 == 'Add'){
 | 
				
			||||||
 | 
								if (mo.cameraList == null || mo.cameraList.indexOf(camera.name) == -1){
 | 
				
			||||||
 | 
									if (mo.cameraList == null) mo.cameraList = [];
 | 
				
			||||||
 | 
									mo.cameraList.push(camera.name);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else{
 | 
				
			||||||
 | 
								if (mo.cameraList != null){
 | 
				
			||||||
 | 
									mo.cameraList.remove(camera.name);
 | 
				
			||||||
 | 
									if (mo.cameraList.length == 0)
 | 
				
			||||||
 | 
										mo.cameraList = null;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							runOutput(0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										21
									
								
								leenkx/Sources/leenkx/logicnode/SetLightShadowNode.hx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								leenkx/Sources/leenkx/logicnode/SetLightShadowNode.hx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					package leenkx.logicnode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import iron.object.LightObject;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SetLightShadowNode extends LogicNode {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public function new(tree: LogicTree) {
 | 
				
			||||||
 | 
							super(tree);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						override function run(from: Int) {
 | 
				
			||||||
 | 
							var light: LightObject = inputs[1].get();
 | 
				
			||||||
 | 
							var shadow: Bool = inputs[2].get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (light == null) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							light.data.raw.cast_shadow = shadow;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							runOutput(0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										206
									
								
								leenkx/Sources/leenkx/logicnode/SetLookAtRotationNode.hx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										206
									
								
								leenkx/Sources/leenkx/logicnode/SetLookAtRotationNode.hx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,206 @@
 | 
				
			|||||||
 | 
					package leenkx.logicnode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import iron.math.Vec4;
 | 
				
			||||||
 | 
					import iron.math.Quat;
 | 
				
			||||||
 | 
					import iron.math.Mat4;
 | 
				
			||||||
 | 
					import iron.object.Object;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SetLookAtRotationNode extends LogicNode {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public var property0: String; // Axis to align
 | 
				
			||||||
 | 
						public var property1: String; // Use vector for target (true/false)
 | 
				
			||||||
 | 
						public var property2: String; // Use vector for source (true/false)
 | 
				
			||||||
 | 
						public var property3: String; // Damping value (backward compatibility, now input socket)
 | 
				
			||||||
 | 
						public var property4: String; // Disable rotation on aligning axis (true/false)
 | 
				
			||||||
 | 
						public var property5: String; // Use local space (true/false)
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						// Store the calculated rotation for output
 | 
				
			||||||
 | 
						var calculatedRotation: Quat = null;
 | 
				
			||||||
 | 
						// Store the previous rotation for smooth interpolation
 | 
				
			||||||
 | 
						var previousRotation: Quat = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public function new(tree: LogicTree) {
 | 
				
			||||||
 | 
							super(tree);
 | 
				
			||||||
 | 
							previousRotation = new Quat();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						override function run(from: Int): Void {
 | 
				
			||||||
 | 
							// Determine if we're using a vector or an object as source
 | 
				
			||||||
 | 
							var useSourceVector: Bool = property2 == "true";
 | 
				
			||||||
 | 
							var objectToUse: Object = null;
 | 
				
			||||||
 | 
							var objectLoc: Vec4 = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (useSourceVector) {
 | 
				
			||||||
 | 
								// Use tree.object as the object to rotate
 | 
				
			||||||
 | 
								objectToUse = tree.object;
 | 
				
			||||||
 | 
								if (objectToUse == null) {
 | 
				
			||||||
 | 
									runOutput(0);
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Get the source location directly
 | 
				
			||||||
 | 
								objectLoc = inputs[1].get();
 | 
				
			||||||
 | 
								if (objectLoc == null) {
 | 
				
			||||||
 | 
									runOutput(0);
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								// Get the source object (or fallback to tree.object)
 | 
				
			||||||
 | 
								objectToUse = (inputs.length > 1 && inputs[1] != null) ? inputs[1].get() : tree.object;
 | 
				
			||||||
 | 
								if (objectToUse == null) {
 | 
				
			||||||
 | 
									runOutput(0);
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Get source object's WORLD position (important for child objects)
 | 
				
			||||||
 | 
								objectLoc = new Vec4(objectToUse.transform.worldx(), objectToUse.transform.worldy(), objectToUse.transform.worldz());
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Determine if we're using a vector or an object as target
 | 
				
			||||||
 | 
							var useTargetVector: Bool = property1 == "true";
 | 
				
			||||||
 | 
							var targetLoc: Vec4 = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (useTargetVector) {
 | 
				
			||||||
 | 
								// Get the target location directly
 | 
				
			||||||
 | 
								targetLoc = inputs[2].get();
 | 
				
			||||||
 | 
								if (targetLoc == null) {
 | 
				
			||||||
 | 
									runOutput(0);
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								// Get the target object
 | 
				
			||||||
 | 
								var targetObject: Object = inputs[2].get();
 | 
				
			||||||
 | 
								if (targetObject == null) {
 | 
				
			||||||
 | 
									runOutput(0);
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								// Get target object's WORLD position (important for child objects)
 | 
				
			||||||
 | 
								targetLoc = new Vec4(targetObject.transform.worldx(), targetObject.transform.worldy(), targetObject.transform.worldz());
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							// Calculate direction to target
 | 
				
			||||||
 | 
							var direction = new Vec4(
 | 
				
			||||||
 | 
								targetLoc.x - objectLoc.x,
 | 
				
			||||||
 | 
								targetLoc.y - objectLoc.y,
 | 
				
			||||||
 | 
								targetLoc.z - objectLoc.z
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
							direction.normalize();
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							// Calculate target rotation based on selected axis
 | 
				
			||||||
 | 
							calculatedRotation = new Quat();
 | 
				
			||||||
 | 
							switch (property0) {
 | 
				
			||||||
 | 
								case "X":
 | 
				
			||||||
 | 
									calculatedRotation.fromTo(new Vec4(1, 0, 0), direction);
 | 
				
			||||||
 | 
								case "-X":
 | 
				
			||||||
 | 
									calculatedRotation.fromTo(new Vec4(-1, 0, 0), direction);
 | 
				
			||||||
 | 
								case "Y":
 | 
				
			||||||
 | 
									calculatedRotation.fromTo(new Vec4(0, 1, 0), direction);
 | 
				
			||||||
 | 
								case "-Y":
 | 
				
			||||||
 | 
									calculatedRotation.fromTo(new Vec4(0, -1, 0), direction);
 | 
				
			||||||
 | 
								case "Z":
 | 
				
			||||||
 | 
									calculatedRotation.fromTo(new Vec4(0, 0, 1), direction);
 | 
				
			||||||
 | 
								case "-Z":
 | 
				
			||||||
 | 
									calculatedRotation.fromTo(new Vec4(0, 0, -1), direction);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							// If disable rotation on aligning axis is enabled, constrain the target rotation
 | 
				
			||||||
 | 
							if (property4 == "true") {
 | 
				
			||||||
 | 
								// Apply constraint to the target rotation BEFORE damping to avoid jiggling
 | 
				
			||||||
 | 
								var eulerAngles = calculatedRotation.toEulerOrdered("XYZ");
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								// Set the rotation around the selected axis to 0
 | 
				
			||||||
 | 
								switch (property0) {
 | 
				
			||||||
 | 
									case "X", "-X":
 | 
				
			||||||
 | 
										eulerAngles.x = 0.0;
 | 
				
			||||||
 | 
									case "Y", "-Y":
 | 
				
			||||||
 | 
										eulerAngles.y = 0.0;
 | 
				
			||||||
 | 
									case "Z", "-Z":
 | 
				
			||||||
 | 
										eulerAngles.z = 0.0;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								// Convert back to quaternion
 | 
				
			||||||
 | 
								calculatedRotation.fromEulerOrdered(eulerAngles, "XYZ");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							// Convert world rotation to local rotation if local space is enabled and object has a parent
 | 
				
			||||||
 | 
							var targetRotation = new Quat();
 | 
				
			||||||
 | 
							if (property5 == "true" && objectToUse.parent != null) {
 | 
				
			||||||
 | 
								// Get parent's world rotation
 | 
				
			||||||
 | 
								var parentWorldLoc = new Vec4();
 | 
				
			||||||
 | 
								var parentWorldRot = new Quat();
 | 
				
			||||||
 | 
								var parentWorldScale = new Vec4();
 | 
				
			||||||
 | 
								objectToUse.parent.transform.world.decompose(parentWorldLoc, parentWorldRot, parentWorldScale);
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								// Convert world rotation to local space by removing parent's rotation influence
 | 
				
			||||||
 | 
								// local_rotation = inverse(parent_world_rotation) * world_rotation
 | 
				
			||||||
 | 
								var invParentRot = new Quat().setFrom(parentWorldRot);
 | 
				
			||||||
 | 
								invParentRot.x = -invParentRot.x;
 | 
				
			||||||
 | 
								invParentRot.y = -invParentRot.y;
 | 
				
			||||||
 | 
								invParentRot.z = -invParentRot.z;
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								targetRotation.multquats(invParentRot, calculatedRotation);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								// No local space conversion needed, use world rotation directly
 | 
				
			||||||
 | 
								targetRotation.setFrom(calculatedRotation);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							// Apply rotation with damping
 | 
				
			||||||
 | 
							var dampingValue: Float = 0.0;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							// Try to get damping from input socket first (index 3), fallback to property
 | 
				
			||||||
 | 
							if (inputs.length > 3 && inputs[3] != null) {
 | 
				
			||||||
 | 
								var dampingInput: Dynamic = inputs[3].get();
 | 
				
			||||||
 | 
								if (dampingInput != null) {
 | 
				
			||||||
 | 
									dampingValue = dampingInput;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								// Fallback to property for backward compatibility
 | 
				
			||||||
 | 
								dampingValue = Std.parseFloat(property3);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							if (dampingValue > 0.0) {
 | 
				
			||||||
 | 
								// Create a fixed interpolation rate that never reaches exactly 1.0
 | 
				
			||||||
 | 
								// Higher damping = slower rotation (smaller step)
 | 
				
			||||||
 | 
								var step = Math.max(0.001, (1.0 - dampingValue) * 0.2); // 0.001 to 0.2 range
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								// Get current local rotation as quaternion
 | 
				
			||||||
 | 
								var currentLocalRot = new Quat().setFrom(objectToUse.transform.rot);
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								// Calculate the difference between current and target rotation
 | 
				
			||||||
 | 
								var diffQuat = new Quat();
 | 
				
			||||||
 | 
								// q1 * inverse(q2) gives the rotation from q2 to q1
 | 
				
			||||||
 | 
								var invCurrent = new Quat().setFrom(currentLocalRot);
 | 
				
			||||||
 | 
								invCurrent.x = -invCurrent.x;
 | 
				
			||||||
 | 
								invCurrent.y = -invCurrent.y;
 | 
				
			||||||
 | 
								invCurrent.z = -invCurrent.z;
 | 
				
			||||||
 | 
								diffQuat.multquats(targetRotation, invCurrent);
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								// Convert to axis-angle representation
 | 
				
			||||||
 | 
								var axis = new Vec4();
 | 
				
			||||||
 | 
								var angle = diffQuat.toAxisAngle(axis);
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								// Apply only a portion of this rotation (step)
 | 
				
			||||||
 | 
								var partialAngle = angle * step;
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								// Create partial rotation quaternion
 | 
				
			||||||
 | 
								var partialRot = new Quat().fromAxisAngle(axis, partialAngle);
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								// Apply this partial rotation to current local rotation
 | 
				
			||||||
 | 
								var newLocalRot = new Quat();
 | 
				
			||||||
 | 
								newLocalRot.multquats(partialRot, currentLocalRot);
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								// Apply the new local rotation
 | 
				
			||||||
 | 
								objectToUse.transform.rot.setFrom(newLocalRot);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								// No damping, apply instant rotation
 | 
				
			||||||
 | 
								objectToUse.transform.rot.setFrom(targetRotation);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							objectToUse.transform.buildMatrix();
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							runOutput(0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// No output sockets needed - this node only performs actions
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,55 @@
 | 
				
			|||||||
 | 
					package leenkx.logicnode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import iron.object.MeshObject;
 | 
				
			||||||
 | 
					import iron.data.MaterialData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SetMaterialTextureFilterNode extends LogicNode {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public function new(tree: LogicTree) {
 | 
				
			||||||
 | 
							super(tree);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						override function run(from: Int) {
 | 
				
			||||||
 | 
							var object: MeshObject = inputs[1].get();
 | 
				
			||||||
 | 
							var mat: MaterialData = inputs[2].get();
 | 
				
			||||||
 | 
							var slot: Int = inputs[3].get();
 | 
				
			||||||
 | 
							var name: String = inputs[4].get();
 | 
				
			||||||
 | 
							var filter: Int = inputs[5].get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (object == null) return;
 | 
				
			||||||
 | 
							if (slot >= object.materials.length) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var mo = cast(object, iron.object.MeshObject);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (i => node in mo.materials[slot].contexts[0].raw.bind_textures)
 | 
				
			||||||
 | 
								if (node.name == name){
 | 
				
			||||||
 | 
									var moImgt = mo.materials[slot].contexts[0].raw.bind_textures[i];
 | 
				
			||||||
 | 
									switch(filter){
 | 
				
			||||||
 | 
										case 0: //Linear
 | 
				
			||||||
 | 
											moImgt.min_filter = null;
 | 
				
			||||||
 | 
											moImgt.mag_filter = null;
 | 
				
			||||||
 | 
											moImgt.mipmap_filter = null;
 | 
				
			||||||
 | 
											moImgt.generate_mipmaps = null;
 | 
				
			||||||
 | 
										case 1: //Closest
 | 
				
			||||||
 | 
											moImgt.min_filter = 'point';
 | 
				
			||||||
 | 
											moImgt.mag_filter = 'point';
 | 
				
			||||||
 | 
											moImgt.mipmap_filter = null;
 | 
				
			||||||
 | 
											moImgt.generate_mipmaps = null;
 | 
				
			||||||
 | 
										case 2: //Cubic
 | 
				
			||||||
 | 
											moImgt.min_filter = null;
 | 
				
			||||||
 | 
											moImgt.mag_filter = null;
 | 
				
			||||||
 | 
											moImgt.mipmap_filter = 'linear';
 | 
				
			||||||
 | 
											moImgt.generate_mipmaps = true;
 | 
				
			||||||
 | 
										case 3: //Smart
 | 
				
			||||||
 | 
											moImgt.min_filter = 'anisotropic';
 | 
				
			||||||
 | 
											moImgt.mag_filter = null;
 | 
				
			||||||
 | 
											moImgt.mipmap_filter = 'linear';
 | 
				
			||||||
 | 
											moImgt.generate_mipmaps = true;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							runOutput(0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,74 @@
 | 
				
			|||||||
 | 
					package leenkx.logicnode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import iron.object.Object;
 | 
				
			||||||
 | 
					import iron.math.Vec4;
 | 
				
			||||||
 | 
					import iron.math.Mat4;
 | 
				
			||||||
 | 
					import iron.system.Time;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SetObjectDelayedLocationNode extends LogicNode {
 | 
				
			||||||
 | 
						public var use_local_space: Bool = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private var initialOffset: Vec4 = null;
 | 
				
			||||||
 | 
						private var targetPos: Vec4 = new Vec4();
 | 
				
			||||||
 | 
						private var currentPos: Vec4 = new Vec4();
 | 
				
			||||||
 | 
						private var deltaVec: Vec4 = new Vec4();
 | 
				
			||||||
 | 
						private var tempVec: Vec4 = new Vec4();
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						private var lastParent: Object = null;
 | 
				
			||||||
 | 
						private var invParentMatrix: Mat4 = null;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						public function new(tree: LogicTree) {
 | 
				
			||||||
 | 
							super(tree);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						override function run(from: Int) {
 | 
				
			||||||
 | 
							var follower: Object = inputs[1].get();
 | 
				
			||||||
 | 
							var target: Object = inputs[2].get();
 | 
				
			||||||
 | 
							var delay: Float = inputs[3].get();
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							if (follower == null || target == null) return runOutput(0);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							if (initialOffset == null) {
 | 
				
			||||||
 | 
								initialOffset = new Vec4();
 | 
				
			||||||
 | 
								var followerPos = follower.transform.world.getLoc();
 | 
				
			||||||
 | 
								var targetPos = target.transform.world.getLoc();
 | 
				
			||||||
 | 
								initialOffset.setFrom(followerPos);
 | 
				
			||||||
 | 
								initialOffset.sub(targetPos);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							targetPos.setFrom(target.transform.world.getLoc());
 | 
				
			||||||
 | 
							currentPos.setFrom(follower.transform.world.getLoc());
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							tempVec.setFrom(targetPos).add(initialOffset);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							deltaVec.setFrom(tempVec).sub(currentPos);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (deltaVec.length() < 0.001 && delay < 0.01) {
 | 
				
			||||||
 | 
								runOutput(0);
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							if (delay == 0.0) {
 | 
				
			||||||
 | 
								currentPos.setFrom(tempVec);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								var smoothFactor = Math.exp(-Time.delta / Math.max(0.0001, delay));
 | 
				
			||||||
 | 
								currentPos.x = tempVec.x + (currentPos.x - tempVec.x) * smoothFactor;
 | 
				
			||||||
 | 
								currentPos.y = tempVec.y + (currentPos.y - tempVec.y) * smoothFactor;
 | 
				
			||||||
 | 
								currentPos.z = tempVec.z + (currentPos.z - tempVec.z) * smoothFactor;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (use_local_space && follower.parent != null) {
 | 
				
			||||||
 | 
								if (follower.parent != lastParent || invParentMatrix == null) {
 | 
				
			||||||
 | 
									lastParent = follower.parent;
 | 
				
			||||||
 | 
									invParentMatrix = Mat4.identity();
 | 
				
			||||||
 | 
									invParentMatrix.getInverse(follower.parent.transform.world);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								tempVec.setFrom(currentPos);
 | 
				
			||||||
 | 
								tempVec.applymat(invParentMatrix); 
 | 
				
			||||||
 | 
								follower.transform.loc.set(tempVec.x, tempVec.y, tempVec.z);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								follower.transform.loc.set(currentPos.x, currentPos.y, currentPos.z);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							follower.transform.buildMatrix();
 | 
				
			||||||
 | 
							runOutput(0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										81
									
								
								leenkx/Sources/leenkx/logicnode/SetParticleDataNode.hx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								leenkx/Sources/leenkx/logicnode/SetParticleDataNode.hx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,81 @@
 | 
				
			|||||||
 | 
					package leenkx.logicnode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import iron.object.Object;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SetParticleDataNode extends LogicNode {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public var property0: String;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public function new(tree: LogicTree) {
 | 
				
			||||||
 | 
							super(tree);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						override function run(from: Int) {
 | 
				
			||||||
 | 
							#if lnx_particles
 | 
				
			||||||
 | 
							var object: Object = inputs[1].get();
 | 
				
			||||||
 | 
							var slot: Int = inputs[2].get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (object == null) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var mo = cast(object, iron.object.MeshObject);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var psys = mo.particleSystems != null ? mo.particleSystems[slot] : 
 | 
				
			||||||
 | 
								mo.particleOwner != null && mo.particleOwner.particleSystems != null ? mo.particleOwner.particleSystems[slot] : null;		if (psys == null) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							switch (property0) {
 | 
				
			||||||
 | 
								case 'Particle Size':
 | 
				
			||||||
 | 
									@:privateAccess psys.r.particle_size = inputs[3].get();
 | 
				
			||||||
 | 
								case 'Frame Start':
 | 
				
			||||||
 | 
									@:privateAccess psys.r.frame_start = inputs[3].get();
 | 
				
			||||||
 | 
									@:privateAccess psys.animtime = (@:privateAccess psys.r.frame_end - @:privateAccess psys.r.frame_start) / @:privateAccess psys.frameRate;
 | 
				
			||||||
 | 
									@:privateAccess psys.spawnRate = ((@:privateAccess psys.r.frame_end - @:privateAccess psys.r.frame_start) / @:privateAccess psys.count) / @:privateAccess psys.frameRate;
 | 
				
			||||||
 | 
								case 'Frame End':
 | 
				
			||||||
 | 
									@:privateAccess psys.r.frame_end = inputs[3].get();
 | 
				
			||||||
 | 
									@:privateAccess psys.animtime = (@:privateAccess psys.r.frame_end - @:privateAccess psys.r.frame_start) / @:privateAccess psys.frameRate;
 | 
				
			||||||
 | 
									@:privateAccess psys.spawnRate = ((@:privateAccess psys.r.frame_end - @:privateAccess psys.r.frame_start) / @:privateAccess psys.count) / @:privateAccess psys.frameRate;
 | 
				
			||||||
 | 
								case 'Lifetime':
 | 
				
			||||||
 | 
									@:privateAccess psys.lifetime = inputs[3].get() / @:privateAccess psys.frameRate;
 | 
				
			||||||
 | 
								case 'Lifetime Random':
 | 
				
			||||||
 | 
									@:privateAccess psys.r.lifetime_random = inputs[3].get();
 | 
				
			||||||
 | 
								case 'Emit From':
 | 
				
			||||||
 | 
									var emit_from: Int = inputs[3].get();
 | 
				
			||||||
 | 
									if (emit_from == 0 || emit_from == 1 || emit_from == 2) {
 | 
				
			||||||
 | 
										@:privateAccess psys.r.emit_from = emit_from;
 | 
				
			||||||
 | 
										@:privateAccess psys.setupGeomGpu(mo.particleChildren != null ? mo.particleChildren[slot] : cast(iron.Scene.active.getChild(@:privateAccess psys.data.raw.instance_object), iron.object.MeshObject), mo);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								case 'Auto Start':
 | 
				
			||||||
 | 
									@:privateAccess psys.r.auto_start = inputs[3].get(); 
 | 
				
			||||||
 | 
								case 'Is Unique':
 | 
				
			||||||
 | 
									@:privateAccess psys.r.is_unique = inputs[3].get();
 | 
				
			||||||
 | 
								case 'Loop':
 | 
				
			||||||
 | 
									@:privateAccess psys.r.loop = inputs[3].get();
 | 
				
			||||||
 | 
								case 'Velocity':
 | 
				
			||||||
 | 
									var vel: iron.math.Vec3 = inputs[3].get();
 | 
				
			||||||
 | 
									@:privateAccess psys.alignx = vel.x;
 | 
				
			||||||
 | 
									@:privateAccess psys.aligny = vel.y;
 | 
				
			||||||
 | 
									@:privateAccess psys.alignz = vel.z;
 | 
				
			||||||
 | 
								case 'Velocity Random':
 | 
				
			||||||
 | 
									@:privateAccess psys.r.factor_random = inputs[3].get();
 | 
				
			||||||
 | 
								case 'Weight Gravity':
 | 
				
			||||||
 | 
									@:privateAccess psys.r.weight_gravity = inputs[3].get();
 | 
				
			||||||
 | 
									if (iron.Scene.active.raw.gravity != null) {
 | 
				
			||||||
 | 
										@:privateAccess psys.gx = iron.Scene.active.raw.gravity[0] * @:privateAccess psys.r.weight_gravity;
 | 
				
			||||||
 | 
										@:privateAccess psys.gy = iron.Scene.active.raw.gravity[1] * @:privateAccess psys.r.weight_gravity;
 | 
				
			||||||
 | 
										@:privateAccess psys.gz = iron.Scene.active.raw.gravity[2] * @:privateAccess psys.r.weight_gravity;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									else {
 | 
				
			||||||
 | 
										@:privateAccess psys.gx = 0;
 | 
				
			||||||
 | 
										@:privateAccess psys.gy = 0;
 | 
				
			||||||
 | 
										@:privateAccess psys.gz = -9.81 * @:privateAccess psys.r.weight_gravity;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								case 'Speed':
 | 
				
			||||||
 | 
									psys.speed = inputs[3].get();
 | 
				
			||||||
 | 
								default: 
 | 
				
			||||||
 | 
									null;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							#end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							runOutput(0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					package leenkx.logicnode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import iron.object.Object;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SetParticleRenderEmitterNode extends LogicNode {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public function new(tree: LogicTree) {
 | 
				
			||||||
 | 
							super(tree);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						override function run(from: Int) {
 | 
				
			||||||
 | 
							#if lnx_particles
 | 
				
			||||||
 | 
							var object: Object = inputs[1].get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (object == null) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							cast(object, iron.object.MeshObject).render_emitter = inputs[2].get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							#end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							runOutput(0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -11,13 +11,16 @@ class SetParticleSpeedNode extends LogicNode {
 | 
				
			|||||||
	override function run(from: Int) {
 | 
						override function run(from: Int) {
 | 
				
			||||||
		#if lnx_particles
 | 
							#if lnx_particles
 | 
				
			||||||
		var object: Object = inputs[1].get();
 | 
							var object: Object = inputs[1].get();
 | 
				
			||||||
		var speed: Float = inputs[2].get();
 | 
							var slot: Int = inputs[2].get();
 | 
				
			||||||
 | 
							var speed: Float = inputs[3].get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (object == null) return;
 | 
							if (object == null) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		var mo = cast(object, iron.object.MeshObject);
 | 
							var mo = cast(object, iron.object.MeshObject);
 | 
				
			||||||
		var psys = mo.particleSystems.length > 0 ? mo.particleSystems[0] : null;
 | 
							var psys = mo.particleSystems != null ? mo.particleSystems[slot] : 
 | 
				
			||||||
		if (psys == null) mo.particleOwner.particleSystems[0];
 | 
								mo.particleOwner != null && mo.particleOwner.particleSystems != null ? mo.particleOwner.particleSystems[slot] : null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (psys == null) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		psys.speed = speed;
 | 
							psys.speed = speed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										39
									
								
								leenkx/Sources/leenkx/logicnode/SetPositionSpeakerNode.hx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								leenkx/Sources/leenkx/logicnode/SetPositionSpeakerNode.hx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,39 @@
 | 
				
			|||||||
 | 
					package leenkx.logicnode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if lnx_audio
 | 
				
			||||||
 | 
					import iron.object.SpeakerObject;
 | 
				
			||||||
 | 
					import kha.audio1.AudioChannel;
 | 
				
			||||||
 | 
					import iron.system.Audio;
 | 
				
			||||||
 | 
					#end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SetPositionSpeakerNode extends LogicNode {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public function new(tree: LogicTree) {
 | 
				
			||||||
 | 
							super(tree);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						override function run(from: Int) {
 | 
				
			||||||
 | 
							#if lnx_audio
 | 
				
			||||||
 | 
							var object: SpeakerObject = cast(inputs[1].get(), SpeakerObject);
 | 
				
			||||||
 | 
							if (object == null || object.sound == null) return;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							var positionInSeconds:Float = inputs[2].get();
 | 
				
			||||||
 | 
							if (positionInSeconds < 0) positionInSeconds = 0; 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var volume = object.data.volume;
 | 
				
			||||||
 | 
							var loop = object.data.loop;
 | 
				
			||||||
 | 
							var stream = object.data.stream;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							object.stop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var channel = Audio.play(object.sound, loop, stream);
 | 
				
			||||||
 | 
							if (channel != null) {
 | 
				
			||||||
 | 
								object.channels.push(channel);
 | 
				
			||||||
 | 
								channel.volume = volume;
 | 
				
			||||||
 | 
								@:privateAccess channel.set_position(positionInSeconds);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							#end
 | 
				
			||||||
 | 
							runOutput(0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										23
									
								
								leenkx/Sources/leenkx/logicnode/SetWorldNode.hx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								leenkx/Sources/leenkx/logicnode/SetWorldNode.hx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					package leenkx.logicnode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import iron.data.SceneFormat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SetWorldNode extends LogicNode {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public function new(tree: LogicTree) {
 | 
				
			||||||
 | 
							super(tree);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						override function run(from: Int) {
 | 
				
			||||||
 | 
							var world: String = inputs[1].get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (world != null){
 | 
				
			||||||
 | 
								iron.Scene.active.raw.world_ref = world;
 | 
				
			||||||
 | 
								var npath = leenkx.renderpath.RenderPathCreator.get();
 | 
				
			||||||
 | 
								npath.loadShader("shader_datas/World_" + world + "/World_" + world);
 | 
				
			||||||
 | 
								iron.RenderPath.setActive(npath);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							runOutput(0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user