Compare commits
	
		
			808 Commits
		
	
	
		
			1958342a74
			...
			e2002e_0
		
	
	| 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 | |||
| 316441b954 | |||
| 9d7613be8f | |||
| c989f3254f | |||
| f8d76929ae | |||
| a51c28b607 | |||
| 9142371f88 | |||
| 35f92341fa | |||
| a8d1eebdaf | |||
| 87922c9389 | |||
| 38287f56b0 | |||
| 42ad5b01c1 | |||
| 2b46d6ebca | |||
| 953ad8391c | |||
| 1458ecd84f | |||
| 288b085d0c | |||
| aa0b2b1b7e | |||
| acede01167 | |||
| 92a2b0305e | |||
| 4886953722 | |||
| 601860b242 | |||
| f00cef2e21 | |||
| e733dca053 | |||
| 387be05826 | |||
| c5b21a9bb3 | |||
| 5b2c7bfc84 | |||
| 47d913ab64 | |||
| 878ce14254 | |||
| 9075931c51 | |||
| 39ab42f2da | |||
| 30cab4d79b | |||
| 8ee2aaa70a | |||
| 2f9694632d | |||
| 7b8d73cd84 | |||
| 3d8bd77c59 | |||
| 290289f413 | |||
| 2732210fc9 | |||
| 68900fb992 | |||
| ef724ae323 | |||
| 6d4c1a680b | |||
| 8aeaa0368e | |||
| 7969286fdc | |||
| cde2bead97 | |||
| c42e4c09a8 | |||
| b8c8ccad9d | |||
| 335f3541f1 | |||
| 808dcef817 | |||
| 6ac06cc504 | |||
| 86de9617f3 | |||
| 29761ec9e6 | |||
| ea7cf849b8 | |||
| 5d559734b9 | |||
| 939346c896 | |||
| f2dcfc0ffa | |||
| e78bd17d93 | |||
| f9a02f03cb | |||
| 21a4ee0af7 | |||
| 9bf83bc49f | |||
| d88e1f0f42 | |||
| 96f4e29778 | |||
| 1d705d2ca2 | |||
| 0979cd976f | |||
| db6d786ee4 | |||
| 06319131fd | |||
| c08e1d3835 | |||
| 27bd360317 | |||
| 82a53a868a | |||
| 94eaba7319 | |||
| 8d1c2c51bd | |||
| 07d98639f2 | |||
| 1944fc97b8 | |||
| d69e3438ff | |||
| 62e52a7316 | |||
| c4b48c2d87 | |||
| 96f69a7cfe | |||
| 90950970f0 | |||
| 106e36e30d | |||
| e71b0849b3 | |||
| e079c94832 | |||
| 5572494f3d | |||
| 8f03927391 | |||
| 6586d90177 | |||
| 952cee36a3 | |||
| 35bfdf3715 | |||
| 135aaa0669 | |||
| c6b776a329 | |||
| 67c7443985 | |||
| 42273470c3 | |||
| 4dfc6be702 | |||
| 92e1abcfdc | |||
| 764eefeb06 | |||
| 979dfc605d | |||
| 55fb300901 | |||
| c59e6a66d4 | |||
| 659802b888 | |||
| 33f6fcaaaf | |||
| d37b41b181 | |||
| 70742b823f | |||
| da8f9d23e4 | |||
| ff886e6d46 | |||
| 70a603cf7a | |||
| bfc4c2644f | |||
| f101124d24 | |||
| c6f672bd61 | |||
| 7f38b15fe7 | |||
| 2bb296028f | |||
| 5628493493 | |||
| f8a08a41b1 | |||
| 2cd91f598c | |||
| a20d6b581c | |||
| e34ed0794f | |||
| bdcf4c980b | |||
| 25d7ba3e72 | |||
| 30e5acf9bf | |||
| c3435b9533 | |||
| 8765e894f5 | |||
| 2c5c8d0e4f | |||
| 4805dd06a7 | |||
| 2bc2ab43a1 | |||
| bf7b4416ec | |||
| a2d03cfe6e | |||
| 95f0ecfc54 | |||
| 07f59224fc | |||
| 02259985be | |||
| 6b8585c81a | |||
| 5d78eabf94 | |||
| 41c1459c4e | |||
| 304a497565 | |||
| 9fa399371a | |||
| 4625fdb6b2 | |||
| 79553927aa | |||
| 86661c1012 | |||
| 03967c7a2b | |||
| 61fd48a12f | |||
| 519039b8b6 | |||
| 5244b1b3e8 | |||
| 7ae3bbe496 | |||
| 001be2f8da | |||
| 6a25b3c5d7 | |||
| 8d4ac7251a | |||
| ae63b252c6 | |||
| ee73823206 | |||
| af2850e20c | |||
| bc4a31d415 | |||
| 5303ad3ac6 | |||
| 5153cff790 | |||
| abe17870ce | |||
| c798f122d0 | |||
| d1edb1464e | |||
| ee8d3314b5 | |||
| c6139282ed | |||
| 559a3b8b39 | |||
| 8d072ae481 | |||
| 293a612e9c | |||
| 8020599513 | |||
| 4fbc1aba7f | |||
| 1380585297 | |||
| beee036a3d | |||
| 76b2ba8f80 | |||
| e7143cc740 | |||
| bd0886b1d7 | |||
| 8eb8c0bd98 | |||
| dd06e490a7 | |||
| 5e4ac6dd0b | |||
| be0a9149ad | |||
| 7ab3398941 | |||
| c10e988d2d | |||
| caafeea2f1 | |||
| 2edee3fe68 | |||
| af147c9c63 | |||
| 8e4c20647b | |||
| 594cbeffbe | |||
| e1d48e4289 | |||
| 7960ca94a6 | |||
| 72f14f59bf | |||
| d994d040ef | |||
| 1e18795d29 | |||
| 9557b82970 | |||
| 88949c63c5 | |||
| 7cab325397 | |||
| 8792ef5cee | |||
| 761b1832ad | |||
| 074a51866f | |||
| c382460355 | |||
| 4a3544b5d8 | |||
| 7cebe8340f | |||
| ecaea8ad9d | |||
| cae7963b21 | |||
| 7a2976ced1 | |||
| aae64aa8f8 | |||
| ef25d15aed | |||
| 01bcf029f9 | |||
| 2b9baef712 | |||
| 489057018e | |||
| 501a064d25 | |||
| 9478e4e957 | |||
| 32c6535f8a | |||
| 21c2abe67c | |||
| 2b1b56bc0a | |||
| 9e47c1db6d | |||
| 6be977da7e | |||
| 693fa36ee1 | |||
| 6ec480930a | |||
| a627a52d46 | |||
| be63323c09 | |||
| 38595db46b | |||
| 48d28f6873 | |||
| eb033149a0 | |||
| db1c3bdf4c | |||
| 2b16b565a8 | |||
| 8c758bf51f | |||
| 1764081740 | |||
| c90bde8719 | |||
| bfb11275df | |||
| 3185f61f39 | |||
| fb00ca88ff | |||
| 78109cfee2 | |||
| fa65c02e8a | |||
| cb93ede7d7 | |||
| 2a3f8db0bc | |||
| 3ab9123000 | |||
| d6b4b6eeea | |||
| 2f1e6783a4 | |||
| 603a976adf | |||
| 1e0d32a88d | |||
| 82a7075308 | |||
| de8f7d08ed | |||
| caf95e2611 | |||
| b639f06aba | |||
| de41800e1c | |||
| d2746fb087 | |||
| 62d3e65796 | |||
| 74473087b5 | |||
| 392da64d1f | |||
| 30748390ca | |||
| f9d463ca1d | |||
| b8771e9d81 | |||
| 1f52eed66c | |||
| e562b626cb | |||
| ccb554ba16 | |||
| 972775b432 | |||
| ee984c332e | |||
| 038e5123c9 | |||
| b5575e5a48 | |||
| 76d79e6e18 | |||
| ca8fd0b357 | |||
| 87fa82e3d3 | |||
| 9fa58d9d7c | |||
| 864568d66b | |||
| f3e96546ae | |||
| fcc114aed3 | |||
| df33848bee | |||
| c17516a4e2 | |||
| 9b9acd5e15 | |||
| 3b0eb0e075 | |||
| f5b3da3a15 | |||
| b71275d0d5 | |||
| 6aeb9b0f22 | |||
| 609477737e | |||
| a747f89438 | |||
| 0bd0c57a00 | |||
| f3ab801928 | |||
| 9b821d4b8e | |||
| f2a0dbe36c | |||
| 12e66d8cf1 | |||
| 4b6424b702 | |||
| e66e082cc7 | |||
| 42eff22cbb | |||
| 448898a634 | |||
| 15ec41b1f0 | |||
| c5a7746c84 | |||
| 51aa8ea1d4 | |||
| ccdfc4246f | |||
| aead4c4903 | |||
| d2f4c0e221 | |||
| 887eeebe27 | |||
| 83077e3f15 | |||
| f5c20c5a13 | |||
| 4bd4995b6e | |||
| 381744e678 | |||
| 34c15c29cd | |||
| 0346e27657 | |||
| 9087b9c98c | |||
| f2cbcc88a7 | |||
| b8d9ea2aff | |||
| 37a09d0a21 | |||
| ed932e3fa4 | |||
| f00edd882f | |||
| f403955fcd | |||
| a562af9b60 | |||
| bdd9b0197f | |||
| f200933375 | |||
| 829ef5f269 | |||
| 0d73133f36 | |||
| 181b860360 | |||
| 20db9cc24d | |||
| c67b38ea1e | |||
| adb95eab1e | |||
| 93addd1200 | |||
| 7f9a7c9b4a | |||
| 7433409cda | |||
| 2a6e05aff1 | |||
| 348d7bf343 | |||
| 4c6df16aa7 | |||
| 8a7f5ee519 | 
							
								
								
									
										2
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,2 @@ | ||||
| *.hdr binary | ||||
| blender/lnx/props.py ident | ||||
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,3 @@ | ||||
| __pycache__/ | ||||
| *.pyc | ||||
| *.DS_Store | ||||
| @ -1,268 +1,268 @@ | ||||
| /* | ||||
|  *  Platform-specific and custom entropy polling functions | ||||
|  * | ||||
|  *  Copyright (C) 2006-2016, ARM Limited, All Rights Reserved | ||||
|  *  SPDX-License-Identifier: Apache-2.0 | ||||
|  * | ||||
|  *  Licensed under the Apache License, Version 2.0 (the "License"); you may | ||||
|  *  not use this file except in compliance with the License. | ||||
|  *  You may obtain a copy of the License at | ||||
|  * | ||||
|  *  http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  *  Unless required by applicable law or agreed to in writing, software | ||||
|  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
|  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  *  See the License for the specific language governing permissions and | ||||
|  *  limitations under the License. | ||||
|  * | ||||
|  *  This file is part of mbed TLS (https://tls.mbed.org) | ||||
|  */ | ||||
|  | ||||
| #if !defined(MBEDTLS_CONFIG_FILE) | ||||
| #include "mbedtls/config.h" | ||||
| #else | ||||
| #include MBEDTLS_CONFIG_FILE | ||||
| #endif | ||||
|  | ||||
| #if defined(MBEDTLS_ENTROPY_C) | ||||
|  | ||||
| #include "mbedtls/entropy.h" | ||||
| #include "mbedtls/entropy_poll.h" | ||||
|  | ||||
| #if defined(MBEDTLS_TIMING_C) | ||||
| #include <string.h> | ||||
| #include "mbedtls/timing.h" | ||||
| #endif | ||||
| #if defined(MBEDTLS_HAVEGE_C) | ||||
| #include "mbedtls/havege.h" | ||||
| #endif | ||||
| #if defined(MBEDTLS_ENTROPY_NV_SEED) | ||||
| #include "mbedtls/platform.h" | ||||
| #endif | ||||
|  | ||||
| #if !defined(MBEDTLS_NO_PLATFORM_ENTROPY) | ||||
|  | ||||
| #if !defined(unix) && !defined(__unix__) && !defined(__unix) && \ | ||||
|     !defined(__APPLE__) && !defined(_WIN32) | ||||
| #error "Platform entropy sources only work on Unix and Windows, see MBEDTLS_NO_PLATFORM_ENTROPY in config.h" | ||||
| #endif | ||||
|  | ||||
| #if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) | ||||
|  | ||||
| #if !defined(_WIN32_WINNT) | ||||
| #define _WIN32_WINNT 0x0400 | ||||
| #endif | ||||
| #include <windows.h> | ||||
| #include <wincrypt.h> | ||||
|  | ||||
| int mbedtls_platform_entropy_poll( void *data, unsigned char *output, size_t len, | ||||
|                            size_t *olen ) | ||||
| { | ||||
|     HCRYPTPROV provider; | ||||
|     ((void) data); | ||||
|     *olen = 0; | ||||
|  | ||||
|     if( CryptAcquireContext( &provider, NULL, NULL, | ||||
|                               PROV_RSA_FULL, CRYPT_VERIFYCONTEXT ) == FALSE ) | ||||
|     { | ||||
|         return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); | ||||
|     } | ||||
|  | ||||
|     if( CryptGenRandom( provider, (DWORD) len, output ) == FALSE ) | ||||
|     { | ||||
|         CryptReleaseContext( provider, 0 ); | ||||
|         return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); | ||||
|     } | ||||
|  | ||||
|     CryptReleaseContext( provider, 0 ); | ||||
|     *olen = len; | ||||
|  | ||||
|     return( 0 ); | ||||
| } | ||||
| #else /* _WIN32 && !EFIX64 && !EFI32 */ | ||||
|  | ||||
| /* | ||||
|  * Test for Linux getrandom() support. | ||||
|  * Since there is no wrapper in the libc yet, use the generic syscall wrapper | ||||
|  * available in GNU libc and compatible libc's (eg uClibc). | ||||
|  */ | ||||
| #if defined(__linux__) && defined(__GLIBC__) | ||||
| #include <unistd.h> | ||||
| #include <sys/syscall.h> | ||||
| #if defined(SYS_getrandom) | ||||
| #define HAVE_GETRANDOM | ||||
|  | ||||
| static int getrandom_wrapper( void *buf, size_t buflen, unsigned int flags ) | ||||
| { | ||||
|     /* MemSan cannot understand that the syscall writes to the buffer */ | ||||
| #if defined(__has_feature) | ||||
| #if __has_feature(memory_sanitizer) | ||||
|     memset( buf, 0, buflen ); | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
|     return( syscall( SYS_getrandom, buf, buflen, flags ) ); | ||||
| } | ||||
|  | ||||
| #include <sys/utsname.h> | ||||
| /* Check if version is at least 3.17.0 */ | ||||
| static int check_version_3_17_plus( void ) | ||||
| { | ||||
|     int minor; | ||||
|     struct utsname un; | ||||
|     const char *ver; | ||||
|  | ||||
|     /* Get version information */ | ||||
|     uname(&un); | ||||
|     ver = un.release; | ||||
|  | ||||
|     /* Check major version; assume a single digit */ | ||||
|     if( ver[0] < '3' || ver[0] > '9' || ver [1] != '.' ) | ||||
|         return( -1 ); | ||||
|  | ||||
|     if( ver[0] - '0' > 3 ) | ||||
|         return( 0 ); | ||||
|  | ||||
|     /* Ok, so now we know major == 3, check minor. | ||||
|      * Assume 1 or 2 digits. */ | ||||
|     if( ver[2] < '0' || ver[2] > '9' ) | ||||
|         return( -1 ); | ||||
|  | ||||
|     minor = ver[2] - '0'; | ||||
|  | ||||
|     if( ver[3] >= '0' && ver[3] <= '9' ) | ||||
|         minor = 10 * minor + ver[3] - '0'; | ||||
|     else if( ver [3] != '.' ) | ||||
|         return( -1 ); | ||||
|  | ||||
|     if( minor < 17 ) | ||||
|         return( -1 ); | ||||
|  | ||||
|     return( 0 ); | ||||
| } | ||||
| static int has_getrandom = -1; | ||||
| #endif /* SYS_getrandom */ | ||||
| #endif /* __linux__ */ | ||||
|  | ||||
| #include <stdio.h> | ||||
|  | ||||
| int mbedtls_platform_entropy_poll( void *data, | ||||
|                            unsigned char *output, size_t len, size_t *olen ) | ||||
| { | ||||
|     FILE *file; | ||||
|     size_t read_len; | ||||
|     ((void) data); | ||||
|  | ||||
| #if defined(HAVE_GETRANDOM) | ||||
|     if( has_getrandom == -1 ) | ||||
|         has_getrandom = ( check_version_3_17_plus() == 0 ); | ||||
|  | ||||
|     if( has_getrandom ) | ||||
|     { | ||||
|         int ret; | ||||
|  | ||||
|         if( ( ret = getrandom_wrapper( output, len, 0 ) ) < 0 ) | ||||
|             return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); | ||||
|  | ||||
|         *olen = ret; | ||||
|         return( 0 ); | ||||
|     } | ||||
| #endif /* HAVE_GETRANDOM */ | ||||
|  | ||||
|     *olen = 0; | ||||
|  | ||||
|     file = fopen( "/dev/urandom", "rb" ); | ||||
|     if( file == NULL ) | ||||
|         return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); | ||||
|  | ||||
|     read_len = fread( output, 1, len, file ); | ||||
|     if( read_len != len ) | ||||
|     { | ||||
|         fclose( file ); | ||||
|         return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); | ||||
|     } | ||||
|  | ||||
|     fclose( file ); | ||||
|     *olen = len; | ||||
|  | ||||
|     return( 0 ); | ||||
| } | ||||
| #endif /* _WIN32 && !EFIX64 && !EFI32 */ | ||||
| #endif /* !MBEDTLS_NO_PLATFORM_ENTROPY */ | ||||
|  | ||||
| #if defined(MBEDTLS_TEST_NULL_ENTROPY) | ||||
| int mbedtls_null_entropy_poll( void *data, | ||||
|                     unsigned char *output, size_t len, size_t *olen ) | ||||
| { | ||||
|     ((void) data); | ||||
|     ((void) output); | ||||
|     *olen = 0; | ||||
|  | ||||
|     if( len < sizeof(unsigned char) ) | ||||
|         return( 0 ); | ||||
|  | ||||
|     *olen = sizeof(unsigned char); | ||||
|  | ||||
|     return( 0 ); | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #if defined(MBEDTLS_TIMING_C) | ||||
| int mbedtls_hardclock_poll( void *data, | ||||
|                     unsigned char *output, size_t len, size_t *olen ) | ||||
| { | ||||
|     unsigned long timer = mbedtls_timing_hardclock(); | ||||
|     ((void) data); | ||||
|     *olen = 0; | ||||
|  | ||||
|     if( len < sizeof(unsigned long) ) | ||||
|         return( 0 ); | ||||
|  | ||||
|     memcpy( output, &timer, sizeof(unsigned long) ); | ||||
|     *olen = sizeof(unsigned long); | ||||
|  | ||||
|     return( 0 ); | ||||
| } | ||||
| #endif /* MBEDTLS_TIMING_C */ | ||||
|  | ||||
| #if defined(MBEDTLS_HAVEGE_C) | ||||
| int mbedtls_havege_poll( void *data, | ||||
|                  unsigned char *output, size_t len, size_t *olen ) | ||||
| { | ||||
|     mbedtls_havege_state *hs = (mbedtls_havege_state *) data; | ||||
|     *olen = 0; | ||||
|  | ||||
|     if( mbedtls_havege_random( hs, output, len ) != 0 ) | ||||
|         return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); | ||||
|  | ||||
|     *olen = len; | ||||
|  | ||||
|     return( 0 ); | ||||
| } | ||||
| #endif /* MBEDTLS_HAVEGE_C */ | ||||
|  | ||||
| #if defined(MBEDTLS_ENTROPY_NV_SEED) | ||||
| int mbedtls_nv_seed_poll( void *data, | ||||
|                           unsigned char *output, size_t len, size_t *olen ) | ||||
| { | ||||
|     unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE]; | ||||
|     size_t use_len = MBEDTLS_ENTROPY_BLOCK_SIZE; | ||||
|     ((void) data); | ||||
|  | ||||
|     memset( buf, 0, MBEDTLS_ENTROPY_BLOCK_SIZE ); | ||||
|  | ||||
|     if( mbedtls_nv_seed_read( buf, MBEDTLS_ENTROPY_BLOCK_SIZE ) < 0 ) | ||||
|       return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); | ||||
|  | ||||
|     if( len < use_len ) | ||||
|       use_len = len; | ||||
|  | ||||
|     memcpy( output, buf, use_len ); | ||||
|     *olen = use_len; | ||||
|  | ||||
|     return( 0 ); | ||||
| } | ||||
| #endif /* MBEDTLS_ENTROPY_NV_SEED */ | ||||
|  | ||||
| #endif /* MBEDTLS_ENTROPY_C */ | ||||
| /* | ||||
|  *  Platform-specific and custom entropy polling functions | ||||
|  * | ||||
|  *  Copyright (C) 2006-2016, ARM Limited, All Rights Reserved | ||||
|  *  SPDX-License-Identifier: Apache-2.0 | ||||
|  * | ||||
|  *  Licensed under the Apache License, Version 2.0 (the "License"); you may | ||||
|  *  not use this file except in compliance with the License. | ||||
|  *  You may obtain a copy of the License at | ||||
|  * | ||||
|  *  http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  *  Unless required by applicable law or agreed to in writing, software | ||||
|  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
|  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  *  See the License for the specific language governing permissions and | ||||
|  *  limitations under the License. | ||||
|  * | ||||
|  *  This file is part of mbed TLS (https://tls.mbed.org) | ||||
|  */ | ||||
| #define _GNU_SOURCE | ||||
| #if !defined(MBEDTLS_CONFIG_FILE) | ||||
| #include "mbedtls/config.h" | ||||
| #else | ||||
| #include MBEDTLS_CONFIG_FILE | ||||
| #endif | ||||
|  | ||||
| #if defined(MBEDTLS_ENTROPY_C) | ||||
|  | ||||
| #include "mbedtls/entropy.h" | ||||
| #include "mbedtls/entropy_poll.h" | ||||
|  | ||||
| #if defined(MBEDTLS_TIMING_C) | ||||
| #include <string.h> | ||||
| #include "mbedtls/timing.h" | ||||
| #endif | ||||
| #if defined(MBEDTLS_HAVEGE_C) | ||||
| #include "mbedtls/havege.h" | ||||
| #endif | ||||
| #if defined(MBEDTLS_ENTROPY_NV_SEED) | ||||
| #include "mbedtls/platform.h" | ||||
| #endif | ||||
|  | ||||
| #if !defined(MBEDTLS_NO_PLATFORM_ENTROPY) | ||||
|  | ||||
| #if !defined(unix) && !defined(__unix__) && !defined(__unix) && \ | ||||
|     !defined(__APPLE__) && !defined(_WIN32) | ||||
| #error "Platform entropy sources only work on Unix and Windows, see MBEDTLS_NO_PLATFORM_ENTROPY in config.h" | ||||
| #endif | ||||
|  | ||||
| #if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) | ||||
|  | ||||
| #if !defined(_WIN32_WINNT) | ||||
| #define _WIN32_WINNT 0x0400 | ||||
| #endif | ||||
| #include <windows.h> | ||||
| #include <wincrypt.h> | ||||
|  | ||||
| int mbedtls_platform_entropy_poll( void *data, unsigned char *output, size_t len, | ||||
|                            size_t *olen ) | ||||
| { | ||||
|     HCRYPTPROV provider; | ||||
|     ((void) data); | ||||
|     *olen = 0; | ||||
|  | ||||
|     if( CryptAcquireContext( &provider, NULL, NULL, | ||||
|                               PROV_RSA_FULL, CRYPT_VERIFYCONTEXT ) == FALSE ) | ||||
|     { | ||||
|         return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); | ||||
|     } | ||||
|  | ||||
|     if( CryptGenRandom( provider, (DWORD) len, output ) == FALSE ) | ||||
|     { | ||||
|         CryptReleaseContext( provider, 0 ); | ||||
|         return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); | ||||
|     } | ||||
|  | ||||
|     CryptReleaseContext( provider, 0 ); | ||||
|     *olen = len; | ||||
|  | ||||
|     return( 0 ); | ||||
| } | ||||
| #else /* _WIN32 && !EFIX64 && !EFI32 */ | ||||
|  | ||||
| /* | ||||
|  * Test for Linux getrandom() support. | ||||
|  * Since there is no wrapper in the libc yet, use the generic syscall wrapper | ||||
|  * available in GNU libc and compatible libc's (eg uClibc). | ||||
|  */ | ||||
| #if defined(__linux__) && defined(__GLIBC__) | ||||
| #include <unistd.h> | ||||
| #include <sys/syscall.h> | ||||
| #if defined(SYS_getrandom) | ||||
| #define HAVE_GETRANDOM | ||||
|  | ||||
| static int getrandom_wrapper( void *buf, size_t buflen, unsigned int flags ) | ||||
| { | ||||
|     /* MemSan cannot understand that the syscall writes to the buffer */ | ||||
| #if defined(__has_feature) | ||||
| #if __has_feature(memory_sanitizer) | ||||
|     memset( buf, 0, buflen ); | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
|     return( syscall( SYS_getrandom, buf, buflen, flags ) ); | ||||
| } | ||||
|  | ||||
| #include <sys/utsname.h> | ||||
| /* Check if version is at least 3.17.0 */ | ||||
| static int check_version_3_17_plus( void ) | ||||
| { | ||||
|     int minor; | ||||
|     struct utsname un; | ||||
|     const char *ver; | ||||
|  | ||||
|     /* Get version information */ | ||||
|     uname(&un); | ||||
|     ver = un.release; | ||||
|  | ||||
|     /* Check major version; assume a single digit */ | ||||
|     if( ver[0] < '3' || ver[0] > '9' || ver [1] != '.' ) | ||||
|         return( -1 ); | ||||
|  | ||||
|     if( ver[0] - '0' > 3 ) | ||||
|         return( 0 ); | ||||
|  | ||||
|     /* Ok, so now we know major == 3, check minor. | ||||
|      * Assume 1 or 2 digits. */ | ||||
|     if( ver[2] < '0' || ver[2] > '9' ) | ||||
|         return( -1 ); | ||||
|  | ||||
|     minor = ver[2] - '0'; | ||||
|  | ||||
|     if( ver[3] >= '0' && ver[3] <= '9' ) | ||||
|         minor = 10 * minor + ver[3] - '0'; | ||||
|     else if( ver [3] != '.' ) | ||||
|         return( -1 ); | ||||
|  | ||||
|     if( minor < 17 ) | ||||
|         return( -1 ); | ||||
|  | ||||
|     return( 0 ); | ||||
| } | ||||
| static int has_getrandom = -1; | ||||
| #endif /* SYS_getrandom */ | ||||
| #endif /* __linux__ */ | ||||
|  | ||||
| #include <stdio.h> | ||||
|  | ||||
| int mbedtls_platform_entropy_poll( void *data, | ||||
|                            unsigned char *output, size_t len, size_t *olen ) | ||||
| { | ||||
|     FILE *file; | ||||
|     size_t read_len; | ||||
|     ((void) data); | ||||
|  | ||||
| #if defined(HAVE_GETRANDOM) | ||||
|     if( has_getrandom == -1 ) | ||||
|         has_getrandom = ( check_version_3_17_plus() == 0 ); | ||||
|  | ||||
|     if( has_getrandom ) | ||||
|     { | ||||
|         int ret; | ||||
|  | ||||
|         if( ( ret = getrandom_wrapper( output, len, 0 ) ) < 0 ) | ||||
|             return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); | ||||
|  | ||||
|         *olen = ret; | ||||
|         return( 0 ); | ||||
|     } | ||||
| #endif /* HAVE_GETRANDOM */ | ||||
|  | ||||
|     *olen = 0; | ||||
|  | ||||
|     file = fopen( "/dev/urandom", "rb" ); | ||||
|     if( file == NULL ) | ||||
|         return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); | ||||
|  | ||||
|     read_len = fread( output, 1, len, file ); | ||||
|     if( read_len != len ) | ||||
|     { | ||||
|         fclose( file ); | ||||
|         return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); | ||||
|     } | ||||
|  | ||||
|     fclose( file ); | ||||
|     *olen = len; | ||||
|  | ||||
|     return( 0 ); | ||||
| } | ||||
| #endif /* _WIN32 && !EFIX64 && !EFI32 */ | ||||
| #endif /* !MBEDTLS_NO_PLATFORM_ENTROPY */ | ||||
|  | ||||
| #if defined(MBEDTLS_TEST_NULL_ENTROPY) | ||||
| int mbedtls_null_entropy_poll( void *data, | ||||
|                     unsigned char *output, size_t len, size_t *olen ) | ||||
| { | ||||
|     ((void) data); | ||||
|     ((void) output); | ||||
|     *olen = 0; | ||||
|  | ||||
|     if( len < sizeof(unsigned char) ) | ||||
|         return( 0 ); | ||||
|  | ||||
|     *olen = sizeof(unsigned char); | ||||
|  | ||||
|     return( 0 ); | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #if defined(MBEDTLS_TIMING_C) | ||||
| int mbedtls_hardclock_poll( void *data, | ||||
|                     unsigned char *output, size_t len, size_t *olen ) | ||||
| { | ||||
|     unsigned long timer = mbedtls_timing_hardclock(); | ||||
|     ((void) data); | ||||
|     *olen = 0; | ||||
|  | ||||
|     if( len < sizeof(unsigned long) ) | ||||
|         return( 0 ); | ||||
|  | ||||
|     memcpy( output, &timer, sizeof(unsigned long) ); | ||||
|     *olen = sizeof(unsigned long); | ||||
|  | ||||
|     return( 0 ); | ||||
| } | ||||
| #endif /* MBEDTLS_TIMING_C */ | ||||
|  | ||||
| #if defined(MBEDTLS_HAVEGE_C) | ||||
| int mbedtls_havege_poll( void *data, | ||||
|                  unsigned char *output, size_t len, size_t *olen ) | ||||
| { | ||||
|     mbedtls_havege_state *hs = (mbedtls_havege_state *) data; | ||||
|     *olen = 0; | ||||
|  | ||||
|     if( mbedtls_havege_random( hs, output, len ) != 0 ) | ||||
|         return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); | ||||
|  | ||||
|     *olen = len; | ||||
|  | ||||
|     return( 0 ); | ||||
| } | ||||
| #endif /* MBEDTLS_HAVEGE_C */ | ||||
|  | ||||
| #if defined(MBEDTLS_ENTROPY_NV_SEED) | ||||
| int mbedtls_nv_seed_poll( void *data, | ||||
|                           unsigned char *output, size_t len, size_t *olen ) | ||||
| { | ||||
|     unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE]; | ||||
|     size_t use_len = MBEDTLS_ENTROPY_BLOCK_SIZE; | ||||
|     ((void) data); | ||||
|  | ||||
|     memset( buf, 0, MBEDTLS_ENTROPY_BLOCK_SIZE ); | ||||
|  | ||||
|     if( mbedtls_nv_seed_read( buf, MBEDTLS_ENTROPY_BLOCK_SIZE ) < 0 ) | ||||
|       return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); | ||||
|  | ||||
|     if( len < use_len ) | ||||
|       use_len = len; | ||||
|  | ||||
|     memcpy( output, buf, use_len ); | ||||
|     *olen = use_len; | ||||
|  | ||||
|     return( 0 ); | ||||
| } | ||||
| #endif /* MBEDTLS_ENTROPY_NV_SEED */ | ||||
|  | ||||
| #endif /* MBEDTLS_ENTROPY_C */ | ||||
|  | ||||
| @ -9,6 +9,7 @@ if (platform == Platform.OSX) project.addDefine('KORE_DEBUGDIR="osx-hl"'); | ||||
| if (platform == Platform.iOS) project.addDefine('KORE_DEBUGDIR="ios-hl"'); | ||||
| if (platform !== Platform.Windows || audio !== AudioApi.DirectSound) { | ||||
| 	project.addDefine('KORE_MULTITHREADED_AUDIO'); | ||||
| 	project.addDefine('KINC_MULTITHREADED_AUDIO'); | ||||
| } | ||||
|  | ||||
| project.addDefine('KORE'); | ||||
|  | ||||
| @ -1,31 +1,70 @@ | ||||
| package kha.graphics4; | ||||
|  | ||||
| import kha.Blob; | ||||
|  | ||||
| class FragmentShader { | ||||
| 	public var _shader: Pointer; | ||||
|  | ||||
| 	public function new(sources: Array<Blob>, files: Array<String>) { | ||||
| 		initShader(sources[0]); | ||||
| 	} | ||||
|  | ||||
| 	function initShader(source: Blob): Void { | ||||
| 		_shader = kinc_create_fragmentshader(source.bytes.getData(), source.bytes.getData().length); | ||||
| 	} | ||||
|  | ||||
| 	public static function fromSource(source: String): FragmentShader { | ||||
| 		var sh = new FragmentShader(null, null); | ||||
| 		sh._shader = kinc_fragmentshader_from_source(StringHelper.convert(source)); | ||||
| 		return sh; | ||||
| 	} | ||||
|  | ||||
| 	public function delete(): Void {} | ||||
|  | ||||
| 	@:hlNative("std", "kinc_create_fragmentshader") static function kinc_create_fragmentshader(data: hl.Bytes, length: Int): Pointer { | ||||
| 		return null; | ||||
| 	} | ||||
|  | ||||
| 	@:hlNative("std", "kinc_fragmentshader_from_source") static function kinc_fragmentshader_from_source(source: hl.Bytes): Pointer { | ||||
| 		return null; | ||||
| 	} | ||||
| } | ||||
| package kha.graphics4; | ||||
| using StringTools; | ||||
| import kha.Blob; | ||||
|  | ||||
| class FragmentShader { | ||||
| 	public var _shader: Pointer; | ||||
|  | ||||
| 	public function new(sources: Array<Blob>, files: Array<String>) { | ||||
| 		//initShader(sources[0]); | ||||
| 		var shaderBlob: Blob = null; | ||||
| 		var shaderFile: String = null; | ||||
|  | ||||
| 		#if kha_opengl | ||||
| 		final expectedExtension = ".glsl"; | ||||
| 		#elseif kha_direct3d11 | ||||
| 		final expectedExtension = ".d3d11"; | ||||
| 		#elseif kha_direct3d12 | ||||
| 		final expectedExtension = ".d3d12"; | ||||
| 		#elseif kha_metal | ||||
| 		final expectedExtension = ".metal"; | ||||
| 		#elseif kha_vulkan | ||||
| 		final expectedExtension = ".spirv"; | ||||
| 		#else | ||||
| 		final expectedExtension = ".glsl"; | ||||
| 		#end | ||||
|  | ||||
| 		if (sources != null && files != null) { | ||||
| 			for (i in 0...files.length) { | ||||
| 				if (files[i].endsWith(expectedExtension)) { | ||||
| 					shaderBlob = sources[i]; | ||||
| 					shaderFile = files[i]; | ||||
| 					break; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if (shaderBlob == null && sources != null && sources.length > 0) { | ||||
| 			trace('Warning: Could not find shader with extension ${expectedExtension}. Falling back to sources[0]: ${files != null && files.length > 0 ? files[0] : "Unknown"}'); | ||||
| 			shaderBlob = sources[0]; | ||||
| 		} | ||||
|  | ||||
| 		if (shaderBlob != null) { | ||||
| 			initShader(shaderBlob); | ||||
| 		} else { | ||||
| 			trace('Error: No suitable fragment shader source found!'); | ||||
| 		} | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	function initShader(source: Blob): Void { | ||||
| 		//_shader = kinc_create_fragmentshader(source.bytes.getData(), source.bytes.getData().length); | ||||
| 		_shader = kinc_create_fragmentshader(source.bytes.getData(), source.length); // Use source.length here | ||||
| 	} | ||||
|  | ||||
| 	public static function fromSource(source: String): FragmentShader { | ||||
| 		var sh = new FragmentShader(null, null); | ||||
| 		sh._shader = kinc_fragmentshader_from_source(StringHelper.convert(source)); | ||||
| 		return sh; | ||||
| 	} | ||||
|  | ||||
| 	public function delete(): Void {} | ||||
|  | ||||
| 	@:hlNative("std", "kinc_create_fragmentshader") static function kinc_create_fragmentshader(data: hl.Bytes, length: Int): Pointer { | ||||
| 		return null; | ||||
| 	} | ||||
|  | ||||
| 	@:hlNative("std", "kinc_fragmentshader_from_source") static function kinc_fragmentshader_from_source(source: hl.Bytes): Pointer { | ||||
| 		return null; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -1,179 +1,38 @@ | ||||
| #include <kinc/compute/compute.h> | ||||
| #include <kinc/graphics4/compute.h> | ||||
| #include <kinc/graphics4/texture.h> | ||||
|  | ||||
| #include <hl.h> | ||||
|  | ||||
| vbyte *hl_kinc_compute_create_shader(vbyte *data, int length) { | ||||
| 	kinc_compute_shader_t *shader = (kinc_compute_shader_t *)malloc(sizeof(kinc_compute_shader_t)); | ||||
| 	kinc_compute_shader_init(shader, data, length); | ||||
| 	kinc_g4_compute_shader *shader = (kinc_g4_compute_shader *)malloc(sizeof(kinc_g4_compute_shader)); | ||||
| 	kinc_g4_compute_shader_init(shader, data, length); | ||||
| 	return (vbyte *)shader; | ||||
| } | ||||
|  | ||||
| void hl_kinc_compute_delete_shader(vbyte *shader) { | ||||
| 	kinc_compute_shader_t *sh = (kinc_compute_shader_t *)shader; | ||||
| 	kinc_compute_shader_destroy(sh); | ||||
| 	kinc_g4_compute_shader *sh = (kinc_g4_compute_shader *)shader; | ||||
| 	kinc_g4_compute_shader_destroy(sh); | ||||
| 	free(sh); | ||||
| } | ||||
|  | ||||
| vbyte *hl_kinc_compute_get_constantlocation(vbyte *shader, vbyte *name) { | ||||
| 	kinc_compute_shader_t *sh = (kinc_compute_shader_t *)shader; | ||||
| 	kinc_compute_constant_location_t *location = (kinc_compute_constant_location_t *)malloc(sizeof(kinc_compute_constant_location_t)); | ||||
| 	*location = kinc_compute_shader_get_constant_location(sh, (char *)name), sizeof(kinc_compute_constant_location_t); | ||||
| 	kinc_g4_compute_shader *sh = (kinc_g4_compute_shader *)shader; | ||||
| 	kinc_g4_constant_location_t *location = (kinc_g4_constant_location_t *)malloc(sizeof(kinc_g4_constant_location_t)); | ||||
| 	*location = kinc_g4_compute_shader_get_constant_location(sh, (char *)name); | ||||
| 	return (vbyte *)location; | ||||
| } | ||||
|  | ||||
| vbyte *hl_kinc_compute_get_textureunit(vbyte *shader, vbyte *name) { | ||||
| 	kinc_compute_shader_t *sh = (kinc_compute_shader_t *)shader; | ||||
| 	kinc_compute_texture_unit_t *unit = (kinc_compute_texture_unit_t *)malloc(sizeof(kinc_compute_texture_unit_t)); | ||||
| 	*unit = kinc_compute_shader_get_texture_unit(sh, (char *)name), sizeof(kinc_compute_texture_unit_t); | ||||
| 	kinc_g4_compute_shader *sh = (kinc_g4_compute_shader *)shader; | ||||
| 	kinc_g4_texture_unit_t *unit = (kinc_g4_texture_unit_t *)malloc(sizeof(kinc_g4_texture_unit_t)); | ||||
| 	*unit = kinc_g4_compute_shader_get_texture_unit(sh, (char *)name); | ||||
| 	return (vbyte *)unit; | ||||
| } | ||||
|  | ||||
| void hl_kinc_compute_set_bool(vbyte *location, bool value) { | ||||
| 	kinc_compute_constant_location_t *loc = (kinc_compute_constant_location_t *)location; | ||||
| 	kinc_compute_set_bool(*loc, value); | ||||
| void hl_kinc_set_compute_shader(vbyte *shader) { | ||||
| 	kinc_g4_set_compute_shader((kinc_g4_compute_shader *)shader); | ||||
| } | ||||
|  | ||||
| void hl_kinc_compute_set_int(vbyte *location, int value) { | ||||
| 	kinc_compute_constant_location_t *loc = (kinc_compute_constant_location_t *)location; | ||||
| 	kinc_compute_set_int(*loc, value); | ||||
| } | ||||
|  | ||||
| void hl_kinc_compute_set_float(vbyte *location, float value) { | ||||
| 	kinc_compute_constant_location_t *loc = (kinc_compute_constant_location_t *)location; | ||||
| 	kinc_compute_set_float(*loc, value); | ||||
| } | ||||
|  | ||||
| void hl_kinc_compute_set_float2(vbyte *location, float value1, float value2) { | ||||
| 	kinc_compute_constant_location_t *loc = (kinc_compute_constant_location_t *)location; | ||||
| 	kinc_compute_set_float2(*loc, value1, value2); | ||||
| } | ||||
|  | ||||
| void hl_kinc_compute_set_float3(vbyte *location, float value1, float value2, float value3) { | ||||
| 	kinc_compute_constant_location_t *loc = (kinc_compute_constant_location_t *)location; | ||||
| 	kinc_compute_set_float3(*loc, value1, value2, value3); | ||||
| } | ||||
|  | ||||
| void hl_kinc_compute_set_float4(vbyte *location, float value1, float value2, float value3, float value4) { | ||||
| 	kinc_compute_constant_location_t *loc = (kinc_compute_constant_location_t *)location; | ||||
| 	kinc_compute_set_float4(*loc, value1, value2, value3, value4); | ||||
| } | ||||
|  | ||||
| void hl_kinc_compute_set_floats(vbyte *location, vbyte *values, int count) { | ||||
| 	kinc_compute_constant_location_t *loc = (kinc_compute_constant_location_t *)location; | ||||
| 	kinc_compute_set_floats(*loc, (float *)values, count); | ||||
| } | ||||
|  | ||||
| void hl_kinc_compute_set_matrix(vbyte *location, float _00, float _10, float _20, float _30, float _01, float _11, float _21, float _31, float _02, float _12, | ||||
|                                 float _22, float _32, float _03, float _13, float _23, float _33) { | ||||
| 	kinc_compute_constant_location_t *loc = (kinc_compute_constant_location_t *)location; | ||||
| 	kinc_matrix4x4_t value; | ||||
| 	kinc_matrix4x4_set(&value, 0, 0, _00); | ||||
| 	kinc_matrix4x4_set(&value, 0, 1, _01); | ||||
| 	kinc_matrix4x4_set(&value, 0, 2, _02); | ||||
| 	kinc_matrix4x4_set(&value, 0, 3, _03); | ||||
| 	kinc_matrix4x4_set(&value, 1, 0, _10); | ||||
| 	kinc_matrix4x4_set(&value, 1, 1, _11); | ||||
| 	kinc_matrix4x4_set(&value, 1, 2, _12); | ||||
| 	kinc_matrix4x4_set(&value, 1, 3, _13); | ||||
| 	kinc_matrix4x4_set(&value, 2, 0, _20); | ||||
| 	kinc_matrix4x4_set(&value, 2, 1, _21); | ||||
| 	kinc_matrix4x4_set(&value, 2, 2, _22); | ||||
| 	kinc_matrix4x4_set(&value, 2, 3, _23); | ||||
| 	kinc_matrix4x4_set(&value, 3, 0, _30); | ||||
| 	kinc_matrix4x4_set(&value, 3, 1, _31); | ||||
| 	kinc_matrix4x4_set(&value, 3, 2, _32); | ||||
| 	kinc_matrix4x4_set(&value, 3, 3, _33); | ||||
| 	kinc_compute_set_matrix4(*loc, &value); | ||||
| } | ||||
|  | ||||
| void hl_kinc_compute_set_matrix3(vbyte *location, float _00, float _10, float _20, float _01, float _11, float _21, float _02, float _12, float _22) { | ||||
| 	kinc_compute_constant_location_t *loc = (kinc_compute_constant_location_t *)location; | ||||
| 	kinc_matrix3x3_t value; | ||||
| 	kinc_matrix3x3_set(&value, 0, 0, _00); | ||||
| 	kinc_matrix3x3_set(&value, 0, 1, _01); | ||||
| 	kinc_matrix3x3_set(&value, 0, 2, _02); | ||||
| 	kinc_matrix3x3_set(&value, 1, 0, _10); | ||||
| 	kinc_matrix3x3_set(&value, 1, 1, _11); | ||||
| 	kinc_matrix3x3_set(&value, 1, 2, _12); | ||||
| 	kinc_matrix3x3_set(&value, 2, 0, _20); | ||||
| 	kinc_matrix3x3_set(&value, 2, 1, _21); | ||||
| 	kinc_matrix3x3_set(&value, 2, 2, _22); | ||||
| 	kinc_compute_set_matrix3(*loc, &value); | ||||
| } | ||||
|  | ||||
| void hl_kinc_compute_set_texture(vbyte *unit, vbyte *texture, int access) { | ||||
| 	kinc_compute_texture_unit_t *u = (kinc_compute_texture_unit_t *)unit; | ||||
| 	kinc_g4_texture_t *tex = (kinc_g4_texture_t *)texture; | ||||
| 	kinc_compute_set_texture(*u, tex, (kinc_compute_access_t)access); | ||||
| } | ||||
|  | ||||
| void hl_kinc_compute_set_target(vbyte *unit, vbyte *renderTarget, int access) { | ||||
| 	kinc_compute_texture_unit_t *u = (kinc_compute_texture_unit_t *)unit; | ||||
| 	kinc_g4_render_target_t *rt = (kinc_g4_render_target_t *)renderTarget; | ||||
| 	kinc_compute_set_render_target(*u, rt, (kinc_compute_access_t)access); | ||||
| } | ||||
|  | ||||
| void hl_kinc_compute_set_sampled_texture(vbyte *unit, vbyte *texture) { | ||||
| 	kinc_compute_texture_unit_t *u = (kinc_compute_texture_unit_t *)unit; | ||||
| 	kinc_g4_texture_t *tex = (kinc_g4_texture_t *)texture; | ||||
| 	kinc_compute_set_sampled_texture(*u, tex); | ||||
| } | ||||
|  | ||||
| void hl_kinc_compute_set_sampled_target(vbyte *unit, vbyte *renderTarget) { | ||||
| 	kinc_compute_texture_unit_t *u = (kinc_compute_texture_unit_t *)unit; | ||||
| 	kinc_g4_render_target_t *rt = (kinc_g4_render_target_t *)renderTarget; | ||||
| 	kinc_compute_set_sampled_render_target(*u, rt); | ||||
| } | ||||
|  | ||||
| void hl_kinc_compute_set_sampled_depth_target(vbyte *unit, vbyte *renderTarget) { | ||||
| 	kinc_compute_texture_unit_t *u = (kinc_compute_texture_unit_t *)unit; | ||||
| 	kinc_g4_render_target_t *rt = (kinc_g4_render_target_t *)renderTarget; | ||||
| 	kinc_compute_set_sampled_depth_from_render_target(*u, rt); | ||||
| } | ||||
|  | ||||
| void hl_kinc_compute_set_sampled_cubemap_texture(vbyte *unit, vbyte *texture) { | ||||
| 	kinc_compute_texture_unit_t *u = (kinc_compute_texture_unit_t *)unit; | ||||
| 	kinc_g4_texture_t *tex = (kinc_g4_texture_t *)texture; | ||||
| 	kinc_compute_set_sampled_texture(*u, tex); | ||||
| } | ||||
|  | ||||
| void hl_kinc_compute_set_sampled_cubemap_target(vbyte *unit, vbyte *renderTarget) { | ||||
| 	kinc_compute_texture_unit_t *u = (kinc_compute_texture_unit_t *)unit; | ||||
| 	kinc_g4_render_target_t *rt = (kinc_g4_render_target_t *)renderTarget; | ||||
| 	kinc_compute_set_sampled_render_target(*u, rt); | ||||
| } | ||||
|  | ||||
| void hl_kinc_compute_set_sampled_cubemap_depth_target(vbyte *unit, vbyte *renderTarget) { | ||||
| 	kinc_compute_texture_unit_t *u = (kinc_compute_texture_unit_t *)unit; | ||||
| 	kinc_g4_render_target_t *rt = (kinc_g4_render_target_t *)renderTarget; | ||||
| 	kinc_compute_set_sampled_depth_from_render_target(*u, rt); | ||||
| } | ||||
|  | ||||
| void hl_kinc_compute_set_texture_parameters(vbyte *unit, int uAddressing, int vAddressing, int minificationFilter, int magnificationFilter, int mipmapFilter) { | ||||
| 	kinc_compute_texture_unit_t *u = (kinc_compute_texture_unit_t *)unit; | ||||
| 	kinc_compute_set_texture_addressing(*u, KINC_G4_TEXTURE_DIRECTION_U, (kinc_g4_texture_addressing_t)uAddressing); | ||||
| 	kinc_compute_set_texture_addressing(*u, KINC_G4_TEXTURE_DIRECTION_V, (kinc_g4_texture_addressing_t)vAddressing); | ||||
| 	kinc_compute_set_texture_minification_filter(*u, (kinc_g4_texture_filter_t)minificationFilter); | ||||
| 	kinc_compute_set_texture_magnification_filter(*u, (kinc_g4_texture_filter_t)magnificationFilter); | ||||
| 	kinc_compute_set_texture_mipmap_filter(*u, (kinc_g4_mipmap_filter_t)mipmapFilter); | ||||
| } | ||||
|  | ||||
| void hl_kinc_compute_set_texture3d_parameters(vbyte *unit, int uAddressing, int vAddressing, int wAddressing, int minificationFilter, int magnificationFilter, | ||||
|                                               int mipmapFilter) { | ||||
| 	kinc_compute_texture_unit_t *u = (kinc_compute_texture_unit_t *)unit; | ||||
| 	kinc_compute_set_texture3d_addressing(*u, KINC_G4_TEXTURE_DIRECTION_U, (kinc_g4_texture_addressing_t)uAddressing); | ||||
| 	kinc_compute_set_texture3d_addressing(*u, KINC_G4_TEXTURE_DIRECTION_V, (kinc_g4_texture_addressing_t)vAddressing); | ||||
| 	kinc_compute_set_texture3d_addressing(*u, KINC_G4_TEXTURE_DIRECTION_W, (kinc_g4_texture_addressing_t)wAddressing); | ||||
| 	kinc_compute_set_texture3d_minification_filter(*u, (kinc_g4_texture_filter_t)minificationFilter); | ||||
| 	kinc_compute_set_texture3d_magnification_filter(*u, (kinc_g4_texture_filter_t)magnificationFilter); | ||||
| 	kinc_compute_set_texture3d_mipmap_filter(*u, (kinc_g4_mipmap_filter_t)mipmapFilter); | ||||
| } | ||||
|  | ||||
| void hl_kinc_compute_set_shader(vbyte *shader) { | ||||
| 	kinc_compute_set_shader((kinc_compute_shader_t *)shader); | ||||
| } | ||||
|  | ||||
| void hl_kinc_compute_compute(int x, int y, int z) { | ||||
| 	kinc_compute(x, y, z); | ||||
| void hl_kinc_compute(int x, int y, int z) { | ||||
| 	kinc_g4_compute(x, y, z); | ||||
| } | ||||
|  | ||||
| @ -1,127 +1,129 @@ | ||||
| #include <kinc/audio2/audio.h> | ||||
| #include <kinc/graphics4/graphics.h> | ||||
| #include <kinc/io/filereader.h> | ||||
| #include <kinc/log.h> | ||||
| #include <kinc/system.h> | ||||
| #include <kinc/window.h> | ||||
|  | ||||
| #include <hl.h> | ||||
|  | ||||
| void frame(); | ||||
|  | ||||
| static bool visible = true; | ||||
| static bool paused = false; | ||||
|  | ||||
| typedef void (*FN_AUDIO_CALL_CALLBACK)(int); | ||||
| typedef float (*FN_AUDIO_READ_SAMPLE)(void); | ||||
|  | ||||
| void (*audioCallCallback)(int); | ||||
| float (*audioReadSample)(void); | ||||
|  | ||||
| static void update(void *data) { | ||||
| 	if (paused) { | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	kinc_a2_update(); | ||||
|  | ||||
| 	int windowCount = kinc_count_windows(); | ||||
|  | ||||
| 	for (int windowIndex = 0; windowIndex < windowCount; ++windowIndex) { | ||||
| 		if (visible) { | ||||
| 			kinc_g4_begin(windowIndex); | ||||
| 			frame(); | ||||
| 			kinc_g4_end(windowIndex); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (!kinc_g4_swap_buffers()) { | ||||
| 		kinc_log(KINC_LOG_LEVEL_ERROR, "Graphics context lost."); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static bool mixThreadregistered = false; | ||||
|  | ||||
| static void mix(kinc_a2_buffer_t *buffer, int samples) { | ||||
| #ifdef KORE_MULTITHREADED_AUDIO | ||||
| 	if (!mixThreadregistered) { | ||||
| 		vdynamic *ret; | ||||
| 		hl_register_thread(&ret); | ||||
| 		mixThreadregistered = true; | ||||
| 	} | ||||
| 	hl_blocking(true); | ||||
| #endif | ||||
|  | ||||
| 	audioCallCallback(samples); | ||||
|  | ||||
| 	for (int i = 0; i < samples; ++i) { | ||||
| 		float value = audioReadSample(); | ||||
| 		*(float *)&buffer->data[buffer->write_location] = value; | ||||
| 		buffer->write_location += 4; | ||||
| 		if (buffer->write_location >= buffer->data_size) { | ||||
| 			buffer->write_location = 0; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| #ifdef KORE_MULTITHREADED_AUDIO | ||||
| 	hl_blocking(false); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| void hl_init_kore(vbyte *title, int width, int height, int samplesPerPixel, bool vSync, int windowMode, int windowFeatures) { | ||||
| 	kinc_log(KINC_LOG_LEVEL_INFO, "Starting KincHL"); | ||||
|  | ||||
| 	kinc_window_options_t win; | ||||
| 	kinc_window_options_set_defaults(&win); | ||||
| 	win.title = (char *)title; | ||||
| 	win.width = width; | ||||
| 	win.height = height; | ||||
| 	win.x = -1; | ||||
| 	win.y = -1; | ||||
| 	win.mode = (kinc_window_mode_t)windowMode; | ||||
| 	win.window_features = windowFeatures; | ||||
| 	kinc_framebuffer_options_t frame; | ||||
| 	kinc_framebuffer_options_set_defaults(&frame); | ||||
| 	frame.vertical_sync = vSync; | ||||
| 	frame.samples_per_pixel = samplesPerPixel; | ||||
| 	kinc_init((char *)title, width, height, &win, &frame); | ||||
|  | ||||
| 	kinc_set_update_callback(update, NULL); | ||||
| } | ||||
|  | ||||
| void hl_kinc_init_audio(vclosure *callCallback, vclosure *readSample, int *outSamplesPerSecond) { | ||||
| 	audioCallCallback = *((FN_AUDIO_CALL_CALLBACK *)(&callCallback->fun)); | ||||
| 	audioReadSample = *((FN_AUDIO_READ_SAMPLE *)(&readSample->fun)); | ||||
| 	kinc_a2_set_callback(mix); | ||||
| 	kinc_a2_init(); | ||||
| 	*outSamplesPerSecond = kinc_a2_samples_per_second; | ||||
| } | ||||
|  | ||||
| void hl_run_kore(void) { | ||||
| 	kinc_start(); | ||||
| } | ||||
|  | ||||
| vbyte *hl_kinc_file_contents(vbyte *name, int *size) { | ||||
| 	int len; | ||||
| 	int p = 0; | ||||
| 	vbyte *content; | ||||
| 	kinc_file_reader_t file; | ||||
| 	if (!kinc_file_reader_open(&file, (char *)name, KINC_FILE_TYPE_ASSET)) { | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	hl_blocking(true); | ||||
| 	len = (int)kinc_file_reader_size(&file); | ||||
| 	if (size) { | ||||
| 		*size = len; | ||||
| 	} | ||||
| 	hl_blocking(false); | ||||
| 	content = (vbyte *)hl_gc_alloc_noptr(size ? len : len + 1); | ||||
| 	hl_blocking(true); | ||||
| 	if (!size) { | ||||
| 		content[len] = 0; // final 0 for UTF8 | ||||
| 	} | ||||
| 	kinc_file_reader_read(&file, content, len); | ||||
| 	kinc_file_reader_close(&file); | ||||
| 	hl_blocking(false); | ||||
| 	return content; | ||||
| } | ||||
| #include <kinc/audio2/audio.h> | ||||
| #include <kinc/graphics4/graphics.h> | ||||
| #include <kinc/io/filereader.h> | ||||
| #include <kinc/log.h> | ||||
| #include <kinc/system.h> | ||||
| #include <kinc/window.h> | ||||
|  | ||||
| #include <hl.h> | ||||
|  | ||||
| void frame(); | ||||
|  | ||||
| static bool visible = true; | ||||
| static bool paused = false; | ||||
|  | ||||
| typedef void (*FN_AUDIO_CALL_CALLBACK)(int); | ||||
| typedef float (*FN_AUDIO_READ_SAMPLE)(void); | ||||
|  | ||||
| void (*audioCallCallback)(int); | ||||
| float (*audioReadSample)(void); | ||||
|  | ||||
| static void update(void *data) { | ||||
| 	if (paused) { | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	kinc_a2_update(); | ||||
|  | ||||
| 	int windowCount = kinc_count_windows(); | ||||
|  | ||||
| 	for (int windowIndex = 0; windowIndex < windowCount; ++windowIndex) { | ||||
| 		if (visible) { | ||||
| 			kinc_g4_begin(windowIndex); | ||||
| 			frame(); | ||||
| 			kinc_g4_end(windowIndex); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (!kinc_g4_swap_buffers()) { | ||||
| 		kinc_log(KINC_LOG_LEVEL_ERROR, "Graphics context lost."); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static bool mixThreadregistered = false; | ||||
|  | ||||
| static void mix(kinc_a2_buffer_t *buffer, uint32_t samples, void *userdata) { | ||||
| #ifdef KINC_MULTITHREADED_AUDIO | ||||
| 	if (!mixThreadregistered) { | ||||
| 		vdynamic *ret; | ||||
| 		hl_register_thread(&ret); | ||||
| 		mixThreadregistered = true; | ||||
| 	} | ||||
| 	hl_blocking(true); | ||||
| #endif | ||||
|  | ||||
| 	audioCallCallback(samples); | ||||
|  | ||||
| 	for (uint32_t i = 0; i < samples; i += 2) { | ||||
| 		float left_value = audioReadSample(); | ||||
| 		float right_value = audioReadSample(); | ||||
| 		*(float *)&buffer->channels[0][buffer->write_location] = left_value; | ||||
| 		*(float *)&buffer->channels[1][buffer->write_location] = right_value; | ||||
| 		buffer->write_location += 1; | ||||
| 		if (buffer->write_location >= buffer->data_size) { | ||||
| 			buffer->write_location = 0; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| #ifdef KINC_MULTITHREADED_AUDIO | ||||
| 	hl_blocking(false); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| void hl_init_kore(vbyte *title, int width, int height, int samplesPerPixel, bool vSync, int windowMode, int windowFeatures) { | ||||
| 	kinc_log(KINC_LOG_LEVEL_INFO, "Starting KincHL"); | ||||
|  | ||||
| 	kinc_window_options_t win; | ||||
| 	kinc_window_options_set_defaults(&win); | ||||
| 	win.title = (char *)title; | ||||
| 	win.width = width; | ||||
| 	win.height = height; | ||||
| 	win.x = -1; | ||||
| 	win.y = -1; | ||||
| 	win.mode = (kinc_window_mode_t)windowMode; | ||||
| 	win.window_features = windowFeatures; | ||||
| 	kinc_framebuffer_options_t frame; | ||||
| 	kinc_framebuffer_options_set_defaults(&frame); | ||||
| 	frame.vertical_sync = vSync; | ||||
| 	frame.samples_per_pixel = samplesPerPixel; | ||||
| 	kinc_init((char *)title, width, height, &win, &frame); | ||||
|  | ||||
| 	kinc_set_update_callback(update, NULL); | ||||
| } | ||||
|  | ||||
| void hl_kinc_init_audio(vclosure *callCallback, vclosure *readSample, int *outSamplesPerSecond) { | ||||
| 	audioCallCallback = *((FN_AUDIO_CALL_CALLBACK *)(&callCallback->fun)); | ||||
| 	audioReadSample = *((FN_AUDIO_READ_SAMPLE *)(&readSample->fun)); | ||||
| 	kinc_a2_init(); | ||||
| 	kinc_a2_set_callback(mix, NULL); | ||||
| 	*outSamplesPerSecond = kinc_a2_samples_per_second(); | ||||
| } | ||||
|  | ||||
| void hl_run_kore(void) { | ||||
| 	kinc_start(); | ||||
| } | ||||
|  | ||||
| vbyte *hl_kinc_file_contents(vbyte *name, int *size) { | ||||
| 	int len; | ||||
| 	int p = 0; | ||||
| 	vbyte *content; | ||||
| 	kinc_file_reader_t file; | ||||
| 	if (!kinc_file_reader_open(&file, (char *)name, KINC_FILE_TYPE_ASSET)) { | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	hl_blocking(true); | ||||
| 	len = (int)kinc_file_reader_size(&file); | ||||
| 	if (size) { | ||||
| 		*size = len; | ||||
| 	} | ||||
| 	hl_blocking(false); | ||||
| 	content = (vbyte *)hl_gc_alloc_noptr(size ? len : len + 1); | ||||
| 	hl_blocking(true); | ||||
| 	if (!size) { | ||||
| 		content[len] = 0; // final 0 for UTF8 | ||||
| 	} | ||||
| 	kinc_file_reader_read(&file, content, len); | ||||
| 	kinc_file_reader_close(&file); | ||||
| 	hl_blocking(false); | ||||
| 	return content; | ||||
| } | ||||
|  | ||||
| @ -1,265 +1,265 @@ | ||||
| #include <kinc/graphics4/graphics.h> | ||||
| #include <kinc/graphics4/pipeline.h> | ||||
| #include <kinc/graphics4/shader.h> | ||||
| #include <kinc/graphics4/vertexstructure.h> | ||||
|  | ||||
| #include <hl.h> | ||||
|  | ||||
| static kinc_g4_compare_mode_t convertCompareMode(int mode) { | ||||
| 	switch (mode) { | ||||
| 	case 0: | ||||
| 		return KINC_G4_COMPARE_ALWAYS; | ||||
| 	case 1: | ||||
| 		return KINC_G4_COMPARE_NEVER; | ||||
| 	case 2: | ||||
| 		return KINC_G4_COMPARE_EQUAL; | ||||
| 	case 3: | ||||
| 		return KINC_G4_COMPARE_NOT_EQUAL; | ||||
| 	case 4: | ||||
| 		return KINC_G4_COMPARE_LESS; | ||||
| 	case 5: | ||||
| 		return KINC_G4_COMPARE_LESS_EQUAL; | ||||
| 	case 6: | ||||
| 		return KINC_G4_COMPARE_GREATER; | ||||
| 	case 7: | ||||
| 	default: | ||||
| 		return KINC_G4_COMPARE_GREATER_EQUAL; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static kinc_g4_stencil_action_t convertStencilAction(int action) { | ||||
| 	switch (action) { | ||||
| 	case 0: | ||||
| 		return KINC_G4_STENCIL_KEEP; | ||||
| 	case 1: | ||||
| 		return KINC_G4_STENCIL_ZERO; | ||||
| 	case 2: | ||||
| 		return KINC_G4_STENCIL_REPLACE; | ||||
| 	case 3: | ||||
| 		return KINC_G4_STENCIL_INCREMENT; | ||||
| 	case 4: | ||||
| 		return KINC_G4_STENCIL_INCREMENT_WRAP; | ||||
| 	case 5: | ||||
| 		return KINC_G4_STENCIL_DECREMENT; | ||||
| 	case 6: | ||||
| 		return KINC_G4_STENCIL_DECREMENT_WRAP; | ||||
| 	case 7: | ||||
| 	default: | ||||
| 		return KINC_G4_STENCIL_INVERT; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static kinc_g4_render_target_format_t convertColorAttachment(int format) { | ||||
| 	switch (format) { | ||||
| 	case 0: | ||||
| 		return KINC_G4_RENDER_TARGET_FORMAT_32BIT; | ||||
| 	case 1: | ||||
| 		return KINC_G4_RENDER_TARGET_FORMAT_8BIT_RED; | ||||
| 	case 2: | ||||
| 		return KINC_G4_RENDER_TARGET_FORMAT_128BIT_FLOAT; | ||||
| 	case 3: | ||||
| 		return KINC_G4_RENDER_TARGET_FORMAT_16BIT_DEPTH; | ||||
| 	case 4: | ||||
| 		return KINC_G4_RENDER_TARGET_FORMAT_64BIT_FLOAT; | ||||
| 	case 5: | ||||
| 		return KINC_G4_RENDER_TARGET_FORMAT_32BIT_RED_FLOAT; | ||||
| 	case 6: | ||||
| 	default: | ||||
| 		return KINC_G4_RENDER_TARGET_FORMAT_16BIT_RED_FLOAT; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| vbyte *hl_kinc_create_vertexshader(vbyte *data, int length) { | ||||
| 	kinc_g4_shader_t *shader = (kinc_g4_shader_t *)malloc(sizeof(kinc_g4_shader_t)); | ||||
| 	kinc_g4_shader_init(shader, data, length, KINC_G4_SHADER_TYPE_VERTEX); | ||||
| 	return (vbyte *)shader; | ||||
| } | ||||
|  | ||||
| vbyte *hl_kinc_create_fragmentshader(vbyte *data, int length) { | ||||
| 	kinc_g4_shader_t *shader = (kinc_g4_shader_t *)malloc(sizeof(kinc_g4_shader_t)); | ||||
| 	kinc_g4_shader_init(shader, data, length, KINC_G4_SHADER_TYPE_FRAGMENT); | ||||
| 	return (vbyte *)shader; | ||||
| } | ||||
|  | ||||
| vbyte *hl_kinc_create_geometryshader(vbyte *data, int length) { | ||||
| 	kinc_g4_shader_t *shader = (kinc_g4_shader_t *)malloc(sizeof(kinc_g4_shader_t)); | ||||
| 	kinc_g4_shader_init(shader, data, length, KINC_G4_SHADER_TYPE_GEOMETRY); | ||||
| 	return (vbyte *)shader; | ||||
| } | ||||
|  | ||||
| vbyte *hl_kinc_create_tesscontrolshader(vbyte *data, int length) { | ||||
| 	kinc_g4_shader_t *shader = (kinc_g4_shader_t *)malloc(sizeof(kinc_g4_shader_t)); | ||||
| 	kinc_g4_shader_init(shader, data, length, KINC_G4_SHADER_TYPE_TESSELLATION_CONTROL); | ||||
| 	return (vbyte *)shader; | ||||
| } | ||||
|  | ||||
| vbyte *hl_kinc_create_tessevalshader(vbyte *data, int length) { | ||||
| 	kinc_g4_shader_t *shader = (kinc_g4_shader_t *)malloc(sizeof(kinc_g4_shader_t)); | ||||
| 	kinc_g4_shader_init(shader, data, length, KINC_G4_SHADER_TYPE_TESSELLATION_EVALUATION); | ||||
| 	return (vbyte *)shader; | ||||
| } | ||||
|  | ||||
| vbyte *hl_kinc_vertexshader_from_source(vbyte *source) { | ||||
| 	kinc_g4_shader_t *shader = (kinc_g4_shader_t *)malloc(sizeof(kinc_g4_shader_t)); | ||||
| 	kinc_g4_shader_init_from_source(shader, (char *)source, KINC_G4_SHADER_TYPE_VERTEX); | ||||
| 	return (vbyte *)shader; | ||||
| } | ||||
|  | ||||
| vbyte *hl_kinc_fragmentshader_from_source(vbyte *source) { | ||||
| 	kinc_g4_shader_t *shader = (kinc_g4_shader_t *)malloc(sizeof(kinc_g4_shader_t)); | ||||
| 	kinc_g4_shader_init_from_source(shader, (char *)source, KINC_G4_SHADER_TYPE_FRAGMENT); | ||||
| 	return (vbyte *)shader; | ||||
| } | ||||
|  | ||||
| vbyte *hl_kinc_geometryshader_from_source(vbyte *source) { | ||||
| 	kinc_g4_shader_t *shader = (kinc_g4_shader_t *)malloc(sizeof(kinc_g4_shader_t)); | ||||
| 	kinc_g4_shader_init_from_source(shader, (char *)source, KINC_G4_SHADER_TYPE_GEOMETRY); | ||||
| 	return (vbyte *)shader; | ||||
| } | ||||
|  | ||||
| vbyte *hl_kinc_tesscontrolshader_from_source(vbyte *source) { | ||||
| 	kinc_g4_shader_t *shader = (kinc_g4_shader_t *)malloc(sizeof(kinc_g4_shader_t)); | ||||
| 	kinc_g4_shader_init_from_source(shader, (char *)source, KINC_G4_SHADER_TYPE_TESSELLATION_CONTROL); | ||||
| 	return (vbyte *)shader; | ||||
| } | ||||
|  | ||||
| vbyte *hl_kinc_tessevalshader_from_source(vbyte *source) { | ||||
| 	kinc_g4_shader_t *shader = (kinc_g4_shader_t *)malloc(sizeof(kinc_g4_shader_t)); | ||||
| 	kinc_g4_shader_init_from_source(shader, (char *)source, KINC_G4_SHADER_TYPE_TESSELLATION_EVALUATION); | ||||
| 	return (vbyte *)shader; | ||||
| } | ||||
|  | ||||
| vbyte *hl_kinc_create_pipeline() { | ||||
| 	kinc_g4_pipeline_t *pipeline = (kinc_g4_pipeline_t *)malloc(sizeof(kinc_g4_pipeline_t)); | ||||
| 	kinc_g4_pipeline_init(pipeline); | ||||
| 	return (vbyte *)pipeline; | ||||
| } | ||||
|  | ||||
| void hl_kinc_delete_pipeline(vbyte *pipeline) { | ||||
| 	kinc_g4_pipeline_t *pipe = (kinc_g4_pipeline_t *)pipeline; | ||||
| 	kinc_g4_pipeline_destroy(pipe); | ||||
| 	free(pipe); | ||||
| } | ||||
|  | ||||
| void hl_kinc_pipeline_set_vertex_shader(vbyte *pipeline, vbyte *shader) { | ||||
| 	kinc_g4_pipeline_t *pipe = (kinc_g4_pipeline_t *)pipeline; | ||||
| 	kinc_g4_shader_t *sh = (kinc_g4_shader_t *)shader; | ||||
| 	pipe->vertex_shader = sh; | ||||
| } | ||||
|  | ||||
| void hl_kinc_pipeline_set_fragment_shader(vbyte *pipeline, vbyte *shader) { | ||||
| 	kinc_g4_pipeline_t *pipe = (kinc_g4_pipeline_t *)pipeline; | ||||
| 	kinc_g4_shader_t *sh = (kinc_g4_shader_t *)shader; | ||||
| 	pipe->fragment_shader = sh; | ||||
| } | ||||
|  | ||||
| void hl_kinc_pipeline_set_geometry_shader(vbyte *pipeline, vbyte *shader) { | ||||
| 	kinc_g4_pipeline_t *pipe = (kinc_g4_pipeline_t *)pipeline; | ||||
| 	kinc_g4_shader_t *sh = (kinc_g4_shader_t *)shader; | ||||
| 	pipe->geometry_shader = sh; | ||||
| } | ||||
|  | ||||
| void hl_kinc_pipeline_set_tesscontrol_shader(vbyte *pipeline, vbyte *shader) { | ||||
| 	kinc_g4_pipeline_t *pipe = (kinc_g4_pipeline_t *)pipeline; | ||||
| 	kinc_g4_shader_t *sh = (kinc_g4_shader_t *)shader; | ||||
| 	pipe->tessellation_control_shader = sh; | ||||
| } | ||||
|  | ||||
| void hl_kinc_pipeline_set_tesseval_shader(vbyte *pipeline, vbyte *shader) { | ||||
| 	kinc_g4_pipeline_t *pipe = (kinc_g4_pipeline_t *)pipeline; | ||||
| 	kinc_g4_shader_t *sh = (kinc_g4_shader_t *)shader; | ||||
| 	pipe->tessellation_evaluation_shader = sh; | ||||
| } | ||||
|  | ||||
| void hl_kinc_pipeline_compile(vbyte *pipeline, vbyte *structure0, vbyte *structure1, vbyte *structure2, vbyte *structure3) { | ||||
| 	kinc_g4_pipeline_t *pipe = (kinc_g4_pipeline_t *)pipeline; | ||||
| 	pipe->input_layout[0] = (kinc_g4_vertex_structure_t *)structure0; | ||||
| 	pipe->input_layout[1] = (kinc_g4_vertex_structure_t *)structure1; | ||||
| 	pipe->input_layout[2] = (kinc_g4_vertex_structure_t *)structure2; | ||||
| 	pipe->input_layout[3] = (kinc_g4_vertex_structure_t *)structure3; | ||||
| 	pipe->input_layout[4] = NULL; | ||||
| 	kinc_g4_pipeline_compile(pipe); | ||||
| } | ||||
|  | ||||
| void hl_kinc_pipeline_set_states(vbyte *pipeline, int cullMode, int depthMode, int stencilFrontMode, int stencilFrontBothPass, int stencilFrontDepthFail, | ||||
|                                  int stencilFrontFail, int stencilBackMode, int stencilBackBothPass, int stencilBackDepthFail, int stencilBackFail, | ||||
|                                  int blendSource, int blendDestination, int alphaBlendSource, int alphaBlendDestination, bool depthWrite, | ||||
|                                  int stencilReferenceValue, int stencilReadMask, int stencilWriteMask, bool colorWriteMaskRed, bool colorWriteMaskGreen, | ||||
|                                  bool colorWriteMaskBlue, bool colorWriteMaskAlpha, int colorAttachmentCount, int colorAttachment0, int colorAttachment1, | ||||
|                                  int colorAttachment2, int colorAttachment3, int colorAttachment4, int colorAttachment5, int colorAttachment6, | ||||
|                                  int colorAttachment7, int depthAttachmentBits, int stencilAttachmentBits, bool conservativeRasterization) { | ||||
| 	kinc_g4_pipeline_t *pipe = (kinc_g4_pipeline_t *)pipeline; | ||||
|  | ||||
| 	switch (cullMode) { | ||||
| 	case 0: | ||||
| 		pipe->cull_mode = KINC_G4_CULL_CLOCKWISE; | ||||
| 		break; | ||||
| 	case 1: | ||||
| 		pipe->cull_mode = KINC_G4_CULL_COUNTER_CLOCKWISE; | ||||
| 		break; | ||||
| 	case 2: | ||||
| 		pipe->cull_mode = KINC_G4_CULL_NOTHING; | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| 	pipe->depth_mode = convertCompareMode(depthMode); | ||||
| 	pipe->depth_write = depthWrite; | ||||
|  | ||||
| 	pipe->stencil_front_mode = convertCompareMode(stencilFrontMode); | ||||
| 	pipe->stencil_front_both_pass = convertStencilAction(stencilFrontBothPass); | ||||
| 	pipe->stencil_front_depth_fail = convertStencilAction(stencilFrontDepthFail); | ||||
| 	pipe->stencil_front_fail = convertStencilAction(stencilFrontFail); | ||||
|  | ||||
| 	pipe->stencil_back_mode = convertCompareMode(stencilBackMode); | ||||
| 	pipe->stencil_back_both_pass = convertStencilAction(stencilBackBothPass); | ||||
| 	pipe->stencil_back_depth_fail = convertStencilAction(stencilBackDepthFail); | ||||
| 	pipe->stencil_back_fail = convertStencilAction(stencilBackFail); | ||||
|  | ||||
| 	pipe->stencil_reference_value = stencilReferenceValue; | ||||
| 	pipe->stencil_read_mask = stencilReadMask; | ||||
| 	pipe->stencil_write_mask = stencilWriteMask; | ||||
|  | ||||
| 	pipe->blend_source = (kinc_g4_blending_factor_t)blendSource; | ||||
| 	pipe->blend_destination = (kinc_g4_blending_factor_t)blendDestination; | ||||
| 	pipe->alpha_blend_source = (kinc_g4_blending_factor_t)alphaBlendSource; | ||||
| 	pipe->alpha_blend_destination = (kinc_g4_blending_factor_t)alphaBlendDestination; | ||||
|  | ||||
| 	pipe->color_write_mask_red[0] = colorWriteMaskRed; | ||||
| 	pipe->color_write_mask_green[0] = colorWriteMaskGreen; | ||||
| 	pipe->color_write_mask_blue[0] = colorWriteMaskBlue; | ||||
| 	pipe->color_write_mask_alpha[0] = colorWriteMaskAlpha; | ||||
|  | ||||
| 	pipe->color_attachment_count = colorAttachmentCount; | ||||
| 	pipe->color_attachment[0] = convertColorAttachment(colorAttachment0); | ||||
| 	pipe->color_attachment[1] = convertColorAttachment(colorAttachment1); | ||||
| 	pipe->color_attachment[2] = convertColorAttachment(colorAttachment2); | ||||
| 	pipe->color_attachment[3] = convertColorAttachment(colorAttachment3); | ||||
| 	pipe->color_attachment[4] = convertColorAttachment(colorAttachment4); | ||||
| 	pipe->color_attachment[5] = convertColorAttachment(colorAttachment5); | ||||
| 	pipe->color_attachment[6] = convertColorAttachment(colorAttachment6); | ||||
| 	pipe->color_attachment[7] = convertColorAttachment(colorAttachment7); | ||||
|  | ||||
| 	pipe->depth_attachment_bits = depthAttachmentBits; | ||||
| 	pipe->stencil_attachment_bits = stencilAttachmentBits; | ||||
|  | ||||
| 	pipe->conservative_rasterization = conservativeRasterization; | ||||
| } | ||||
|  | ||||
| void hl_kinc_pipeline_set(vbyte *pipeline) { | ||||
| 	kinc_g4_pipeline_t *pipe = (kinc_g4_pipeline_t *)pipeline; | ||||
| 	kinc_g4_set_pipeline(pipe); | ||||
| } | ||||
|  | ||||
| vbyte *hl_kinc_pipeline_get_constantlocation(vbyte *pipeline, vbyte *name) { | ||||
| 	kinc_g4_pipeline_t *pipe = (kinc_g4_pipeline_t *)pipeline; | ||||
| 	kinc_g4_constant_location_t *location = (kinc_g4_constant_location_t *)malloc(sizeof(kinc_g4_constant_location_t)); | ||||
| 	*location = kinc_g4_pipeline_get_constant_location(pipe, (char *)name); | ||||
| 	return (vbyte *)location; | ||||
| } | ||||
|  | ||||
| vbyte *hl_kinc_pipeline_get_textureunit(vbyte *pipeline, vbyte *name) { | ||||
| 	kinc_g4_pipeline_t *pipe = (kinc_g4_pipeline_t *)pipeline; | ||||
| 	kinc_g4_texture_unit_t *unit = (kinc_g4_texture_unit_t *)malloc(sizeof(kinc_g4_texture_unit_t)); | ||||
| 	*unit = kinc_g4_pipeline_get_texture_unit(pipe, (char *)name); | ||||
| 	return (vbyte *)unit; | ||||
| } | ||||
| #include <kinc/graphics4/graphics.h> | ||||
| #include <kinc/graphics4/pipeline.h> | ||||
| #include <kinc/graphics4/shader.h> | ||||
| #include <kinc/graphics4/vertexstructure.h> | ||||
|  | ||||
| #include <hl.h> | ||||
|  | ||||
| static kinc_g4_compare_mode_t convertCompareMode(int mode) { | ||||
| 	switch (mode) { | ||||
| 	case 0: | ||||
| 		return KINC_G4_COMPARE_ALWAYS; | ||||
| 	case 1: | ||||
| 		return KINC_G4_COMPARE_NEVER; | ||||
| 	case 2: | ||||
| 		return KINC_G4_COMPARE_EQUAL; | ||||
| 	case 3: | ||||
| 		return KINC_G4_COMPARE_NOT_EQUAL; | ||||
| 	case 4: | ||||
| 		return KINC_G4_COMPARE_LESS; | ||||
| 	case 5: | ||||
| 		return KINC_G4_COMPARE_LESS_EQUAL; | ||||
| 	case 6: | ||||
| 		return KINC_G4_COMPARE_GREATER; | ||||
| 	case 7: | ||||
| 	default: | ||||
| 		return KINC_G4_COMPARE_GREATER_EQUAL; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static kinc_g4_stencil_action_t convertStencilAction(int action) { | ||||
| 	switch (action) { | ||||
| 	case 0: | ||||
| 		return KINC_G4_STENCIL_KEEP; | ||||
| 	case 1: | ||||
| 		return KINC_G4_STENCIL_ZERO; | ||||
| 	case 2: | ||||
| 		return KINC_G4_STENCIL_REPLACE; | ||||
| 	case 3: | ||||
| 		return KINC_G4_STENCIL_INCREMENT; | ||||
| 	case 4: | ||||
| 		return KINC_G4_STENCIL_INCREMENT_WRAP; | ||||
| 	case 5: | ||||
| 		return KINC_G4_STENCIL_DECREMENT; | ||||
| 	case 6: | ||||
| 		return KINC_G4_STENCIL_DECREMENT_WRAP; | ||||
| 	case 7: | ||||
| 	default: | ||||
| 		return KINC_G4_STENCIL_INVERT; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static kinc_g4_render_target_format_t convertColorAttachment(int format) { | ||||
| 	switch (format) { | ||||
| 	case 0: | ||||
| 		return KINC_G4_RENDER_TARGET_FORMAT_32BIT; | ||||
| 	case 1: | ||||
| 		return KINC_G4_RENDER_TARGET_FORMAT_8BIT_RED; | ||||
| 	case 2: | ||||
| 		return KINC_G4_RENDER_TARGET_FORMAT_128BIT_FLOAT; | ||||
| 	case 3: | ||||
| 		return KINC_G4_RENDER_TARGET_FORMAT_16BIT_DEPTH; | ||||
| 	case 4: | ||||
| 		return KINC_G4_RENDER_TARGET_FORMAT_64BIT_FLOAT; | ||||
| 	case 5: | ||||
| 		return KINC_G4_RENDER_TARGET_FORMAT_32BIT_RED_FLOAT; | ||||
| 	case 6: | ||||
| 	default: | ||||
| 		return KINC_G4_RENDER_TARGET_FORMAT_16BIT_RED_FLOAT; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| vbyte *hl_kinc_create_vertexshader(vbyte *data, int length) { | ||||
| 	kinc_g4_shader_t *shader = (kinc_g4_shader_t *)malloc(sizeof(kinc_g4_shader_t)); | ||||
| 	kinc_g4_shader_init(shader, data, length, KINC_G4_SHADER_TYPE_VERTEX); | ||||
| 	return (vbyte *)shader; | ||||
| } | ||||
|  | ||||
| vbyte *hl_kinc_create_fragmentshader(vbyte *data, int length) { | ||||
| 	kinc_g4_shader_t *shader = (kinc_g4_shader_t *)malloc(sizeof(kinc_g4_shader_t)); | ||||
| 	kinc_g4_shader_init(shader, data, length, KINC_G4_SHADER_TYPE_FRAGMENT); | ||||
| 	return (vbyte *)shader; | ||||
| } | ||||
|  | ||||
| vbyte *hl_kinc_create_geometryshader(vbyte *data, int length) { | ||||
| 	kinc_g4_shader_t *shader = (kinc_g4_shader_t *)malloc(sizeof(kinc_g4_shader_t)); | ||||
| 	kinc_g4_shader_init(shader, data, length, KINC_G4_SHADER_TYPE_GEOMETRY); | ||||
| 	return (vbyte *)shader; | ||||
| } | ||||
|  | ||||
| vbyte *hl_kinc_create_tesscontrolshader(vbyte *data, int length) { | ||||
| 	kinc_g4_shader_t *shader = (kinc_g4_shader_t *)malloc(sizeof(kinc_g4_shader_t)); | ||||
| 	kinc_g4_shader_init(shader, data, length, KINC_G4_SHADER_TYPE_TESSELLATION_CONTROL); | ||||
| 	return (vbyte *)shader; | ||||
| } | ||||
|  | ||||
| vbyte *hl_kinc_create_tessevalshader(vbyte *data, int length) { | ||||
| 	kinc_g4_shader_t *shader = (kinc_g4_shader_t *)malloc(sizeof(kinc_g4_shader_t)); | ||||
| 	kinc_g4_shader_init(shader, data, length, KINC_G4_SHADER_TYPE_TESSELLATION_EVALUATION); | ||||
| 	return (vbyte *)shader; | ||||
| } | ||||
|  | ||||
| vbyte *hl_kinc_vertexshader_from_source(vbyte *source) { | ||||
| 	kinc_g4_shader_t *shader = (kinc_g4_shader_t *)malloc(sizeof(kinc_g4_shader_t)); | ||||
| 	kinc_g4_shader_init_from_source(shader, (char *)source, KINC_G4_SHADER_TYPE_VERTEX); | ||||
| 	return (vbyte *)shader; | ||||
| } | ||||
|  | ||||
| vbyte *hl_kinc_fragmentshader_from_source(vbyte *source) { | ||||
| 	kinc_g4_shader_t *shader = (kinc_g4_shader_t *)malloc(sizeof(kinc_g4_shader_t)); | ||||
| 	kinc_g4_shader_init_from_source(shader, (char *)source, KINC_G4_SHADER_TYPE_FRAGMENT); | ||||
| 	return (vbyte *)shader; | ||||
| } | ||||
|  | ||||
| vbyte *hl_kinc_geometryshader_from_source(vbyte *source) { | ||||
| 	kinc_g4_shader_t *shader = (kinc_g4_shader_t *)malloc(sizeof(kinc_g4_shader_t)); | ||||
| 	kinc_g4_shader_init_from_source(shader, (char *)source, KINC_G4_SHADER_TYPE_GEOMETRY); | ||||
| 	return (vbyte *)shader; | ||||
| } | ||||
|  | ||||
| vbyte *hl_kinc_tesscontrolshader_from_source(vbyte *source) { | ||||
| 	kinc_g4_shader_t *shader = (kinc_g4_shader_t *)malloc(sizeof(kinc_g4_shader_t)); | ||||
| 	kinc_g4_shader_init_from_source(shader, (char *)source, KINC_G4_SHADER_TYPE_TESSELLATION_CONTROL); | ||||
| 	return (vbyte *)shader; | ||||
| } | ||||
|  | ||||
| vbyte *hl_kinc_tessevalshader_from_source(vbyte *source) { | ||||
| 	kinc_g4_shader_t *shader = (kinc_g4_shader_t *)malloc(sizeof(kinc_g4_shader_t)); | ||||
| 	kinc_g4_shader_init_from_source(shader, (char *)source, KINC_G4_SHADER_TYPE_TESSELLATION_EVALUATION); | ||||
| 	return (vbyte *)shader; | ||||
| } | ||||
|  | ||||
| vbyte *hl_kinc_create_pipeline() { | ||||
| 	kinc_g4_pipeline_t *pipeline = (kinc_g4_pipeline_t *)malloc(sizeof(kinc_g4_pipeline_t)); | ||||
| 	kinc_g4_pipeline_init(pipeline); | ||||
| 	return (vbyte *)pipeline; | ||||
| } | ||||
|  | ||||
| void hl_kinc_delete_pipeline(vbyte *pipeline) { | ||||
| 	kinc_g4_pipeline_t *pipe = (kinc_g4_pipeline_t *)pipeline; | ||||
| 	kinc_g4_pipeline_destroy(pipe); | ||||
| 	free(pipe); | ||||
| } | ||||
|  | ||||
| void hl_kinc_pipeline_set_vertex_shader(vbyte *pipeline, vbyte *shader) { | ||||
| 	kinc_g4_pipeline_t *pipe = (kinc_g4_pipeline_t *)pipeline; | ||||
| 	kinc_g4_shader_t *sh = (kinc_g4_shader_t *)shader; | ||||
| 	pipe->vertex_shader = sh; | ||||
| } | ||||
|  | ||||
| void hl_kinc_pipeline_set_fragment_shader(vbyte *pipeline, vbyte *shader) { | ||||
| 	kinc_g4_pipeline_t *pipe = (kinc_g4_pipeline_t *)pipeline; | ||||
| 	kinc_g4_shader_t *sh = (kinc_g4_shader_t *)shader; | ||||
| 	pipe->fragment_shader = sh; | ||||
| } | ||||
|  | ||||
| void hl_kinc_pipeline_set_geometry_shader(vbyte *pipeline, vbyte *shader) { | ||||
| 	kinc_g4_pipeline_t *pipe = (kinc_g4_pipeline_t *)pipeline; | ||||
| 	kinc_g4_shader_t *sh = (kinc_g4_shader_t *)shader; | ||||
| 	pipe->geometry_shader = sh; | ||||
| } | ||||
|  | ||||
| void hl_kinc_pipeline_set_tesscontrol_shader(vbyte *pipeline, vbyte *shader) { | ||||
| 	kinc_g4_pipeline_t *pipe = (kinc_g4_pipeline_t *)pipeline; | ||||
| 	kinc_g4_shader_t *sh = (kinc_g4_shader_t *)shader; | ||||
| 	pipe->tessellation_control_shader = sh; | ||||
| } | ||||
|  | ||||
| void hl_kinc_pipeline_set_tesseval_shader(vbyte *pipeline, vbyte *shader) { | ||||
| 	kinc_g4_pipeline_t *pipe = (kinc_g4_pipeline_t *)pipeline; | ||||
| 	kinc_g4_shader_t *sh = (kinc_g4_shader_t *)shader; | ||||
| 	pipe->tessellation_evaluation_shader = sh; | ||||
| } | ||||
|  | ||||
| void hl_kinc_pipeline_compile(vbyte *pipeline, vbyte *structure0, vbyte *structure1, vbyte *structure2, vbyte *structure3) { | ||||
| 	kinc_g4_pipeline_t *pipe = (kinc_g4_pipeline_t *)pipeline; | ||||
| 	pipe->input_layout[0] = (kinc_g4_vertex_structure_t *)structure0; | ||||
| 	pipe->input_layout[1] = (kinc_g4_vertex_structure_t *)structure1; | ||||
| 	pipe->input_layout[2] = (kinc_g4_vertex_structure_t *)structure2; | ||||
| 	pipe->input_layout[3] = (kinc_g4_vertex_structure_t *)structure3; | ||||
| 	pipe->input_layout[4] = NULL; | ||||
| 	kinc_g4_pipeline_compile(pipe); | ||||
| } | ||||
|  | ||||
| void hl_kinc_pipeline_set_states(vbyte *pipeline, int cullMode, int depthMode, int stencilFrontMode, int stencilFrontBothPass, int stencilFrontDepthFail, | ||||
|                                  int stencilFrontFail, int stencilBackMode, int stencilBackBothPass, int stencilBackDepthFail, int stencilBackFail, | ||||
|                                  int blendSource, int blendDestination, int alphaBlendSource, int alphaBlendDestination, bool depthWrite, | ||||
|                                  int stencilReferenceValue, int stencilReadMask, int stencilWriteMask, bool colorWriteMaskRed, bool colorWriteMaskGreen, | ||||
|                                  bool colorWriteMaskBlue, bool colorWriteMaskAlpha, int colorAttachmentCount, int colorAttachment0, int colorAttachment1, | ||||
|                                  int colorAttachment2, int colorAttachment3, int colorAttachment4, int colorAttachment5, int colorAttachment6, | ||||
|                                  int colorAttachment7, int depthAttachmentBits, int stencilAttachmentBits, bool conservativeRasterization) { | ||||
| 	kinc_g4_pipeline_t *pipe = (kinc_g4_pipeline_t *)pipeline; | ||||
|  | ||||
| 	switch (cullMode) { | ||||
| 	case 0: | ||||
| 		pipe->cull_mode = KINC_G4_CULL_CLOCKWISE; | ||||
| 		break; | ||||
| 	case 1: | ||||
| 		pipe->cull_mode = KINC_G4_CULL_COUNTER_CLOCKWISE; | ||||
| 		break; | ||||
| 	case 2: | ||||
| 		pipe->cull_mode = KINC_G4_CULL_NOTHING; | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| 	pipe->depth_mode = convertCompareMode(depthMode); | ||||
| 	pipe->depth_write = depthWrite; | ||||
|  | ||||
| 	pipe->stencil_front_mode = convertCompareMode(stencilFrontMode); | ||||
| 	pipe->stencil_front_both_pass = convertStencilAction(stencilFrontBothPass); | ||||
| 	pipe->stencil_front_depth_fail = convertStencilAction(stencilFrontDepthFail); | ||||
| 	pipe->stencil_front_fail = convertStencilAction(stencilFrontFail); | ||||
|  | ||||
| 	pipe->stencil_back_mode = convertCompareMode(stencilBackMode); | ||||
| 	pipe->stencil_back_both_pass = convertStencilAction(stencilBackBothPass); | ||||
| 	pipe->stencil_back_depth_fail = convertStencilAction(stencilBackDepthFail); | ||||
| 	pipe->stencil_back_fail = convertStencilAction(stencilBackFail); | ||||
|  | ||||
| 	pipe->stencil_reference_value = stencilReferenceValue; | ||||
| 	pipe->stencil_read_mask = stencilReadMask; | ||||
| 	pipe->stencil_write_mask = stencilWriteMask; | ||||
|  | ||||
| 	pipe->blend_source = (kinc_g4_blending_factor_t)blendSource; | ||||
| 	pipe->blend_destination = (kinc_g4_blending_factor_t)blendDestination; | ||||
| 	pipe->alpha_blend_source = (kinc_g4_blending_factor_t)alphaBlendSource; | ||||
| 	pipe->alpha_blend_destination = (kinc_g4_blending_factor_t)alphaBlendDestination; | ||||
|  | ||||
| 	pipe->color_write_mask_red[0] = colorWriteMaskRed; | ||||
| 	pipe->color_write_mask_green[0] = colorWriteMaskGreen; | ||||
| 	pipe->color_write_mask_blue[0] = colorWriteMaskBlue; | ||||
| 	pipe->color_write_mask_alpha[0] = colorWriteMaskAlpha; | ||||
|  | ||||
| 	pipe->color_attachment_count = colorAttachmentCount; | ||||
| 	pipe->color_attachment[0] = convertColorAttachment(colorAttachment0); | ||||
| 	pipe->color_attachment[1] = convertColorAttachment(colorAttachment1); | ||||
| 	pipe->color_attachment[2] = convertColorAttachment(colorAttachment2); | ||||
| 	pipe->color_attachment[3] = convertColorAttachment(colorAttachment3); | ||||
| 	pipe->color_attachment[4] = convertColorAttachment(colorAttachment4); | ||||
| 	pipe->color_attachment[5] = convertColorAttachment(colorAttachment5); | ||||
| 	pipe->color_attachment[6] = convertColorAttachment(colorAttachment6); | ||||
| 	pipe->color_attachment[7] = convertColorAttachment(colorAttachment7); | ||||
|  | ||||
| 	pipe->depth_attachment_bits = depthAttachmentBits; | ||||
| 	pipe->stencil_attachment_bits = stencilAttachmentBits; | ||||
|  | ||||
| 	pipe->conservative_rasterization = conservativeRasterization; | ||||
| } | ||||
|  | ||||
| void hl_kinc_pipeline_set(vbyte *pipeline) { | ||||
| 	kinc_g4_pipeline_t *pipe = (kinc_g4_pipeline_t *)pipeline; | ||||
| 	kinc_g4_set_pipeline(pipe); | ||||
| } | ||||
|  | ||||
| vbyte *hl_kinc_pipeline_get_constantlocation(vbyte *pipeline, vbyte *name) { | ||||
| 	kinc_g4_pipeline_t *pipe = (kinc_g4_pipeline_t *)pipeline; | ||||
| 	kinc_g4_constant_location_t *location = (kinc_g4_constant_location_t *)malloc(sizeof(kinc_g4_constant_location_t)); | ||||
| 	*location = kinc_g4_pipeline_get_constant_location(pipe, (char *)name); | ||||
| 	return (vbyte *)location; | ||||
| } | ||||
|  | ||||
| vbyte *hl_kinc_pipeline_get_textureunit(vbyte *pipeline, vbyte *name) { | ||||
| 	kinc_g4_pipeline_t *pipe = (kinc_g4_pipeline_t *)pipeline; | ||||
| 	kinc_g4_texture_unit_t *unit = (kinc_g4_texture_unit_t *)malloc(sizeof(kinc_g4_texture_unit_t)); | ||||
| 	*unit = kinc_g4_pipeline_get_texture_unit(pipe, (char *)name); | ||||
| 	return (vbyte *)unit; | ||||
| }  | ||||
| @ -1,201 +1,201 @@ | ||||
| #include <kinc/input/acceleration.h> | ||||
| #include <kinc/input/gamepad.h> | ||||
| #include <kinc/input/keyboard.h> | ||||
| #include <kinc/input/mouse.h> | ||||
| #include <kinc/input/pen.h> | ||||
| #include <kinc/input/rotation.h> | ||||
| #include <kinc/input/surface.h> | ||||
| #include <kinc/log.h> | ||||
| #include <kinc/system.h> | ||||
| #include <kinc/video.h> | ||||
| #include <kinc/window.h> | ||||
|  | ||||
| #include <hl.h> | ||||
|  | ||||
| void hl_kinc_log(vbyte *v) { | ||||
| 	kinc_log(KINC_LOG_LEVEL_INFO, (char *)v); | ||||
| } | ||||
|  | ||||
| double hl_kinc_get_time(void) { | ||||
| 	return kinc_time(); | ||||
| } | ||||
|  | ||||
| int hl_kinc_get_window_width(int window) { | ||||
| 	return kinc_window_width(window); | ||||
| } | ||||
|  | ||||
| int hl_kinc_get_window_height(int window) { | ||||
| 	return kinc_window_height(window); | ||||
| } | ||||
|  | ||||
| vbyte *hl_kinc_get_system_id(void) { | ||||
| 	return (vbyte *)kinc_system_id(); | ||||
| } | ||||
|  | ||||
| void hl_kinc_vibrate(int ms) { | ||||
| 	kinc_vibrate(ms); | ||||
| } | ||||
|  | ||||
| vbyte *hl_kinc_get_language(void) { | ||||
| 	return (vbyte *)kinc_language(); | ||||
| } | ||||
|  | ||||
| void hl_kinc_request_shutdown(void) { | ||||
| 	kinc_stop(); | ||||
| } | ||||
|  | ||||
| void hl_kinc_mouse_lock(int windowId) { | ||||
| 	kinc_mouse_lock(windowId); | ||||
| } | ||||
|  | ||||
| void hl_kinc_mouse_unlock(void) { | ||||
| 	kinc_mouse_unlock(); | ||||
| } | ||||
|  | ||||
| bool hl_kinc_can_lock_mouse(void) { | ||||
| 	return kinc_mouse_can_lock(); | ||||
| } | ||||
|  | ||||
| bool hl_kinc_is_mouse_locked(void) { | ||||
| 	return kinc_mouse_is_locked(); | ||||
| } | ||||
|  | ||||
| void hl_kinc_show_mouse(bool show) { | ||||
| 	if (show) { | ||||
| 		kinc_mouse_show(); | ||||
| 	} | ||||
| 	else { | ||||
| 		kinc_mouse_hide(); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| bool hl_kinc_system_is_fullscreen(void) { | ||||
| 	return false; // kinc_is_fullscreen(); | ||||
| } | ||||
|  | ||||
| void hl_kinc_system_request_fullscreen(void) { | ||||
| 	// kinc_change_resolution(display_width(), display_height(), true); | ||||
| } | ||||
|  | ||||
| void hl_kinc_system_exit_fullscreen(int previousWidth, int previousHeight) { | ||||
| 	// kinc_change_resolution(previousWidth, previousHeight, false); | ||||
| } | ||||
|  | ||||
| void hl_kinc_system_change_resolution(int width, int height) { | ||||
| 	// kinc_change_resolution(width, height, false); | ||||
| } | ||||
|  | ||||
| void hl_kinc_system_set_keepscreenon(bool on) { | ||||
| 	kinc_set_keep_screen_on(on); | ||||
| } | ||||
|  | ||||
| void hl_kinc_system_load_url(vbyte *url) { | ||||
| 	kinc_load_url((char *)url); | ||||
| } | ||||
|  | ||||
| vbyte *hl_kinc_get_gamepad_id(int index) { | ||||
| 	return (vbyte*)kinc_gamepad_product_name(index); | ||||
| } | ||||
|  | ||||
| vbyte *hl_kinc_get_gamepad_vendor(int index) { | ||||
| 	return (vbyte*)kinc_gamepad_vendor(index); | ||||
| } | ||||
|  | ||||
| bool hl_kinc_gamepad_connected(int index) { | ||||
| 	return kinc_gamepad_connected(index); | ||||
| } | ||||
|  | ||||
| typedef void (*FN_KEY_DOWN)(int, void *); | ||||
| typedef void (*FN_KEY_UP)(int, void *); | ||||
| typedef void (*FN_KEY_PRESS)(unsigned int, void *); | ||||
|  | ||||
| void hl_kinc_register_keyboard(vclosure *keyDown, vclosure *keyUp, vclosure *keyPress) { | ||||
| 	kinc_keyboard_set_key_down_callback(*((FN_KEY_DOWN *)(&keyDown->fun)), NULL); | ||||
| 	kinc_keyboard_set_key_up_callback(*((FN_KEY_UP *)(&keyUp->fun)), NULL); | ||||
| 	kinc_keyboard_set_key_press_callback(*((FN_KEY_PRESS *)(&keyPress->fun)), NULL); | ||||
| } | ||||
|  | ||||
| typedef void (*FN_MOUSE_DOWN)(int, int, int, int, void *); | ||||
| typedef void (*FN_MOUSE_UP)(int, int, int, int, void *); | ||||
| typedef void (*FN_MOUSE_MOVE)(int, int, int, int, int, void *); | ||||
| typedef void (*FN_MOUSE_WHEEL)(int, int, void *); | ||||
|  | ||||
| void hl_kinc_register_mouse(vclosure *mouseDown, vclosure *mouseUp, vclosure *mouseMove, vclosure *mouseWheel) { | ||||
| 	kinc_mouse_set_press_callback(*((FN_MOUSE_DOWN *)(&mouseDown->fun)), NULL); | ||||
| 	kinc_mouse_set_release_callback(*((FN_MOUSE_UP *)(&mouseUp->fun)), NULL); | ||||
| 	kinc_mouse_set_move_callback(*((FN_MOUSE_MOVE *)(&mouseMove->fun)), NULL); | ||||
| 	kinc_mouse_set_scroll_callback(*((FN_MOUSE_WHEEL *)(&mouseWheel->fun)), NULL); | ||||
| } | ||||
|  | ||||
| typedef void (*FN_PEN_DOWN)(int, int, int, float); | ||||
| typedef void (*FN_PEN_UP)(int, int, int, float); | ||||
| typedef void (*FN_PEN_MOVE)(int, int, int, float); | ||||
|  | ||||
| void hl_kinc_register_pen(vclosure *penDown, vclosure *penUp, vclosure *penMove) { | ||||
| 	kinc_pen_set_press_callback(*((FN_PEN_DOWN *)(&penDown->fun))); | ||||
| 	kinc_pen_set_release_callback(*((FN_PEN_UP *)(&penUp->fun))); | ||||
| 	kinc_pen_set_move_callback(*((FN_PEN_MOVE *)(&penMove->fun))); | ||||
| } | ||||
|  | ||||
| typedef void (*FN_GAMEPAD_AXIS)(int, int, float); | ||||
| typedef void (*FN_GAMEPAD_BUTTON)(int, int, float); | ||||
|  | ||||
| void hl_kinc_register_gamepad(vclosure *gamepadAxis, vclosure *gamepadButton) { | ||||
| 	kinc_gamepad_set_axis_callback(*((FN_GAMEPAD_AXIS *)(&gamepadAxis->fun))); | ||||
| 	kinc_gamepad_set_button_callback(*((FN_GAMEPAD_BUTTON *)(&gamepadButton->fun))); | ||||
| } | ||||
|  | ||||
| typedef void (*FN_TOUCH_START)(int, int, int); | ||||
| typedef void (*FN_TOUCH_END)(int, int, int); | ||||
| typedef void (*FN_TOUCH_MOVE)(int, int, int); | ||||
|  | ||||
| void hl_kinc_register_surface(vclosure *touchStart, vclosure *touchEnd, vclosure *touchMove) { | ||||
| 	kinc_surface_set_touch_start_callback(*((FN_TOUCH_START *)(&touchStart->fun))); | ||||
| 	kinc_surface_set_touch_end_callback(*((FN_TOUCH_END *)(&touchEnd->fun))); | ||||
| 	kinc_surface_set_move_callback(*((FN_TOUCH_MOVE *)(&touchMove->fun))); | ||||
| } | ||||
|  | ||||
| typedef void (*FN_SENSOR_ACCELEROMETER)(float, float, float); | ||||
| typedef void (*FN_SENSOR_GYROSCOPE)(float, float, float); | ||||
|  | ||||
| void hl_kinc_register_sensor(vclosure *accelerometerChanged, vclosure *gyroscopeChanged) { | ||||
| 	kinc_acceleration_set_callback(*((FN_SENSOR_ACCELEROMETER *)(&accelerometerChanged->fun))); | ||||
| 	kinc_rotation_set_callback(*((FN_SENSOR_GYROSCOPE *)(&gyroscopeChanged->fun))); | ||||
| } | ||||
|  | ||||
| // typedef void(*FN_CB_ORIENTATION)(int); | ||||
| typedef void (*FN_CB_FOREGROUND)(void *); | ||||
| typedef void (*FN_CB_RESUME)(void *); | ||||
| typedef void (*FN_CB_PAUSE)(void *); | ||||
| typedef void (*FN_CB_BACKGROUND)(void *); | ||||
| typedef void (*FN_CB_SHUTDOWN)(void *); | ||||
|  | ||||
| void hl_kinc_register_callbacks(vclosure *foreground, vclosure *resume, vclosure *pause, vclosure *background, vclosure *shutdown) { | ||||
| 	// kinc_set_orientation_callback(orientation); | ||||
| 	kinc_set_foreground_callback(*((FN_CB_FOREGROUND *)(&foreground->fun)), NULL); | ||||
| 	kinc_set_resume_callback(*((FN_CB_RESUME *)(&resume->fun)), NULL); | ||||
| 	kinc_set_pause_callback(*((FN_CB_PAUSE *)(&pause->fun)), NULL); | ||||
| 	kinc_set_background_callback(*((FN_CB_BACKGROUND *)(&background->fun)), NULL); | ||||
| 	kinc_set_shutdown_callback(*((FN_CB_SHUTDOWN *)(&shutdown->fun)), NULL); | ||||
| } | ||||
|  | ||||
| typedef void (*FN_CB_DROPFILES)(wchar_t *); | ||||
|  | ||||
| void hl_kinc_register_dropfiles(vclosure *dropFiles) { | ||||
| 	// todo: string convert | ||||
| 	// kinc_set_drop_files_callback(*((FN_CB_DROPFILES*)(&dropFiles->fun))); | ||||
| } | ||||
|  | ||||
| typedef char *(*FN_CB_COPY)(void *); | ||||
| typedef char *(*FN_CB_CUT)(void *); | ||||
| typedef void (*FN_CB_PASTE)(char *, void *); | ||||
|  | ||||
| void hl_kinc_register_copycutpaste(vclosure *copy, vclosure *cut, vclosure *paste) { | ||||
| 	kinc_set_copy_callback(*((FN_CB_COPY *)(©->fun)), NULL); | ||||
| 	kinc_set_cut_callback(*((FN_CB_CUT *)(&cut->fun)), NULL); | ||||
| 	kinc_set_paste_callback(*((FN_CB_PASTE *)(&paste->fun)), NULL); | ||||
| } | ||||
|  | ||||
| const char *hl_kinc_video_format(void) { | ||||
| 	return kinc_video_formats()[0]; | ||||
| } | ||||
| #include <kinc/input/acceleration.h> | ||||
| #include <kinc/input/gamepad.h> | ||||
| #include <kinc/input/keyboard.h> | ||||
| #include <kinc/input/mouse.h> | ||||
| #include <kinc/input/pen.h> | ||||
| #include <kinc/input/rotation.h> | ||||
| #include <kinc/input/surface.h> | ||||
| #include <kinc/log.h> | ||||
| #include <kinc/system.h> | ||||
| #include <kinc/video.h> | ||||
| #include <kinc/window.h> | ||||
|  | ||||
| #include <hl.h> | ||||
|  | ||||
| void hl_kinc_log(vbyte *v) { | ||||
| 	kinc_log(KINC_LOG_LEVEL_INFO, (char *)v); | ||||
| } | ||||
|  | ||||
| double hl_kinc_get_time(void) { | ||||
| 	return kinc_time(); | ||||
| } | ||||
|  | ||||
| int hl_kinc_get_window_width(int window) { | ||||
| 	return kinc_window_width(window); | ||||
| } | ||||
|  | ||||
| int hl_kinc_get_window_height(int window) { | ||||
| 	return kinc_window_height(window); | ||||
| } | ||||
|  | ||||
| vbyte *hl_kinc_get_system_id(void) { | ||||
| 	return (vbyte *)kinc_system_id(); | ||||
| } | ||||
|  | ||||
| void hl_kinc_vibrate(int ms) { | ||||
| 	kinc_vibrate(ms); | ||||
| } | ||||
|  | ||||
| vbyte *hl_kinc_get_language(void) { | ||||
| 	return (vbyte *)kinc_language(); | ||||
| } | ||||
|  | ||||
| void hl_kinc_request_shutdown(void) { | ||||
| 	kinc_stop(); | ||||
| } | ||||
|  | ||||
| void hl_kinc_mouse_lock(int windowId) { | ||||
| 	kinc_mouse_lock(windowId); | ||||
| } | ||||
|  | ||||
| void hl_kinc_mouse_unlock(void) { | ||||
| 	kinc_mouse_unlock(); | ||||
| } | ||||
|  | ||||
| bool hl_kinc_can_lock_mouse(void) { | ||||
| 	return kinc_mouse_can_lock(); | ||||
| } | ||||
|  | ||||
| bool hl_kinc_is_mouse_locked(void) { | ||||
| 	return kinc_mouse_is_locked(); | ||||
| } | ||||
|  | ||||
| void hl_kinc_show_mouse(bool show) { | ||||
| 	if (show) { | ||||
| 		kinc_mouse_show(); | ||||
| 	} | ||||
| 	else { | ||||
| 		kinc_mouse_hide(); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| bool hl_kinc_system_is_fullscreen(void) { | ||||
| 	return false; // kinc_is_fullscreen(); | ||||
| } | ||||
|  | ||||
| void hl_kinc_system_request_fullscreen(void) { | ||||
| 	// kinc_change_resolution(display_width(), display_height(), true); | ||||
| } | ||||
|  | ||||
| void hl_kinc_system_exit_fullscreen(int previousWidth, int previousHeight) { | ||||
| 	// kinc_change_resolution(previousWidth, previousHeight, false); | ||||
| } | ||||
|  | ||||
| void hl_kinc_system_change_resolution(int width, int height) { | ||||
| 	// kinc_change_resolution(width, height, false); | ||||
| } | ||||
|  | ||||
| void hl_kinc_system_set_keepscreenon(bool on) { | ||||
| 	kinc_set_keep_screen_on(on); | ||||
| } | ||||
|  | ||||
| void hl_kinc_system_load_url(vbyte *url) { | ||||
| 	kinc_load_url((char *)url); | ||||
| } | ||||
|  | ||||
| vbyte *hl_kinc_get_gamepad_id(int index) { | ||||
| 	return (vbyte *)kinc_gamepad_product_name(index); | ||||
| } | ||||
|  | ||||
| vbyte *hl_kinc_get_gamepad_vendor(int index) { | ||||
| 	return (vbyte *)kinc_gamepad_vendor(index); | ||||
| } | ||||
|  | ||||
| bool hl_kinc_gamepad_connected(int index) { | ||||
| 	return kinc_gamepad_connected(index); | ||||
| } | ||||
|  | ||||
| typedef void (*FN_KEY_DOWN)(int, void *); | ||||
| typedef void (*FN_KEY_UP)(int, void *); | ||||
| typedef void (*FN_KEY_PRESS)(unsigned int, void *); | ||||
|  | ||||
| void hl_kinc_register_keyboard(vclosure *keyDown, vclosure *keyUp, vclosure *keyPress) { | ||||
| 	kinc_keyboard_set_key_down_callback(*((FN_KEY_DOWN *)(&keyDown->fun)), NULL); | ||||
| 	kinc_keyboard_set_key_up_callback(*((FN_KEY_UP *)(&keyUp->fun)), NULL); | ||||
| 	kinc_keyboard_set_key_press_callback(*((FN_KEY_PRESS *)(&keyPress->fun)), NULL); | ||||
| } | ||||
|  | ||||
| typedef void (*FN_MOUSE_DOWN)(int, int, int, int, void *); | ||||
| typedef void (*FN_MOUSE_UP)(int, int, int, int, void *); | ||||
| typedef void (*FN_MOUSE_MOVE)(int, int, int, int, int, void *); | ||||
| typedef void (*FN_MOUSE_WHEEL)(int, int, void *); | ||||
|  | ||||
| void hl_kinc_register_mouse(vclosure *mouseDown, vclosure *mouseUp, vclosure *mouseMove, vclosure *mouseWheel) { | ||||
| 	kinc_mouse_set_press_callback(*((FN_MOUSE_DOWN *)(&mouseDown->fun)), NULL); | ||||
| 	kinc_mouse_set_release_callback(*((FN_MOUSE_UP *)(&mouseUp->fun)), NULL); | ||||
| 	kinc_mouse_set_move_callback(*((FN_MOUSE_MOVE *)(&mouseMove->fun)), NULL); | ||||
| 	kinc_mouse_set_scroll_callback(*((FN_MOUSE_WHEEL *)(&mouseWheel->fun)), NULL); | ||||
| } | ||||
|  | ||||
| typedef void (*FN_PEN_DOWN)(int, int, int, float); | ||||
| typedef void (*FN_PEN_UP)(int, int, int, float); | ||||
| typedef void (*FN_PEN_MOVE)(int, int, int, float); | ||||
|  | ||||
| void hl_kinc_register_pen(vclosure *penDown, vclosure *penUp, vclosure *penMove) { | ||||
| 	kinc_pen_set_press_callback(*((FN_PEN_DOWN *)(&penDown->fun))); | ||||
| 	kinc_pen_set_release_callback(*((FN_PEN_UP *)(&penUp->fun))); | ||||
| 	kinc_pen_set_move_callback(*((FN_PEN_MOVE *)(&penMove->fun))); | ||||
| } | ||||
|  | ||||
| typedef void (*FN_GAMEPAD_AXIS)(int, int, float, void *); | ||||
| typedef void (*FN_GAMEPAD_BUTTON)(int, int, float, void *); | ||||
|  | ||||
| void hl_kinc_register_gamepad(vclosure *gamepadAxis, vclosure *gamepadButton) { | ||||
| 	kinc_gamepad_set_axis_callback(*((FN_GAMEPAD_AXIS *)(&gamepadAxis->fun)), NULL); | ||||
| 	kinc_gamepad_set_button_callback(*((FN_GAMEPAD_BUTTON *)(&gamepadButton->fun)), NULL); | ||||
| } | ||||
|  | ||||
| typedef void (*FN_TOUCH_START)(int, int, int); | ||||
| typedef void (*FN_TOUCH_END)(int, int, int); | ||||
| typedef void (*FN_TOUCH_MOVE)(int, int, int); | ||||
|  | ||||
| void hl_kinc_register_surface(vclosure *touchStart, vclosure *touchEnd, vclosure *touchMove) { | ||||
| 	kinc_surface_set_touch_start_callback(*((FN_TOUCH_START *)(&touchStart->fun))); | ||||
| 	kinc_surface_set_touch_end_callback(*((FN_TOUCH_END *)(&touchEnd->fun))); | ||||
| 	kinc_surface_set_move_callback(*((FN_TOUCH_MOVE *)(&touchMove->fun))); | ||||
| } | ||||
|  | ||||
| typedef void (*FN_SENSOR_ACCELEROMETER)(float, float, float); | ||||
| typedef void (*FN_SENSOR_GYROSCOPE)(float, float, float); | ||||
|  | ||||
| void hl_kinc_register_sensor(vclosure *accelerometerChanged, vclosure *gyroscopeChanged) { | ||||
| 	kinc_acceleration_set_callback(*((FN_SENSOR_ACCELEROMETER *)(&accelerometerChanged->fun))); | ||||
| 	kinc_rotation_set_callback(*((FN_SENSOR_GYROSCOPE *)(&gyroscopeChanged->fun))); | ||||
| } | ||||
|  | ||||
| // typedef void(*FN_CB_ORIENTATION)(int); | ||||
| typedef void (*FN_CB_FOREGROUND)(void *); | ||||
| typedef void (*FN_CB_RESUME)(void *); | ||||
| typedef void (*FN_CB_PAUSE)(void *); | ||||
| typedef void (*FN_CB_BACKGROUND)(void *); | ||||
| typedef void (*FN_CB_SHUTDOWN)(void *); | ||||
|  | ||||
| void hl_kinc_register_callbacks(vclosure *foreground, vclosure *resume, vclosure *pause, vclosure *background, vclosure *shutdown) { | ||||
| 	// kinc_set_orientation_callback(orientation); | ||||
| 	kinc_set_foreground_callback(*((FN_CB_FOREGROUND *)(&foreground->fun)), NULL); | ||||
| 	kinc_set_resume_callback(*((FN_CB_RESUME *)(&resume->fun)), NULL); | ||||
| 	kinc_set_pause_callback(*((FN_CB_PAUSE *)(&pause->fun)), NULL); | ||||
| 	kinc_set_background_callback(*((FN_CB_BACKGROUND *)(&background->fun)), NULL); | ||||
| 	kinc_set_shutdown_callback(*((FN_CB_SHUTDOWN *)(&shutdown->fun)), NULL); | ||||
| } | ||||
|  | ||||
| typedef void (*FN_CB_DROPFILES)(wchar_t *); | ||||
|  | ||||
| void hl_kinc_register_dropfiles(vclosure *dropFiles) { | ||||
| 	// todo: string convert | ||||
| 	// kinc_set_drop_files_callback(*((FN_CB_DROPFILES*)(&dropFiles->fun))); | ||||
| } | ||||
|  | ||||
| typedef char *(*FN_CB_COPY)(void *); | ||||
| typedef char *(*FN_CB_CUT)(void *); | ||||
| typedef void (*FN_CB_PASTE)(char *, void *); | ||||
|  | ||||
| void hl_kinc_register_copycutpaste(vclosure *copy, vclosure *cut, vclosure *paste) { | ||||
| 	kinc_set_copy_callback(*((FN_CB_COPY *)(©->fun)), NULL); | ||||
| 	kinc_set_cut_callback(*((FN_CB_CUT *)(&cut->fun)), NULL); | ||||
| 	kinc_set_paste_callback(*((FN_CB_PASTE *)(&paste->fun)), NULL); | ||||
| } | ||||
|  | ||||
| const char *hl_kinc_video_format(void) { | ||||
| 	return kinc_video_formats()[0]; | ||||
| } | ||||
|  | ||||
| @ -80,6 +80,7 @@ extern class Krom { | ||||
| 	static function unloadImage(image: kha.Image): Void; | ||||
| 	static function loadSound(file: String): Dynamic; | ||||
| 	static function writeAudioBuffer(buffer: js.lib.ArrayBuffer, samples: Int): Void; | ||||
| 	static function getSamplesPerSecond(): Int; | ||||
| 	static function loadBlob(file: String): js.lib.ArrayBuffer; | ||||
|  | ||||
| 	static function init(title: String, width: Int, height: Int, samplesPerPixel: Int, vSync: Bool, windowMode: Int, windowFeatures: Int, kromApi: Int): Void; | ||||
| @ -115,6 +116,7 @@ extern class Krom { | ||||
| 	static function screenDpi(): Int; | ||||
| 	static function systemId(): String; | ||||
| 	static function requestShutdown(): Void; | ||||
| 	static function displayFrequency(): Int; | ||||
| 	static function displayCount(): Int; | ||||
| 	static function displayWidth(index: Int): Int; | ||||
| 	static function displayHeight(index: Int): Int; | ||||
|  | ||||
| @ -79,7 +79,7 @@ class Display { | ||||
| 	public var frequency(get, never): Int; | ||||
|  | ||||
| 	function get_frequency(): Int { | ||||
| 		return 60; | ||||
| 		return Krom.displayFrequency(); | ||||
| 	} | ||||
|  | ||||
| 	public var pixelsPerInch(get, never): Int; | ||||
|  | ||||
| @ -1,343 +1,344 @@ | ||||
| package kha; | ||||
|  | ||||
| import kha.graphics4.TextureFormat; | ||||
| import kha.input.Gamepad; | ||||
| import kha.input.Keyboard; | ||||
| import kha.input.Mouse; | ||||
| import kha.input.MouseImpl; | ||||
| import kha.input.Pen; | ||||
| import kha.input.Surface; | ||||
| import kha.System; | ||||
| import haxe.ds.Vector; | ||||
|  | ||||
| class SystemImpl { | ||||
| 	static var start: Float; | ||||
| 	static var framebuffer: Framebuffer; | ||||
| 	static var keyboard: Keyboard; | ||||
| 	static var mouse: Mouse; | ||||
| 	static var pen: Pen; | ||||
| 	static var maxGamepads: Int = 4; | ||||
| 	static var gamepads: Array<Gamepad>; | ||||
| 	static var mouseLockListeners: Array<Void->Void> = []; | ||||
|  | ||||
| 	static function renderCallback(): Void { | ||||
| 		Scheduler.executeFrame(); | ||||
| 		System.render([framebuffer]); | ||||
| 	} | ||||
|  | ||||
| 	static function dropFilesCallback(filePath: String): Void { | ||||
| 		System.dropFiles(filePath); | ||||
| 	} | ||||
|  | ||||
| 	static function copyCallback(): String { | ||||
| 		if (System.copyListener != null) { | ||||
| 			return System.copyListener(); | ||||
| 		} | ||||
| 		else { | ||||
| 			return null; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	static function cutCallback(): String { | ||||
| 		if (System.cutListener != null) { | ||||
| 			return System.cutListener(); | ||||
| 		} | ||||
| 		else { | ||||
| 			return null; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	static function pasteCallback(data: String): Void { | ||||
| 		if (System.pasteListener != null) { | ||||
| 			System.pasteListener(data); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	static function foregroundCallback(): Void { | ||||
| 		System.foreground(); | ||||
| 	} | ||||
|  | ||||
| 	static function resumeCallback(): Void { | ||||
| 		System.resume(); | ||||
| 	} | ||||
|  | ||||
| 	static function pauseCallback(): Void { | ||||
| 		System.pause(); | ||||
| 	} | ||||
|  | ||||
| 	static function backgroundCallback(): Void { | ||||
| 		System.background(); | ||||
| 	} | ||||
|  | ||||
| 	static function shutdownCallback(): Void { | ||||
| 		System.shutdown(); | ||||
| 	} | ||||
|  | ||||
| 	static function keyboardDownCallback(code: Int): Void { | ||||
| 		keyboard.sendDownEvent(cast code); | ||||
| 	} | ||||
|  | ||||
| 	static function keyboardUpCallback(code: Int): Void { | ||||
| 		keyboard.sendUpEvent(cast code); | ||||
| 	} | ||||
|  | ||||
| 	static function keyboardPressCallback(charCode: Int): Void { | ||||
| 		keyboard.sendPressEvent(String.fromCharCode(charCode)); | ||||
| 	} | ||||
|  | ||||
| 	static function mouseDownCallback(button: Int, x: Int, y: Int): Void { | ||||
| 		mouse.sendDownEvent(0, button, x, y); | ||||
| 	} | ||||
|  | ||||
| 	static function mouseUpCallback(button: Int, x: Int, y: Int): Void { | ||||
| 		mouse.sendUpEvent(0, button, x, y); | ||||
| 	} | ||||
|  | ||||
| 	static function mouseMoveCallback(x: Int, y: Int, mx: Int, my: Int): Void { | ||||
| 		mouse.sendMoveEvent(0, x, y, mx, my); | ||||
| 	} | ||||
|  | ||||
| 	static function mouseWheelCallback(delta: Int): Void { | ||||
| 		mouse.sendWheelEvent(0, delta); | ||||
| 	} | ||||
|  | ||||
| 	static function penDownCallback(x: Int, y: Int, pressure: Float): Void { | ||||
| 		pen.sendDownEvent(0, x, y, pressure); | ||||
| 	} | ||||
|  | ||||
| 	static function penUpCallback(x: Int, y: Int, pressure: Float): Void { | ||||
| 		pen.sendUpEvent(0, x, y, pressure); | ||||
| 	} | ||||
|  | ||||
| 	static function penMoveCallback(x: Int, y: Int, pressure: Float): Void { | ||||
| 		pen.sendMoveEvent(0, x, y, pressure); | ||||
| 	} | ||||
|  | ||||
| 	static function gamepadAxisCallback(gamepad: Int, axis: Int, value: Float): Void { | ||||
| 		gamepads[gamepad].sendAxisEvent(axis, value); | ||||
| 	} | ||||
|  | ||||
| 	static function gamepadButtonCallback(gamepad: Int, button: Int, value: Float): Void { | ||||
| 		gamepads[gamepad].sendButtonEvent(button, value); | ||||
| 	} | ||||
|  | ||||
| 	static function audioCallback(samples: Int): Void { | ||||
| 		kha.audio2.Audio._callCallback(samples); | ||||
| 		var buffer = @:privateAccess kha.audio2.Audio.buffer; | ||||
| 		Krom.writeAudioBuffer(buffer.data.buffer, samples); | ||||
| 	} | ||||
|  | ||||
| 	public static function init(options: SystemOptions, callback: Window->Void): Void { | ||||
| 		Krom.init(options.title, options.width, options.height, options.framebuffer.samplesPerPixel, options.framebuffer.verticalSync, | ||||
| 			cast options.window.mode, options.window.windowFeatures, Krom.KROM_API); | ||||
|  | ||||
| 		start = Krom.getTime(); | ||||
|  | ||||
| 		haxe.Log.trace = function(v: Dynamic, ?infos: haxe.PosInfos) { | ||||
| 			var message = haxe.Log.formatOutput(v, infos); | ||||
| 			Krom.log(message); | ||||
| 		}; | ||||
|  | ||||
| 		new Window(0); | ||||
| 		Scheduler.init(); | ||||
| 		Shaders.init(); | ||||
|  | ||||
| 		var g4 = new kha.krom.Graphics(); | ||||
| 		framebuffer = new Framebuffer(0, null, null, g4); | ||||
| 		framebuffer.init(new kha.graphics2.Graphics1(framebuffer), new kha.graphics4.Graphics2(framebuffer), g4); | ||||
| 		Krom.setCallback(renderCallback); | ||||
| 		Krom.setDropFilesCallback(dropFilesCallback); | ||||
| 		Krom.setCutCopyPasteCallback(cutCallback, copyCallback, pasteCallback); | ||||
| 		Krom.setApplicationStateCallback(foregroundCallback, resumeCallback, pauseCallback, backgroundCallback, shutdownCallback); | ||||
|  | ||||
| 		keyboard = new Keyboard(); | ||||
| 		mouse = new MouseImpl(); | ||||
| 		pen = new Pen(); | ||||
| 		gamepads = new Array<Gamepad>(); | ||||
| 		for (i in 0...maxGamepads) { | ||||
| 			gamepads[i] = new Gamepad(i); | ||||
| 		} | ||||
|  | ||||
| 		Krom.setKeyboardDownCallback(keyboardDownCallback); | ||||
| 		Krom.setKeyboardUpCallback(keyboardUpCallback); | ||||
| 		Krom.setKeyboardPressCallback(keyboardPressCallback); | ||||
| 		Krom.setMouseDownCallback(mouseDownCallback); | ||||
| 		Krom.setMouseUpCallback(mouseUpCallback); | ||||
| 		Krom.setMouseMoveCallback(mouseMoveCallback); | ||||
| 		Krom.setMouseWheelCallback(mouseWheelCallback); | ||||
| 		Krom.setPenDownCallback(penDownCallback); | ||||
| 		Krom.setPenUpCallback(penUpCallback); | ||||
| 		Krom.setPenMoveCallback(penMoveCallback); | ||||
| 		Krom.setGamepadAxisCallback(gamepadAxisCallback); | ||||
| 		Krom.setGamepadButtonCallback(gamepadButtonCallback); | ||||
|  | ||||
| 		kha.audio2.Audio._init(); | ||||
| 		kha.audio1.Audio._init(); | ||||
| 		Krom.setAudioCallback(audioCallback); | ||||
|  | ||||
| 		Scheduler.start(); | ||||
|  | ||||
| 		callback(Window.get(0)); | ||||
| 	} | ||||
|  | ||||
| 	public static function initEx(title: String, options: Array<WindowOptions>, windowCallback: Int->Void, callback: Void->Void): Void {} | ||||
|  | ||||
| 	static function translateWindowMode(value: Null<WindowMode>): Int { | ||||
| 		if (value == null) { | ||||
| 			return 0; | ||||
| 		} | ||||
|  | ||||
| 		return switch (value) { | ||||
| 			case Windowed: 0; | ||||
| 			case Fullscreen: 1; | ||||
| 			case ExclusiveFullscreen: 2; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	public static function getScreenRotation(): ScreenRotation { | ||||
| 		return ScreenRotation.RotationNone; | ||||
| 	} | ||||
|  | ||||
| 	public static function getTime(): Float { | ||||
| 		return Krom.getTime() - start; | ||||
| 	} | ||||
|  | ||||
| 	public static function getVsync(): Bool { | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
| 	public static function getRefreshRate(): Int { | ||||
| 		return 60; | ||||
| 	} | ||||
|  | ||||
| 	public static function getSystemId(): String { | ||||
| 		return Krom.systemId(); | ||||
| 	} | ||||
|  | ||||
| 	public static function vibrate(ms: Int): Void { | ||||
| 		// TODO: Implement | ||||
| 	} | ||||
|  | ||||
| 	public static function getLanguage(): String { | ||||
| 		return "en"; // TODO: Implement | ||||
| 	} | ||||
|  | ||||
| 	public static function requestShutdown(): Bool { | ||||
| 		Krom.requestShutdown(); | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
| 	public static function getMouse(num: Int): Mouse { | ||||
| 		return mouse; | ||||
| 	} | ||||
|  | ||||
| 	public static function getPen(num: Int): Pen { | ||||
| 		return pen; | ||||
| 	} | ||||
|  | ||||
| 	public static function getKeyboard(num: Int): Keyboard { | ||||
| 		return keyboard; | ||||
| 	} | ||||
|  | ||||
| 	public static function lockMouse(): Void { | ||||
| 		if (!isMouseLocked()) { | ||||
| 			Krom.lockMouse(); | ||||
| 			for (listener in mouseLockListeners) { | ||||
| 				listener(); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	public static function unlockMouse(): Void { | ||||
| 		if (isMouseLocked()) { | ||||
| 			Krom.unlockMouse(); | ||||
| 			for (listener in mouseLockListeners) { | ||||
| 				listener(); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	public static function canLockMouse(): Bool { | ||||
| 		return Krom.canLockMouse(); | ||||
| 	} | ||||
|  | ||||
| 	public static function isMouseLocked(): Bool { | ||||
| 		return Krom.isMouseLocked(); | ||||
| 	} | ||||
|  | ||||
| 	public static function notifyOfMouseLockChange(func: Void->Void, error: Void->Void): Void { | ||||
| 		if (canLockMouse() && func != null) { | ||||
| 			mouseLockListeners.push(func); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	public static function removeFromMouseLockChange(func: Void->Void, error: Void->Void): Void { | ||||
| 		if (canLockMouse() && func != null) { | ||||
| 			mouseLockListeners.remove(func); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	public static function hideSystemCursor(): Void { | ||||
| 		Krom.showMouse(false); | ||||
| 	} | ||||
|  | ||||
| 	public static function showSystemCursor(): Void { | ||||
| 		Krom.showMouse(true); | ||||
| 	} | ||||
|  | ||||
| 	static function unload(): Void {} | ||||
|  | ||||
| 	public static function canSwitchFullscreen(): Bool { | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	public static function isFullscreen(): Bool { | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	public static function requestFullscreen(): Void {} | ||||
|  | ||||
| 	public static function exitFullscreen(): Void {} | ||||
|  | ||||
| 	public static function notifyOfFullscreenChange(func: Void->Void, error: Void->Void): Void {} | ||||
|  | ||||
| 	public static function removeFromFullscreenChange(func: Void->Void, error: Void->Void): Void {} | ||||
|  | ||||
| 	public static function changeResolution(width: Int, height: Int): Void {} | ||||
|  | ||||
| 	public static function setKeepScreenOn(on: Bool): Void {} | ||||
|  | ||||
| 	public static function loadUrl(url: String): Void {} | ||||
|  | ||||
| 	public static function getGamepadId(index: Int): String { | ||||
| 		return "unknown"; | ||||
| 	} | ||||
|  | ||||
| 	public static function getGamepadVendor(index: Int): String { | ||||
| 		return "unknown"; | ||||
| 	} | ||||
|  | ||||
| 	public static function setGamepadRumble(index: Int, leftAmount: Float, rightAmount: Float): Void {} | ||||
|  | ||||
| 	public static function safeZone(): Float { | ||||
| 		return 1.0; | ||||
| 	} | ||||
|  | ||||
| 	public static function login(): Void {} | ||||
|  | ||||
| 	public static function automaticSafeZone(): Bool { | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
| 	public static function setSafeZone(value: Float): Void {} | ||||
|  | ||||
| 	public static function unlockAchievement(id: Int): Void {} | ||||
|  | ||||
| 	public static function waitingForLogin(): Bool { | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	public static function disallowUserChange(): Void {} | ||||
|  | ||||
| 	public static function allowUserChange(): Void {} | ||||
| } | ||||
| package kha; | ||||
|  | ||||
| import kha.graphics4.TextureFormat; | ||||
| import kha.input.Gamepad; | ||||
| import kha.input.Keyboard; | ||||
| import kha.input.Mouse; | ||||
| import kha.input.MouseImpl; | ||||
| import kha.input.Pen; | ||||
| import kha.input.Surface; | ||||
| import kha.System; | ||||
| import haxe.ds.Vector; | ||||
|  | ||||
| class SystemImpl { | ||||
| 	static var start: Float; | ||||
| 	static var framebuffer: Framebuffer; | ||||
| 	static var keyboard: Keyboard; | ||||
| 	static var mouse: Mouse; | ||||
| 	static var pen: Pen; | ||||
| 	static var maxGamepads: Int = 4; | ||||
| 	static var gamepads: Array<Gamepad>; | ||||
| 	static var mouseLockListeners: Array<Void->Void> = []; | ||||
|  | ||||
| 	static function renderCallback(): Void { | ||||
| 		Scheduler.executeFrame(); | ||||
| 		System.render([framebuffer]); | ||||
| 	} | ||||
|  | ||||
| 	static function dropFilesCallback(filePath: String): Void { | ||||
| 		System.dropFiles(filePath); | ||||
| 	} | ||||
|  | ||||
| 	static function copyCallback(): String { | ||||
| 		if (System.copyListener != null) { | ||||
| 			return System.copyListener(); | ||||
| 		} | ||||
| 		else { | ||||
| 			return null; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	static function cutCallback(): String { | ||||
| 		if (System.cutListener != null) { | ||||
| 			return System.cutListener(); | ||||
| 		} | ||||
| 		else { | ||||
| 			return null; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	static function pasteCallback(data: String): Void { | ||||
| 		if (System.pasteListener != null) { | ||||
| 			System.pasteListener(data); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	static function foregroundCallback(): Void { | ||||
| 		System.foreground(); | ||||
| 	} | ||||
|  | ||||
| 	static function resumeCallback(): Void { | ||||
| 		System.resume(); | ||||
| 	} | ||||
|  | ||||
| 	static function pauseCallback(): Void { | ||||
| 		System.pause(); | ||||
| 	} | ||||
|  | ||||
| 	static function backgroundCallback(): Void { | ||||
| 		System.background(); | ||||
| 	} | ||||
|  | ||||
| 	static function shutdownCallback(): Void { | ||||
| 		System.shutdown(); | ||||
| 	} | ||||
|  | ||||
| 	static function keyboardDownCallback(code: Int): Void { | ||||
| 		keyboard.sendDownEvent(cast code); | ||||
| 	} | ||||
|  | ||||
| 	static function keyboardUpCallback(code: Int): Void { | ||||
| 		keyboard.sendUpEvent(cast code); | ||||
| 	} | ||||
|  | ||||
| 	static function keyboardPressCallback(charCode: Int): Void { | ||||
| 		keyboard.sendPressEvent(String.fromCharCode(charCode)); | ||||
| 	} | ||||
|  | ||||
| 	static function mouseDownCallback(button: Int, x: Int, y: Int): Void { | ||||
| 		mouse.sendDownEvent(0, button, x, y); | ||||
| 	} | ||||
|  | ||||
| 	static function mouseUpCallback(button: Int, x: Int, y: Int): Void { | ||||
| 		mouse.sendUpEvent(0, button, x, y); | ||||
| 	} | ||||
|  | ||||
| 	static function mouseMoveCallback(x: Int, y: Int, mx: Int, my: Int): Void { | ||||
| 		mouse.sendMoveEvent(0, x, y, mx, my); | ||||
| 	} | ||||
|  | ||||
| 	static function mouseWheelCallback(delta: Int): Void { | ||||
| 		mouse.sendWheelEvent(0, delta); | ||||
| 	} | ||||
|  | ||||
| 	static function penDownCallback(x: Int, y: Int, pressure: Float): Void { | ||||
| 		pen.sendDownEvent(0, x, y, pressure); | ||||
| 	} | ||||
|  | ||||
| 	static function penUpCallback(x: Int, y: Int, pressure: Float): Void { | ||||
| 		pen.sendUpEvent(0, x, y, pressure); | ||||
| 	} | ||||
|  | ||||
| 	static function penMoveCallback(x: Int, y: Int, pressure: Float): Void { | ||||
| 		pen.sendMoveEvent(0, x, y, pressure); | ||||
| 	} | ||||
|  | ||||
| 	static function gamepadAxisCallback(gamepad: Int, axis: Int, value: Float): Void { | ||||
| 		gamepads[gamepad].sendAxisEvent(axis, value); | ||||
| 	} | ||||
|  | ||||
| 	static function gamepadButtonCallback(gamepad: Int, button: Int, value: Float): Void { | ||||
| 		gamepads[gamepad].sendButtonEvent(button, value); | ||||
| 	} | ||||
|  | ||||
| 	static function audioCallback(samples: Int): Void { | ||||
| 		kha.audio2.Audio._callCallback(samples); | ||||
| 		var buffer = @:privateAccess kha.audio2.Audio.buffer; | ||||
| 		Krom.writeAudioBuffer(buffer.data.buffer, samples); | ||||
| 	} | ||||
|  | ||||
| 	public static function init(options: SystemOptions, callback: Window->Void): Void { | ||||
| 		Krom.init(options.title, options.width, options.height, options.framebuffer.samplesPerPixel, options.framebuffer.verticalSync, | ||||
| 			cast options.window.mode, options.window.windowFeatures, Krom.KROM_API); | ||||
|  | ||||
| 		start = Krom.getTime(); | ||||
|  | ||||
| 		haxe.Log.trace = function(v: Dynamic, ?infos: haxe.PosInfos) { | ||||
| 			var message = haxe.Log.formatOutput(v, infos); | ||||
| 			Krom.log(message); | ||||
| 		}; | ||||
|  | ||||
| 		new Window(0); | ||||
| 		Scheduler.init(); | ||||
| 		Shaders.init(); | ||||
|  | ||||
| 		var g4 = new kha.krom.Graphics(); | ||||
| 		framebuffer = new Framebuffer(0, null, null, g4); | ||||
| 		framebuffer.init(new kha.graphics2.Graphics1(framebuffer), new kha.graphics4.Graphics2(framebuffer), g4); | ||||
| 		Krom.setCallback(renderCallback); | ||||
| 		Krom.setDropFilesCallback(dropFilesCallback); | ||||
| 		Krom.setCutCopyPasteCallback(cutCallback, copyCallback, pasteCallback); | ||||
| 		Krom.setApplicationStateCallback(foregroundCallback, resumeCallback, pauseCallback, backgroundCallback, shutdownCallback); | ||||
|  | ||||
| 		keyboard = new Keyboard(); | ||||
| 		mouse = new MouseImpl(); | ||||
| 		pen = new Pen(); | ||||
| 		gamepads = new Array<Gamepad>(); | ||||
| 		for (i in 0...maxGamepads) { | ||||
| 			gamepads[i] = new Gamepad(i); | ||||
| 		} | ||||
|  | ||||
| 		Krom.setKeyboardDownCallback(keyboardDownCallback); | ||||
| 		Krom.setKeyboardUpCallback(keyboardUpCallback); | ||||
| 		Krom.setKeyboardPressCallback(keyboardPressCallback); | ||||
| 		Krom.setMouseDownCallback(mouseDownCallback); | ||||
| 		Krom.setMouseUpCallback(mouseUpCallback); | ||||
| 		Krom.setMouseMoveCallback(mouseMoveCallback); | ||||
| 		Krom.setMouseWheelCallback(mouseWheelCallback); | ||||
| 		Krom.setPenDownCallback(penDownCallback); | ||||
| 		Krom.setPenUpCallback(penUpCallback); | ||||
| 		Krom.setPenMoveCallback(penMoveCallback); | ||||
| 		Krom.setGamepadAxisCallback(gamepadAxisCallback); | ||||
| 		Krom.setGamepadButtonCallback(gamepadButtonCallback); | ||||
|  | ||||
| 		kha.audio2.Audio.samplesPerSecond = Krom.getSamplesPerSecond(); | ||||
| 		kha.audio1.Audio._init(); | ||||
| 		kha.audio2.Audio._init(); | ||||
| 		Krom.setAudioCallback(audioCallback); | ||||
|  | ||||
| 		Scheduler.start(); | ||||
|  | ||||
| 		callback(Window.get(0)); | ||||
| 	} | ||||
|  | ||||
| 	public static function initEx(title: String, options: Array<WindowOptions>, windowCallback: Int->Void, callback: Void->Void): Void {} | ||||
|  | ||||
| 	static function translateWindowMode(value: Null<WindowMode>): Int { | ||||
| 		if (value == null) { | ||||
| 			return 0; | ||||
| 		} | ||||
|  | ||||
| 		return switch (value) { | ||||
| 			case Windowed: 0; | ||||
| 			case Fullscreen: 1; | ||||
| 			case ExclusiveFullscreen: 2; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	public static function getScreenRotation(): ScreenRotation { | ||||
| 		return ScreenRotation.RotationNone; | ||||
| 	} | ||||
|  | ||||
| 	public static function getTime(): Float { | ||||
| 		return Krom.getTime() - start; | ||||
| 	} | ||||
|  | ||||
| 	public static function getVsync(): Bool { | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
| 	public static function getRefreshRate(): Int { | ||||
| 		return Krom.displayFrequency(); | ||||
| 	} | ||||
|  | ||||
| 	public static function getSystemId(): String { | ||||
| 		return Krom.systemId(); | ||||
| 	} | ||||
|  | ||||
| 	public static function vibrate(ms: Int): Void { | ||||
| 		// TODO: Implement | ||||
| 	} | ||||
|  | ||||
| 	public static function getLanguage(): String { | ||||
| 		return "en"; // TODO: Implement | ||||
| 	} | ||||
|  | ||||
| 	public static function requestShutdown(): Bool { | ||||
| 		Krom.requestShutdown(); | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
| 	public static function getMouse(num: Int): Mouse { | ||||
| 		return mouse; | ||||
| 	} | ||||
|  | ||||
| 	public static function getPen(num: Int): Pen { | ||||
| 		return pen; | ||||
| 	} | ||||
|  | ||||
| 	public static function getKeyboard(num: Int): Keyboard { | ||||
| 		return keyboard; | ||||
| 	} | ||||
|  | ||||
| 	public static function lockMouse(): Void { | ||||
| 		if (!isMouseLocked()) { | ||||
| 			Krom.lockMouse(); | ||||
| 			for (listener in mouseLockListeners) { | ||||
| 				listener(); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	public static function unlockMouse(): Void { | ||||
| 		if (isMouseLocked()) { | ||||
| 			Krom.unlockMouse(); | ||||
| 			for (listener in mouseLockListeners) { | ||||
| 				listener(); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	public static function canLockMouse(): Bool { | ||||
| 		return Krom.canLockMouse(); | ||||
| 	} | ||||
|  | ||||
| 	public static function isMouseLocked(): Bool { | ||||
| 		return Krom.isMouseLocked(); | ||||
| 	} | ||||
|  | ||||
| 	public static function notifyOfMouseLockChange(func: Void->Void, error: Void->Void): Void { | ||||
| 		if (canLockMouse() && func != null) { | ||||
| 			mouseLockListeners.push(func); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	public static function removeFromMouseLockChange(func: Void->Void, error: Void->Void): Void { | ||||
| 		if (canLockMouse() && func != null) { | ||||
| 			mouseLockListeners.remove(func); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	public static function hideSystemCursor(): Void { | ||||
| 		Krom.showMouse(false); | ||||
| 	} | ||||
|  | ||||
| 	public static function showSystemCursor(): Void { | ||||
| 		Krom.showMouse(true); | ||||
| 	} | ||||
|  | ||||
| 	static function unload(): Void {} | ||||
|  | ||||
| 	public static function canSwitchFullscreen(): Bool { | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	public static function isFullscreen(): Bool { | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	public static function requestFullscreen(): Void {} | ||||
|  | ||||
| 	public static function exitFullscreen(): Void {} | ||||
|  | ||||
| 	public static function notifyOfFullscreenChange(func: Void->Void, error: Void->Void): Void {} | ||||
|  | ||||
| 	public static function removeFromFullscreenChange(func: Void->Void, error: Void->Void): Void {} | ||||
|  | ||||
| 	public static function changeResolution(width: Int, height: Int): Void {} | ||||
|  | ||||
| 	public static function setKeepScreenOn(on: Bool): Void {} | ||||
|  | ||||
| 	public static function loadUrl(url: String): Void {} | ||||
|  | ||||
| 	public static function getGamepadId(index: Int): String { | ||||
| 		return "unknown"; | ||||
| 	} | ||||
|  | ||||
| 	public static function getGamepadVendor(index: Int): String { | ||||
| 		return "unknown"; | ||||
| 	} | ||||
|  | ||||
| 	public static function setGamepadRumble(index: Int, leftAmount: Float, rightAmount: Float): Void {} | ||||
|  | ||||
| 	public static function safeZone(): Float { | ||||
| 		return 1.0; | ||||
| 	} | ||||
|  | ||||
| 	public static function login(): Void {} | ||||
|  | ||||
| 	public static function automaticSafeZone(): Bool { | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
| 	public static function setSafeZone(value: Float): Void {} | ||||
|  | ||||
| 	public static function unlockAchievement(id: Int): Void {} | ||||
|  | ||||
| 	public static function waitingForLogin(): Bool { | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	public static function disallowUserChange(): Void {} | ||||
|  | ||||
| 	public static function allowUserChange(): Void {} | ||||
| } | ||||
|  | ||||
| @ -1,57 +1,56 @@ | ||||
| package kha.audio2; | ||||
|  | ||||
| import kha.Sound; | ||||
| import kha.internal.IntBox; | ||||
|  | ||||
| class Audio { | ||||
| 	public static var disableGcInteractions = false; | ||||
| 	static var intBox: IntBox = new IntBox(0); | ||||
| 	static var buffer: Buffer; | ||||
|  | ||||
| 	public static function _init() { | ||||
| 		var bufferSize = 1024 * 2; | ||||
| 		buffer = new Buffer(bufferSize * 4, 2, 44100); | ||||
| 		Audio.samplesPerSecond = 44100; | ||||
| 	} | ||||
|  | ||||
| 	public static function _callCallback(samples: Int): Void { | ||||
| 		if (buffer == null) | ||||
| 			return; | ||||
| 		if (audioCallback != null) { | ||||
| 			intBox.value = samples; | ||||
| 			audioCallback(intBox, buffer); | ||||
| 		} | ||||
| 		else { | ||||
| 			for (i in 0...samples) { | ||||
| 				buffer.data.set(buffer.writeLocation, 0); | ||||
| 				buffer.writeLocation += 1; | ||||
| 				if (buffer.writeLocation >= buffer.size) { | ||||
| 					buffer.writeLocation = 0; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	public static function _readSample(): Float { | ||||
| 		if (buffer == null) | ||||
| 			return 0; | ||||
| 		var value = buffer.data.get(buffer.readLocation); | ||||
| 		buffer.readLocation += 1; | ||||
| 		if (buffer.readLocation >= buffer.size) { | ||||
| 			buffer.readLocation = 0; | ||||
| 		} | ||||
| 		return value; | ||||
| 	} | ||||
|  | ||||
| 	public static var samplesPerSecond: Int; | ||||
|  | ||||
| 	public static var audioCallback: IntBox->Buffer->Void; | ||||
|  | ||||
| 	public static function play(sound: Sound, loop: Bool = false): kha.audio1.AudioChannel { | ||||
| 		return null; | ||||
| 	} | ||||
|  | ||||
| 	public static function stream(sound: Sound, loop: Bool = false): kha.audio1.AudioChannel { | ||||
| 		return null; | ||||
| 	} | ||||
| } | ||||
| package kha.audio2; | ||||
|  | ||||
| import kha.Sound; | ||||
| import kha.internal.IntBox; | ||||
|  | ||||
| class Audio { | ||||
| 	public static var disableGcInteractions = false; | ||||
| 	static var intBox: IntBox = new IntBox(0); | ||||
| 	static var buffer: Buffer; | ||||
|  | ||||
| 	public static function _init() { | ||||
| 		var bufferSize = 1024 * 2; | ||||
| 		buffer = new Buffer(bufferSize * 4, 2, samplesPerSecond); | ||||
| 	} | ||||
|  | ||||
| 	public static function _callCallback(samples: Int): Void { | ||||
| 		if (buffer == null) | ||||
| 			return; | ||||
| 		if (audioCallback != null) { | ||||
| 			intBox.value = samples; | ||||
| 			audioCallback(intBox, buffer); | ||||
| 		} | ||||
| 		else { | ||||
| 			for (i in 0...samples) { | ||||
| 				buffer.data.set(buffer.writeLocation, 0); | ||||
| 				buffer.writeLocation += 1; | ||||
| 				if (buffer.writeLocation >= buffer.size) { | ||||
| 					buffer.writeLocation = 0; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	public static function _readSample(): FastFloat { | ||||
| 		if (buffer == null) | ||||
| 			return 0; | ||||
| 		var value = buffer.data.get(buffer.readLocation); | ||||
| 		++buffer.readLocation; | ||||
| 		if (buffer.readLocation >= buffer.size) { | ||||
| 			buffer.readLocation = 0; | ||||
| 		} | ||||
| 		return value; | ||||
| 	} | ||||
|  | ||||
| 	public static var samplesPerSecond: Int; | ||||
|  | ||||
| 	public static var audioCallback: IntBox->Buffer->Void; | ||||
|  | ||||
| 	public static function play(sound: Sound, loop: Bool = false): kha.audio1.AudioChannel { | ||||
| 		return null; | ||||
| 	} | ||||
|  | ||||
| 	public static function stream(sound: Sound, loop: Bool = false): kha.audio1.AudioChannel { | ||||
| 		return null; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -59,7 +59,7 @@ class Graphics implements kha.graphics4.Graphics { | ||||
| 	} | ||||
|  | ||||
| 	public function refreshRate(): Int { | ||||
| 		return 60; | ||||
| 		return Krom.displayFrequency(); | ||||
| 	} | ||||
|  | ||||
| 	public function clear(?color: Color, ?depth: Float, ?stencil: Int): Void { | ||||
|  | ||||
| @ -34,22 +34,46 @@ void copySample(void *buffer) { | ||||
| } | ||||
|  | ||||
| int playback_callback(snd_pcm_sframes_t nframes) { | ||||
| 	int err = 0; | ||||
| 	if (kinc_a2_internal_callback(&a2_buffer, nframes)) { | ||||
| 		int ni = 0; | ||||
| 		while (ni < nframes) { | ||||
| 			int i = 0; | ||||
| 			for (; ni < nframes && i < 4096 * 2; ++i, ++ni) { | ||||
| 				copySample(&buf[i * 2]); | ||||
| 			} | ||||
| 			int err2; | ||||
| 			if ((err2 = snd_pcm_writei(playback_handle, buf, i)) < 0) { | ||||
| 				fprintf(stderr, "write failed (%s)\n", snd_strerror(err2)); | ||||
| 			} | ||||
| 			err += err2; | ||||
| 		} | ||||
| 	} | ||||
| 	return err; | ||||
|     int err = 0;  | ||||
|     if (kinc_a2_internal_callback(&a2_buffer, nframes)) { | ||||
|         int ni = 0; | ||||
|         while (ni < nframes) { | ||||
|             int i = 0; | ||||
|             for (; ni < nframes && i < 4096; ++i, ++ni) { | ||||
|                 copySample(&buf[i * 2]); | ||||
|             } | ||||
|             int err2 = snd_pcm_writei(playback_handle, buf, i); | ||||
|             if (err2 < 0) { | ||||
|                 fprintf(stderr, "ALSA write failed in playback_callback: %s\n", snd_strerror(err2)); | ||||
|                 return err2; | ||||
|             } | ||||
|             if (err2 < i) { | ||||
|                 fprintf(stderr, "ALSA short write in playback_callback: wrote %d of %d frames\n", err2, i); | ||||
|             } | ||||
|         } | ||||
|         err = nframes; | ||||
|     } | ||||
|     else { | ||||
|         // Write silence data to prevent recovery | ||||
|         if (nframes > 4096) { | ||||
|              fprintf(stderr, "Warning: ALSA requested %ld frames for silence, exceeding local buffer size %d. Clamping.\n", nframes, 4096); | ||||
|              nframes = 4096;  | ||||
|         } | ||||
|         memset(buf, 0, nframes * 4); | ||||
|  | ||||
|         int err2 = snd_pcm_writei(playback_handle, buf, nframes); | ||||
|  | ||||
|         if (err2 < 0) { | ||||
|             fprintf(stderr, "ALSA silence write failed in playback_callback: %s\n", snd_strerror(err2)); | ||||
|             err = err2; | ||||
|         } else { | ||||
|             if (err2 < nframes) { | ||||
|                 fprintf(stderr, "ALSA short silence write in playback_callback: wrote %d of %d frames\n", err2, (int)nframes); | ||||
|             } | ||||
|             err = err2; | ||||
|         } | ||||
|     } | ||||
|     return err; | ||||
| } | ||||
|  | ||||
| bool tryToRecover(snd_pcm_t *handle, int errorCode) { | ||||
|  | ||||
| @ -140,4 +140,4 @@ void kinc_internal_gamepad_trigger_button(int gamepad, int button, float value) | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| #endif | ||||
| Before Width: | Height: | Size: 417 KiB After Width: | Height: | Size: 281 KiB | 
| Before Width: | Height: | Size: 417 KiB After Width: | Height: | Size: 281 KiB | 
| Before Width: | Height: | Size: 417 KiB After Width: | Height: | Size: 281 KiB | 
| Before Width: | Height: | Size: 417 KiB After Width: | Height: | Size: 281 KiB | 
| Before Width: | Height: | Size: 417 KiB After Width: | Height: | Size: 281 KiB | 
| Before Width: | Height: | Size: 417 KiB After Width: | Height: | Size: 281 KiB | 
							
								
								
									
										
											BIN
										
									
								
								Krom/Krom.exe
									
									
									
									
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								Krom/Krom_opengl.exe
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -2,10 +2,12 @@ | ||||
| -cp ../Kha/Backends/Krom | ||||
| -cp ../leenkx/Sources | ||||
| -cp ../iron/Sources | ||||
| -cp ../lib/aura/Sources | ||||
| -cp ../lib/haxebullet/Sources | ||||
| -cp ../lib/haxerecast/Sources | ||||
| -cp ../lib/zui/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('haxerecast', true, null, ['../lib/haxerecast/Sources']) | ||||
| --macro include('leenkx', true, ['leenkx.network'], ['../leenkx/Sources','../iron/Sources']) | ||||
|  | ||||
							
								
								
									
										35
									
								
								leenkx.py
									
									
									
									
									
								
							
							
						
						| @ -24,7 +24,7 @@ import textwrap | ||||
| import threading | ||||
| import traceback | ||||
| import typing | ||||
| from typing import Callable, Optional | ||||
| from typing import Callable, Optional, List | ||||
| import webbrowser | ||||
|  | ||||
| import bpy | ||||
| @ -33,6 +33,12 @@ from bpy.props import * | ||||
| from bpy.types import Operator, AddonPreferences | ||||
|  | ||||
|  | ||||
| if bpy.app.version < (2, 90, 0):   | ||||
|     ListType = List | ||||
| else: | ||||
|     ListType = list | ||||
|  | ||||
|  | ||||
| class SDKSource(IntEnum): | ||||
|     PREFS = 0 | ||||
|     LOCAL = 1 | ||||
| @ -73,9 +79,10 @@ def detect_sdk_path(): | ||||
|     area = win.screen.areas[0] | ||||
|     area_type = area.type | ||||
|     area.type = "INFO" | ||||
|     with bpy.context.temp_override(window=win, screen=win.screen, area=area): | ||||
|         bpy.ops.info.select_all(action='SELECT') | ||||
|         bpy.ops.info.report_copy() | ||||
|     if bpy.app.version >= (2, 92, 0): | ||||
|         with bpy.context.temp_override(window=win, screen=win.screen, area=area): | ||||
|             bpy.ops.info.select_all(action='SELECT') | ||||
|             bpy.ops.info.report_copy() | ||||
|     area.type = area_type | ||||
|     clipboard = bpy.context.window_manager.clipboard | ||||
|  | ||||
| @ -85,6 +92,7 @@ def detect_sdk_path(): | ||||
|     if match: | ||||
|         addon_prefs.sdk_path = os.path.dirname(match[-1]) | ||||
|  | ||||
|  | ||||
| def get_link_web_server(self): | ||||
|     return self.get('link_web_server', 'http://localhost/') | ||||
|  | ||||
| @ -310,9 +318,9 @@ class LeenkxAddonPreferences(AddonPreferences): | ||||
|         layout.label(text="Welcome to Leenkx!") | ||||
|  | ||||
|         # Compare version Blender and Leenkx (major, minor) | ||||
|         if bpy.app.version[0] != 4 or bpy.app.version[1] != 2: | ||||
|         if bpy.app.version[:2] not in [(4, 4), (4, 2), (3, 6), (3, 3)]: | ||||
|             box = layout.box().column() | ||||
|             box.label(text="Warning: For Leenkx to work correctly, use a Blender LTS version such as 4.2 | 3.6 | 3.3") | ||||
|             box.label(text="Warning: For Leenkx to work correctly, use a Blender LTS version") | ||||
|  | ||||
|         layout.prop(self, "sdk_path") | ||||
|         sdk_path = get_sdk_path(context) | ||||
| @ -558,7 +566,7 @@ def remove_readonly(func, path, excinfo): | ||||
|     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): | ||||
|         p.wait() | ||||
|         if done is not None: | ||||
| @ -840,7 +848,13 @@ def update_leenkx_py(sdk_path: str, force_relink=False): | ||||
|                 else: | ||||
|                     raise err | ||||
|     else: | ||||
|         lnx_module_file.unlink(missing_ok=True) | ||||
|         if bpy.app.version < (2, 92, 0): | ||||
|             try: | ||||
|                 lnx_module_file.unlink() | ||||
|             except FileNotFoundError: | ||||
|                 pass  | ||||
|         else: | ||||
|             lnx_module_file.unlink(missing_ok=True) | ||||
|         shutil.copy(Path(sdk_path) / 'leenkx.py', lnx_module_file) | ||||
|  | ||||
|  | ||||
| @ -914,7 +928,10 @@ def restart_leenkx(context): | ||||
|  | ||||
| @persistent | ||||
| def on_load_post(context): | ||||
|     restart_leenkx(bpy.context)  # context is None, use bpy.context instead | ||||
|     if bpy.context is not None: | ||||
|         restart_leenkx(bpy.context)  # context is None, use bpy.context instead | ||||
|     else: | ||||
|         bpy.app.timers.register(lambda: restart_leenkx(bpy.context), first_interval=0.1) | ||||
|  | ||||
|  | ||||
| def on_register_post(): | ||||
|  | ||||
| @ -3,6 +3,10 @@ | ||||
|  | ||||
| #include "compiled.inc" | ||||
|  | ||||
| #ifdef _CPostprocess | ||||
| uniform vec4 PPComp17; | ||||
| #endif | ||||
|  | ||||
| uniform sampler2D tex; | ||||
| uniform vec2 dir; | ||||
| uniform vec2 screenSize; | ||||
| @ -45,6 +49,12 @@ void main() { | ||||
| 		res += factor * col; | ||||
| 	} | ||||
|  | ||||
| 	#ifdef _CPostprocess | ||||
| 		vec3 AirColor = vec3(PPComp17.x, PPComp17.y, PPComp17.z); | ||||
| 	#else | ||||
| 		vec3 AirColor = volumAirColor; | ||||
| 	#endif | ||||
| 	 | ||||
| 	res /= sumfactor; | ||||
| 	fragColor = vec4(volumAirColor * res, 1.0); | ||||
| 	fragColor = vec4(AirColor * res, 1.0); | ||||
| } | ||||
|  | ||||
| @ -19,6 +19,11 @@ | ||||
| 				{ | ||||
| 					"name": "screenSize", | ||||
| 					"link": "_screenSize" | ||||
| 				}, | ||||
| 				{ | ||||
| 					"name": "PPComp17", | ||||
| 					"link": "_PPComp17", | ||||
| 					"ifdef": ["_CPostprocess"] | ||||
| 				} | ||||
| 			], | ||||
| 			"texture_params": [], | ||||
|  | ||||
| @ -5,7 +5,7 @@ | ||||
| uniform sampler2D tex; | ||||
|  | ||||
| #ifdef _CPostprocess | ||||
| uniform vec3 PPComp13; | ||||
| uniform vec4 PPComp13; | ||||
| #endif | ||||
|  | ||||
| in vec2 texCoord; | ||||
| @ -43,13 +43,17 @@ void main() { | ||||
| 	#ifdef _CPostprocess | ||||
| 		float max_distort = PPComp13.x; | ||||
| 		int num_iter = int(PPComp13.y); | ||||
| 		int CAType = int(PPComp13.z); | ||||
| 		int on = int(PPComp13.w); | ||||
| 	#else | ||||
| 		float max_distort = compoChromaticStrength; | ||||
| 		int num_iter = compoChromaticSamples; | ||||
| 		int CAType = compoChromaticType; | ||||
| 		int on = 1; | ||||
| 	#endif | ||||
|  | ||||
| 	// Spectral | ||||
| 	if (compoChromaticType == 1) { | ||||
| 	if (CAType == 1) { | ||||
| 		float reci_num_iter_f = 1.0 / float(num_iter); | ||||
|  | ||||
| 		vec2 resolution = vec2(1,1); | ||||
| @ -64,7 +68,7 @@ void main() { | ||||
| 			sumcol += w * texture(tex, barrelDistortion(uv, 0.6 * max_distort * t)); | ||||
| 		} | ||||
|  | ||||
| 		fragColor = sumcol / sumw; | ||||
| 		if (on == 1) fragColor = sumcol / sumw; else fragColor = texture(tex, texCoord); | ||||
| 	} | ||||
|  | ||||
| 	// Simple | ||||
| @ -73,6 +77,7 @@ void main() { | ||||
| 		col.x = texture(tex, texCoord + ((vec2(0.0, 1.0) * max_distort) / vec2(1000.0))).x; | ||||
| 		col.y = texture(tex, texCoord + ((vec2(-0.85, -0.5) * max_distort) / vec2(1000.0))).y; | ||||
| 		col.z = texture(tex, texCoord + ((vec2(0.85, -0.5) * max_distort) / vec2(1000.0))).z; | ||||
| 		fragColor = vec4(col.x, col.y, col.z, fragColor.w); | ||||
| 		if (on == 1) fragColor = vec4(col.x, col.y, col.z, fragColor.w);  | ||||
| 		else fragColor = texture(tex, texCoord); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -62,8 +62,11 @@ uniform vec3 PPComp5; | ||||
| uniform vec3 PPComp6; | ||||
| uniform vec3 PPComp7; | ||||
| uniform vec3 PPComp8; | ||||
| uniform vec3 PPComp11; | ||||
| uniform vec3 PPComp14; | ||||
| uniform vec4 PPComp15; | ||||
| uniform vec4 PPComp16; | ||||
| uniform vec4 PPComp18; | ||||
| #endif | ||||
|  | ||||
| // #ifdef _CPos | ||||
| @ -106,6 +109,16 @@ in vec2 texCoord; | ||||
| out vec4 fragColor; | ||||
|  | ||||
| #ifdef _CFog | ||||
| 	#ifdef _CPostprocess | ||||
| 		vec3 FogColor = vec3(PPComp18.x, PPComp18.y, PPComp18.z); | ||||
| 		float FogAmountA = PPComp18.w; | ||||
| 		float FogAmountB = PPComp11.z; | ||||
| 	#else | ||||
| 		vec3 FogColor = compoFogColor; | ||||
| 		float FogAmountA = compoFogAmountA; | ||||
| 		float FogAmountB = compoFogAmountB; | ||||
| 	#endif | ||||
| 	 | ||||
| // const vec3 compoFogColor = vec3(0.5, 0.6, 0.7); | ||||
| // const float compoFogAmountA = 1.0; // b = 0.01 | ||||
| // const float compoFogAmountB = 1.0; // c = 0.1 | ||||
| @ -118,8 +131,8 @@ out vec4 fragColor; | ||||
| // } | ||||
| vec3 applyFog(vec3 rgb, float distance) { | ||||
| 	// float fogAmount = 1.0 - exp(-distance * compoFogAmountA); | ||||
| 	float fogAmount = 1.0 - exp(-distance * (compoFogAmountA / 100)); | ||||
| 	return mix(rgb, compoFogColor, fogAmount); | ||||
| 	float fogAmount = 1.0 - exp(-distance * (FogAmountA / 100)); | ||||
| 	return mix(rgb, FogColor, fogAmount); | ||||
| } | ||||
| #endif | ||||
|  | ||||
| @ -131,7 +144,7 @@ float ConvertEV100ToExposure(float EV100) { | ||||
|     return 1/0.8 * exp2(-EV100); | ||||
| } | ||||
| float ComputeEV(float avgLuminance) { | ||||
|     const float sqAperture = PPComp1[0].x * PPComp1.x; | ||||
|     const float sqAperture = PPComp1.x * PPComp1.x; | ||||
|     const float shutterTime = 1.0 / PPComp1.y; | ||||
|     const float ISO = PPComp1.z; | ||||
|     const float EC = PPComp2.x; | ||||
| @ -349,16 +362,22 @@ void main() { | ||||
|  | ||||
| #ifdef _CSharpen | ||||
| 	#ifdef _CPostprocess | ||||
| 		float strengthSharpen = PPComp14.y; | ||||
| 		float strengthSharpen = PPComp14.y;	 | ||||
| 		vec3 SharpenColor = vec3(PPComp16.x, PPComp16.y, PPComp16.z);  | ||||
| 		float SharpenSize = PPComp16.w; | ||||
| 	#else | ||||
| 		float strengthSharpen = compoSharpenStrength; | ||||
| 		vec3 SharpenColor = compoSharpenColor; | ||||
| 		float SharpenSize = compoSharpenSize; | ||||
| 	#endif | ||||
| 	vec3 col1 = textureLod(tex, texCo + vec2(-texStep.x, -texStep.y) * 1.5, 0.0).rgb; | ||||
| 	vec3 col2 = textureLod(tex, texCo + vec2(texStep.x, -texStep.y) * 1.5, 0.0).rgb; | ||||
| 	vec3 col3 = textureLod(tex, texCo + vec2(-texStep.x, texStep.y) * 1.5, 0.0).rgb; | ||||
| 	vec3 col4 = textureLod(tex, texCo + vec2(texStep.x, texStep.y) * 1.5, 0.0).rgb; | ||||
| 	vec3 col1 = textureLod(tex, texCo + vec2(-texStep.x, -texStep.y) * SharpenSize, 0.0).rgb; | ||||
| 	vec3 col2 = textureLod(tex, texCo + vec2(texStep.x, -texStep.y) * SharpenSize, 0.0).rgb; | ||||
| 	vec3 col3 = textureLod(tex, texCo + vec2(-texStep.x, texStep.y) * SharpenSize, 0.0).rgb; | ||||
| 	vec3 col4 = textureLod(tex, texCo + vec2(texStep.x, texStep.y) * SharpenSize, 0.0).rgb; | ||||
| 	vec3 colavg = (col1 + col2 + col3 + col4) * 0.25; | ||||
| 	fragColor.rgb += (fragColor.rgb - colavg) * strengthSharpen; | ||||
| 	 | ||||
| 	float edgeMagnitude = length(fragColor.rgb - colavg);  | ||||
| 	fragColor.rgb = mix(fragColor.rgb, SharpenColor, min(edgeMagnitude * strengthSharpen * 2.0, 1.0)); | ||||
| #endif | ||||
|  | ||||
| #ifdef _CFog | ||||
| @ -407,7 +426,11 @@ void main() { | ||||
| #endif | ||||
|  | ||||
| #ifdef _CExposure | ||||
| 	fragColor.rgb += fragColor.rgb * compoExposureStrength; | ||||
| 	#ifdef _CPostprocess | ||||
| 		fragColor.rgb+=fragColor.rgb*PPComp8.x; | ||||
| 	#else | ||||
| 		fragColor.rgb+= fragColor.rgb*compoExposureStrength; | ||||
| 	#endif | ||||
| #endif | ||||
|  | ||||
| #ifdef _CPostprocess | ||||
| @ -415,8 +438,13 @@ void main() { | ||||
| #endif | ||||
|  | ||||
| #ifdef _AutoExposure | ||||
| 	#ifdef _CPostprocess | ||||
| 		float AEStrength = PPComp8.y; | ||||
| 	#else | ||||
| 		float AEStrength = autoExposureStrength; | ||||
| 	#endif | ||||
| 	float expo = 2.0 - clamp(length(textureLod(histogram, vec2(0.5, 0.5), 0).rgb), 0.0, 1.0); | ||||
| 	fragColor.rgb *= pow(expo, autoExposureStrength * 2.0); | ||||
| 	fragColor.rgb *= pow(expo, AEStrength * 2.0); | ||||
| #endif | ||||
|  | ||||
| // Clamp color to get rid of INF values that don't work for the tone mapping below | ||||
| @ -475,10 +503,12 @@ fragColor.rgb = min(fragColor.rgb, 65504 * 0.5); | ||||
| 			} else { | ||||
| 				fragColor.rgb = mix(midLumColor, maxLumColor, luminance); | ||||
| 			} | ||||
|  | ||||
| 		} else { | ||||
| 			fragColor.rgb = vec3(0,1,0); //ERROR | ||||
| 		} | ||||
| 		} else if (PPComp4.x == 9){ | ||||
| 			fragColor.rgb = tonemapAgXSimple(fragColor.rgb); | ||||
| 			fragColor.rgb = pow(fragColor.rgb, vec3(1.0 / 2.2)); // To gamma | ||||
| 		} else if (PPComp4.x == 10){ | ||||
| 			fragColor.rgb = tonemapAgXFull(fragColor.rgb); | ||||
| 		} //else { fragColor.rgb = vec3(0,1,0); //ERROR} | ||||
| 	#endif | ||||
|  | ||||
| #else | ||||
| @ -498,6 +528,13 @@ fragColor.rgb = min(fragColor.rgb, 65504 * 0.5); | ||||
| 		fragColor.rgb = pow(fragColor.rgb, vec3(1.0 / 2.2)); // To gamma | ||||
| 		fragColor.rgb = clamp(fragColor.rgb, 0.0, 2.2); | ||||
| 	#endif | ||||
| 	#ifdef _CToneAgXSimple | ||||
| 		fragColor.rgb = tonemapAgXSimple(fragColor.rgb); | ||||
| 		fragColor.rgb = pow(fragColor.rgb, vec3(1.0 / 2.2)); // To gamma | ||||
| 	#endif | ||||
| 	#ifdef _CToneAgXFull | ||||
| 		fragColor.rgb = tonemapAgXFull(fragColor.rgb); | ||||
| 	#endif | ||||
| 	#ifdef _CToneNone | ||||
| 		fragColor.rgb = pow(fragColor.rgb, vec3(1.0 / 2.2)); // To gamma | ||||
| 	#endif | ||||
| @ -614,4 +651,37 @@ fragColor.rgb = min(fragColor.rgb, 65504 * 0.5); | ||||
| #ifdef _CLUT | ||||
| 	fragColor = LUTlookup(fragColor, lutTexture); | ||||
| #endif | ||||
|  | ||||
|  | ||||
| #ifdef _CDitheringBlueNoise | ||||
| 	const float ditherStrength = ditherStrengthValue / 255.0; | ||||
| 	float noise = ditherBlueNoiseStyle(gl_FragCoord.xy); | ||||
| 	float noiseOffset = (noise - 0.5) * ditherStrength; | ||||
| 	fragColor.rgb += noiseOffset; | ||||
| #endif | ||||
|  | ||||
| #ifdef _CDitheringWhiteNoise | ||||
| 	const float ditherStrength = ditherStrengthValue / 255.0; | ||||
| 	float noise = ditherWhiteNoise(gl_FragCoord.xy); | ||||
| 	float noiseOffset = (noise - 0.5) * ditherStrength; | ||||
| 	fragColor.rgb += noiseOffset; | ||||
| #endif | ||||
|  | ||||
| #ifdef _CDitheringOrderedBayer4x4 | ||||
| 	const float ditherStrength = ditherStrengthValue / 255.0; | ||||
| 	float noise = ditherOrderedBayer4x4(ivec2(gl_FragCoord.xy)); | ||||
| 	float noiseOffset = (noise - 0.5) * ditherStrength; | ||||
| 	fragColor.rgb += noiseOffset; | ||||
| #endif | ||||
|  | ||||
| #ifdef _CDitheringOrderedBayer8x8 | ||||
| 	const float ditherStrength = ditherStrengthValue / 255.0; | ||||
| 	float noise = ditherOrderedBayer8x8(ivec2(gl_FragCoord.xy)); | ||||
| 	float noiseOffset = (noise - 0.5) * ditherStrength; | ||||
| 	fragColor.rgb += noiseOffset; | ||||
| #endif | ||||
|  | ||||
| 	//fragColor.rgb = clamp(fragColor.rgb, 0.0, 1.0); | ||||
|  | ||||
|  | ||||
| } | ||||
|  | ||||
| @ -235,6 +235,16 @@ | ||||
| 					"name": "PPComp15", | ||||
| 					"link": "_PPComp15", | ||||
| 					"ifdef": ["_CPostprocess"] | ||||
| 				}, | ||||
| 				{ | ||||
| 					"name": "PPComp16", | ||||
| 					"link": "_PPComp16", | ||||
| 					"ifdef": ["_CPostprocess"] | ||||
| 				}, | ||||
| 				{ | ||||
| 					"name": "PPComp18", | ||||
| 					"link": "_PPComp18", | ||||
| 					"ifdef": ["_CPostprocess"] | ||||
| 				} | ||||
| 			], | ||||
| 			"texture_params": [], | ||||
|  | ||||
| @ -29,10 +29,11 @@ uniform sampler2D gbuffer1; | ||||
| #ifdef _VoxelGI | ||||
| uniform sampler2D voxels_diffuse; | ||||
| uniform sampler2D voxels_specular; | ||||
| #endif | ||||
| #else | ||||
| #ifdef _VoxelAOvar | ||||
| uniform sampler2D voxels_ao; | ||||
| #endif | ||||
| #endif | ||||
| #ifdef _VoxelShadow | ||||
| uniform sampler3D voxels; | ||||
| uniform sampler3D voxelsSDF; | ||||
| @ -56,6 +57,10 @@ uniform vec3 backgroundCol; | ||||
|  | ||||
| #ifdef _SSAO | ||||
| uniform sampler2D ssaotex; | ||||
| #else | ||||
| #ifdef _SSGI | ||||
| uniform sampler2D ssaotex; | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| #ifdef _SSS | ||||
| @ -113,11 +118,15 @@ uniform vec2 cameraPlane; | ||||
| #ifdef _SinglePoint | ||||
| 	#ifdef _Spot | ||||
| 	//!uniform sampler2DShadow shadowMapSpot[1]; | ||||
| 	#ifdef _ShadowMapTransparent | ||||
| 	//!uniform sampler2D shadowMapSpotTransparent[1]; | ||||
| 	#endif | ||||
| 	//!uniform mat4 LWVPSpot[1]; | ||||
| 	#else | ||||
| 	//!uniform samplerCubeShadow shadowMapPoint[1]; | ||||
| 	#ifdef _ShadowMapTransparent | ||||
| 	//!uniform samplerCube shadowMapPointTransparent[1]; | ||||
| 	#endif | ||||
| 	//!uniform vec2 lightProj; | ||||
| 	#endif | ||||
| #endif | ||||
| @ -125,30 +134,40 @@ uniform vec2 cameraPlane; | ||||
| 	#ifdef _ShadowMapAtlas | ||||
| 		#ifdef _SingleAtlas | ||||
| 		uniform sampler2DShadow shadowMapAtlas; | ||||
| 		#ifdef _ShadowMapTransparent | ||||
| 		uniform sampler2D shadowMapAtlasTransparent; | ||||
| 		#endif | ||||
| 		#endif | ||||
| 	#endif | ||||
| 	#ifdef _ShadowMapAtlas | ||||
| 		#ifndef _SingleAtlas | ||||
| 		//!uniform sampler2DShadow shadowMapAtlasPoint; | ||||
| 		#ifdef _ShadowMapTransparent | ||||
| 		//!uniform sampler2D shadowMapAtlasPointTransparent; | ||||
| 		#endif | ||||
| 		//!uniform vec4 pointLightDataArray[4]; | ||||
| 		#endif | ||||
| 		//!uniform vec4 pointLightDataArray[maxLightsCluster * 6]; | ||||
| 	#else | ||||
| 		//!uniform samplerCubeShadow shadowMapPoint[4]; | ||||
| 		#ifdef _ShadowMapTransparent | ||||
| 		//!uniform samplerCube shadowMapPointTransparent[4]; | ||||
| 		#endif | ||||
| 	#endif | ||||
| 	//!uniform vec2 lightProj; | ||||
| 	#ifdef _Spot | ||||
| 		#ifdef _ShadowMapAtlas | ||||
| 		#ifndef _SingleAtlas | ||||
| 		//!uniform sampler2DShadow shadowMapAtlasSpot; | ||||
| 		#ifdef _ShadowMapTransparent | ||||
| 		//!uniform sampler2D shadowMapAtlasSpotTransparent; | ||||
| 		#endif | ||||
| 		#endif | ||||
| 		#else | ||||
| 		//!uniform sampler2DShadow shadowMapSpot[4]; | ||||
| 		#ifdef _ShadowMapTransparent | ||||
| 		//!uniform sampler2D shadowMapSpotTransparent[4]; | ||||
| 		#endif | ||||
| 		#endif | ||||
| 	//!uniform mat4 LWVPSpotArray[maxLightsCluster]; | ||||
| 	#endif | ||||
| #endif | ||||
| @ -161,12 +180,16 @@ uniform vec3 sunCol; | ||||
| 	#ifdef _ShadowMapAtlas | ||||
| 	#ifndef _SingleAtlas | ||||
| 	uniform sampler2DShadow shadowMapAtlasSun; | ||||
| 	#ifdef _ShadowMapTransparent | ||||
| 	uniform sampler2D shadowMapAtlasSunTransparent; | ||||
| 	#endif | ||||
| 	#endif | ||||
| 	#else | ||||
| 	uniform sampler2DShadow shadowMap; | ||||
| 	#ifdef _ShadowMapTransparent | ||||
| 	uniform sampler2D shadowMapTransparent; | ||||
| 	#endif | ||||
| 	#endif | ||||
| 	uniform float shadowsBias; | ||||
| 	#ifdef _CSM | ||||
| 	//!uniform vec4 casData[shadowmapCascades * 4 + 4]; | ||||
| @ -227,17 +250,22 @@ void main() { | ||||
| 	vec4 g2 = textureLod(gbuffer2, texCoord, 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 | ||||
|  | ||||
| #ifndef _VoxelAOvar | ||||
| #ifndef _VoxelGI | ||||
| 	// Envmap | ||||
| #ifdef _Irr | ||||
|  | ||||
| 	vec3 envl = shIrradiance(n, shirr); | ||||
|  | ||||
| 	#ifdef _gbuffer2 | ||||
| @ -271,33 +299,33 @@ void main() { | ||||
| 	envl.rgb *= albedo; | ||||
|  | ||||
| #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 | ||||
|  | ||||
| #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 | ||||
| 	#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 | ||||
|  | ||||
| 	envl.rgb *= envmapStrength * occspec.x; | ||||
|  | ||||
| #ifdef _VoxelGI | ||||
| 	vec4 indirect_diffuse = textureLod(voxels_diffuse, texCoord, 0.0); | ||||
| 	fragColor.rgb = (indirect_diffuse.rgb * albedo + envl.rgb * (1.0 - indirect_diffuse.a)) * 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; | ||||
| #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 | ||||
| 	// vec3 origin = vec3(texCoord * 2.0 - 1.0, 0.99); | ||||
| 	// vec3 direction = vec3(0.0, 0.0, -1.0); | ||||
| @ -317,6 +345,10 @@ void main() { | ||||
| 	// #else | ||||
| 	fragColor.rgb *= textureLod(ssaotex, texCoord, 0.0).r; | ||||
| 	// #endif | ||||
| #else | ||||
| #ifdef _SSGI | ||||
| 	fragColor.rgb += textureLod(ssaotex, texCoord, 0.0).rgb; | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| #ifdef _EmissionShadeless | ||||
| @ -349,40 +381,70 @@ void main() { | ||||
| 	#ifdef _ShadowMap | ||||
| 		#ifdef _CSM | ||||
| 			svisibility = shadowTestCascade( | ||||
| 				#ifdef _ShadowMapAtlas | ||||
| 					#ifndef _SingleAtlas | ||||
| 					shadowMapAtlasSun, shadowMapAtlasSunTransparent | ||||
| 					#else | ||||
| 					shadowMapAtlas, shadowMapAtlasTransparent | ||||
| 					#endif | ||||
| 				#else | ||||
| 				shadowMap, shadowMapTransparent | ||||
| 				#endif | ||||
| 				, eye, p + n * shadowsBias * 10, shadowsBias, false | ||||
| 			); | ||||
| 											#ifdef _ShadowMapAtlas | ||||
| 												#ifdef _ShadowMapTransparent | ||||
| 												#ifndef _SingleAtlas | ||||
| 												shadowMapAtlasSun, shadowMapAtlasSunTransparent | ||||
| 												#else | ||||
| 												shadowMapAtlas, shadowMapAtlasTransparent | ||||
| 												#endif | ||||
| 												#else | ||||
| 												#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 | ||||
| 											); | ||||
| 		#else | ||||
| 			vec4 lPos = LWVP * vec4(p + n * shadowsBias * 100, 1.0); | ||||
| 			if (lPos.w > 0.0) { | ||||
| 				svisibility = shadowTest( | ||||
| 					#ifdef _ShadowMapAtlas | ||||
| 						#ifndef _SingleAtlas | ||||
| 						shadowMapAtlasSun, shadowMapAtlasSunTransparent | ||||
| 						#else | ||||
| 						shadowMapAtlas, shadowMapAtlasTransparent | ||||
| 						#endif | ||||
| 					#else | ||||
| 					shadowMap, shadowMapTransparent | ||||
| 					#endif | ||||
| 					, lPos.xyz / lPos.w, shadowsBias, false | ||||
| 				); | ||||
| 										#ifdef _ShadowMapAtlas | ||||
| 											#ifdef _ShadowMapTransparent | ||||
| 											#ifndef _SingleAtlas | ||||
| 											shadowMapAtlasSun, shadowMapAtlasSunTransparent | ||||
| 											#else | ||||
| 											shadowMapAtlas, shadowMapAtlasTransparent | ||||
| 											#endif | ||||
| 											#else | ||||
| 											#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 | ||||
| 	#endif | ||||
|  | ||||
| 	#ifdef _VoxelShadow | ||||
| 	svisibility *= (1.0 - traceShadow(p, n, voxels, voxelsSDF, sunDir, clipmaps, gl_FragCoord.xy).r) * voxelgiShad; | ||||
| 	svisibility *= (1.0 - traceShadow(p, n, voxels, voxelsSDF, sunDir, clipmaps, gl_FragCoord.xy, -g2.rg).r) * voxelgiShad; | ||||
| 	#endif | ||||
| 	 | ||||
|  | ||||
| 	#ifdef _SSRS | ||||
| 	// vec2 coords = getProjectedCoord(hitCoord); | ||||
| 	// vec2 deltaCoords = abs(vec2(0.5, 0.5) - coords.xy); | ||||
| @ -439,13 +501,16 @@ void main() { | ||||
| 	fragColor.rgb += sampleLight( | ||||
| 		p, n, v, dotNV, pointPos, pointCol, albedo, roughness, occspec.y, f0 | ||||
| 		#ifdef _ShadowMap | ||||
| 			, 0, pointBias, true, false | ||||
| 			, 0, pointBias, true | ||||
| 		#ifdef _ShadowMapTransparent | ||||
| 			, false | ||||
| 		#endif | ||||
| 		#endif | ||||
| 		#ifdef _Spot | ||||
| 		, true, spotData.x, spotData.y, spotDir, spotData.zw, spotRight | ||||
| 		#endif | ||||
| 		#ifdef _VoxelShadow | ||||
| 			, voxels, voxelsSDF, clipmaps | ||||
| 			, voxels, voxelsSDF, clipmaps, -g2.rg | ||||
| 		#endif | ||||
| 		#ifdef _MicroShadowing | ||||
| 		, occspec.x | ||||
| @ -492,7 +557,10 @@ void main() { | ||||
| 			f0 | ||||
| 			#ifdef _ShadowMap | ||||
| 				// 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 | ||||
| 			#ifdef _Spot | ||||
| 			, lightsArray[li * 3 + 2].y != 0.0 | ||||
| @ -503,7 +571,7 @@ void main() { | ||||
| 			, lightsArraySpot[li * 2 + 1].xyz // right | ||||
| 			#endif | ||||
| 			#ifdef _VoxelShadow | ||||
| 			, voxels, voxelsSDF, clipmaps | ||||
| 			, voxels, voxelsSDF, clipmaps, -g2.rg | ||||
| 			#endif | ||||
| 			#ifdef _MicroShadowing | ||||
| 			, occspec.x | ||||
| @ -514,14 +582,5 @@ void main() { | ||||
| 		); | ||||
| 	} | ||||
| #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 | ||||
| } | ||||
|  | ||||
| @ -2,13 +2,22 @@ | ||||
|  | ||||
| #include "compiled.inc" | ||||
|  | ||||
| #ifdef _CPostprocess | ||||
| uniform vec3 PPComp8; | ||||
| #endif | ||||
|  | ||||
| uniform sampler2D tex; | ||||
|  | ||||
| in vec2 texCoord; | ||||
| out vec4 fragColor; | ||||
|  | ||||
| void main() { | ||||
| 	fragColor.a = 0.01 * autoExposureSpeed; | ||||
| 	#ifdef _CPostprocess | ||||
| 		fragColor.a = 0.01 * PPComp8.z; | ||||
| 	#else | ||||
| 		fragColor.a = 0.01 * autoExposureSpeed; | ||||
| 	#endif | ||||
|  | ||||
| 	fragColor.rgb = textureLod(tex, vec2(0.5, 0.5), 0.0).rgb + | ||||
| 					textureLod(tex, vec2(0.2, 0.2), 0.0).rgb + | ||||
| 					textureLod(tex, vec2(0.8, 0.2), 0.0).rgb + | ||||
|  | ||||
| @ -8,7 +8,13 @@ | ||||
| 			"blend_source": "source_alpha", | ||||
| 			"blend_destination": "inverse_source_alpha", | ||||
| 			"blend_operation": "add", | ||||
| 			"links": [], | ||||
| 			"links": [ | ||||
| 				{ | ||||
| 					"name": "PPComp8", | ||||
| 					"link": "_PPComp8", | ||||
| 					"ifdef": ["_CPostprocess"] | ||||
| 				} | ||||
| 			], | ||||
| 			"texture_params": [], | ||||
| 			"vertex_shader": "../include/pass.vert.glsl", | ||||
| 			"fragment_shader": "histogram_pass.frag.glsl" | ||||
|  | ||||
| @ -1,107 +1,506 @@ | ||||
| #version 450 | ||||
|  | ||||
| #include "compiled.inc" | ||||
| #include "std/math.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 gbuffer0; // Normal | ||||
| // #ifdef _RTGI | ||||
| // uniform sampler2D gbuffer1; // Basecol | ||||
| // #endif | ||||
| uniform mat4 P; | ||||
| uniform mat3 V3; | ||||
|  | ||||
| #ifdef _EmissionShaded | ||||
| uniform sampler2D gbufferEmission; | ||||
| #endif | ||||
| uniform sampler2D sveloc; | ||||
| uniform vec2 cameraProj; | ||||
| uniform vec3 eye; | ||||
| uniform vec3 eyeLook; | ||||
| uniform vec2 screenSize; | ||||
| uniform mat4 invVP; | ||||
|  | ||||
| const float angleMix = 0.5f; | ||||
| #ifdef _SSGICone9 | ||||
| const float strength = 2.0 * (1.0 / ssgiStrength); | ||||
| #else | ||||
| const float strength = 2.0 * (1.0 / ssgiStrength) * 1.8; | ||||
| in vec2 texCoord; | ||||
| in vec3 viewRay; | ||||
| out vec3 fragColor; | ||||
|  | ||||
| float metallic; | ||||
| uint matid; | ||||
|  | ||||
| #ifdef _SMSizeUniform | ||||
| //!uniform vec2 smSizeUniform; | ||||
| #endif | ||||
|  | ||||
| in vec3 viewRay; | ||||
| in vec2 texCoord; | ||||
| out float fragColor; | ||||
|  | ||||
| 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; | ||||
| #ifdef _Clusters | ||||
| uniform vec4 lightsArray[maxLights * 3]; | ||||
| 	#ifdef _Spot | ||||
| 	uniform vec4 lightsArraySpot[maxLights * 2]; | ||||
| 	#endif | ||||
| 	return projectedCoord.xy; | ||||
| } | ||||
| uniform sampler2D clustersData; | ||||
| uniform vec2 cameraPlane; | ||||
| #endif | ||||
|  | ||||
| float getDeltaDepth(vec3 hitCoord) { | ||||
| 	coord = getProjectedCoord(hitCoord); | ||||
| 	depth = textureLod(gbufferD, coord, 0.0).r * 2.0 - 1.0; | ||||
| 	vec3 p = getPosView(viewRay, depth, cameraProj); | ||||
| 	return p.z - hitCoord.z; | ||||
| } | ||||
| #ifdef _SinglePoint // Fast path for single light | ||||
| uniform vec3 pointPos; | ||||
| uniform vec3 pointCol; | ||||
| 	#ifdef _ShadowMap | ||||
| 	uniform float pointBias; | ||||
| 	#endif | ||||
| 	#ifdef _Spot | ||||
| 	uniform vec3 spotDir; | ||||
| 	uniform vec3 spotRight; | ||||
| 	uniform vec4 spotData; | ||||
| 	#endif | ||||
| #endif | ||||
|  | ||||
| void rayCast(vec3 dir) { | ||||
| 	hitCoord = vpos; | ||||
| 	dir *= ssgiRayStep * 2; | ||||
| 	float dist = 0.15; | ||||
| 	for (int i = 0; i < ssgiMaxSteps; i++) { | ||||
| 		hitCoord += dir; | ||||
| 		float delta = getDeltaDepth(hitCoord); | ||||
| 		if (delta > 0.0 && delta < 0.2) { | ||||
| 			dist = distance(vpos, hitCoord); | ||||
| 			break; | ||||
| #ifdef _CPostprocess | ||||
|     uniform vec3 PPComp12; | ||||
| #endif | ||||
|  | ||||
| #ifdef _ShadowMap | ||||
| 	#ifdef _SinglePoint | ||||
| 		#ifdef _Spot | ||||
| 			#ifndef _LTC | ||||
| 				uniform sampler2DShadow shadowMapSpot[1]; | ||||
| 				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 | ||||
| 			} | ||||
| 		#endif | ||||
| 		return visibility; | ||||
| 	} | ||||
| 	fragColor += dist; | ||||
| 	// #ifdef _RTGI | ||||
| 	// 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 t1 = cross(n, vec3(0, 0, 1)); | ||||
| 	vec3 t2 = cross(n, vec3(0, 1, 0)); | ||||
| 	if (length(t1) > length(t2)) return normalize(t1); | ||||
| 	else return normalize(t2); | ||||
| vec3 getVisibility(vec3 p, vec3 n, float depth, vec2 uv) { | ||||
| 		vec3 visibility = vec3(0.0); | ||||
| #ifdef _Sun | ||||
| 	#ifdef _ShadowMap | ||||
| 		#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; | ||||
| } | ||||
|  | ||||
| vec3 getWorldPos(vec2 uv, float depth) { | ||||
|     vec4 pos = invVP * vec4(uv * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0); | ||||
|     return pos.xyz / pos.w; | ||||
| } | ||||
|  | ||||
| vec3 getNormal(vec2 uv) { | ||||
|     vec4 g0 = textureLod(gbuffer0, uv, 0.0); | ||||
|     vec2 enc = g0.rg; | ||||
|     vec3 n; | ||||
|     n.z = 1.0 - abs(enc.x) - abs(enc.y); | ||||
|     n.xy = n.z >= 0.0 ? enc.xy : octahedronWrap(enc.xy); | ||||
|     return normalize(n); | ||||
| } | ||||
|  | ||||
| vec3 calculateIndirectLight(vec2 uv, vec3 pos, vec3 normal, float depth) { | ||||
|     // Simplified visibility - replace with your full visibility function if needed | ||||
|     vec3 sampleColor = textureLod(gbuffer1, uv, 0.0).rgb * getVisibility(pos, normal, depth, uv); | ||||
|  | ||||
| 	#ifdef _EmissionShadeless | ||||
| 		if (matid == 1) { // pure emissive material, color stored in basecol | ||||
| 			sampleColor += textureLod(gbuffer1, uv, 0.0).rgb; | ||||
| 		} | ||||
| 	#endif | ||||
| 	#ifdef _EmissionShaded | ||||
| 		#ifdef _EmissionShadeless | ||||
| 		else { | ||||
| 		#endif | ||||
| 			vec3 sampleEmission = textureLod(gbufferEmission, uv, 0.0).rgb; | ||||
| 			sampleColor += sampleEmission; // Emission should be added directly | ||||
| 		#ifdef _EmissionShadeless | ||||
| 		} | ||||
| 		#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() { | ||||
| 	fragColor = 0; | ||||
| 	vec4 g0 = textureLod(gbuffer0, texCoord, 0.0); | ||||
| 	float d = textureLod(gbufferD, texCoord, 0.0).r * 2.0 - 1.0; | ||||
|     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; | ||||
|  | ||||
| 	vec2 enc = g0.rg; | ||||
| 	vec3 n; | ||||
| 	n.z = 1.0 - abs(enc.x) - abs(enc.y); | ||||
| 	n.xy = n.z >= 0.0 ? enc.xy : octahedronWrap(enc.xy); | ||||
| 	n = normalize(V3 * 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); | ||||
|  | ||||
| 	vpos = getPosView(viewRay, d, cameraProj); | ||||
|     vec3 pos = getWorldPos(texCoord, depth); | ||||
|     vec3 normal = getNormal(texCoord); | ||||
|     vec3 centerColor = textureLod(gbuffer1, texCoord, 0.0).rgb; | ||||
|  | ||||
| 	rayCast(n); | ||||
| 	vec3 o1 = normalize(tangent(n)); | ||||
| 	vec3 o2 = (cross(o1, n)); | ||||
| 	vec3 c1 = 0.5f * (o1 + o2); | ||||
| 	vec3 c2 = 0.5f * (o1 - o2); | ||||
| 	rayCast(mix(n, o1, angleMix)); | ||||
| 	rayCast(mix(n, o2, angleMix)); | ||||
| 	rayCast(mix(n, -c1, angleMix)); | ||||
| 	rayCast(mix(n, -c2, angleMix)); | ||||
|     float radius = ssaoRadius; | ||||
|  | ||||
| 	#ifdef _SSGICone9 | ||||
| 	rayCast(mix(n, -o1, angleMix)); | ||||
| 	rayCast(mix(n, -o2, angleMix)); | ||||
| 	rayCast(mix(n, c1, angleMix)); | ||||
| 	rayCast(mix(n, c2, angleMix)); | ||||
|     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", | ||||
| 			"cull_mode": "none", | ||||
| 			"links": [ | ||||
| 				{ | ||||
| 					"name": "invVP", | ||||
| 					"link": "_inverseViewProjectionMatrix" | ||||
| 				}, | ||||
| 				{ | ||||
| 					"name": "P", | ||||
| 					"link": "_projectionMatrix" | ||||
| @ -15,16 +19,180 @@ | ||||
| 					"link": "_viewMatrix3" | ||||
| 				}, | ||||
| 				{ | ||||
| 					"name": "invP", | ||||
| 					"link": "_inverseProjectionMatrix" | ||||
| 					"name": "eye", | ||||
| 					"link": "_cameraPosition" | ||||
| 				},				 | ||||
| 				{ | ||||
| 					"name": "eyeLook", | ||||
| 					"link": "_cameraLook" | ||||
| 				}, | ||||
| 				{ | ||||
| 					"name": "cameraProj", | ||||
| 					"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": [], | ||||
| 			"vertex_shader": "../include/pass_viewray2.vert.glsl", | ||||
| 			"vertex_shader": "../include/pass_viewray.vert.glsl", | ||||
| 			"fragment_shader": "ssgi_pass.frag.glsl" | ||||
| 		} | ||||
| 	] | ||||
|  | ||||
| @ -72,10 +72,11 @@ void main() { | ||||
|     float roughness = g0.z; | ||||
|     vec4 gr = textureLod(gbuffer_refraction, texCoord, 0.0); | ||||
|     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; | ||||
|     if (d == 0.0 || d == 1.0 || opac == 1.0 || ior == 1.0) { | ||||
|         fragColor.rgb = textureLod(tex1, texCoord, 0.0).rgb; | ||||
| 		fragColor.a = opac; | ||||
|         return; | ||||
|     } | ||||
| 	vec2 enc = g0.rg; | ||||
| @ -86,7 +87,7 @@ void main() { | ||||
|  | ||||
|     vec3 viewNormal = V3 * n; | ||||
|     vec3 viewPos = getPosView(viewRay, d, cameraProj); | ||||
|     vec3 refracted = refract(viewPos, viewNormal, 1.0 / ior); | ||||
|     vec3 refracted = refract(normalize(viewPos), viewNormal, 1.0 / ior); | ||||
|     hitCoord = viewPos; | ||||
|  | ||||
|     vec3 dir = refracted * (1.0 - rand(texCoord) * ss_refractionJitter * roughness) * 2.0; | ||||
| @ -98,9 +99,12 @@ void main() { | ||||
| 						clamp(-refracted.z, 0.0, 1.0) * clamp((length(viewPos - hitCoord)), 0.0, 1.0) * coords.w; | ||||
| 	intensity = clamp(intensity, 0.0, 1.0); | ||||
|  | ||||
| 	vec3 refractionCol = textureLod(tex1, coords.xy, 0.0).rgb; | ||||
| 	refractionCol *= intensity; | ||||
| 	vec3 color = textureLod(tex, texCoord.xy, 0.0).rgb; | ||||
| 	vec4 refractionCol = textureLod(tex1, coords.xy, 0.0).rgba; | ||||
| 	refractionCol.a = opac; | ||||
| 	//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, | ||||
| 			"compare_mode": "always", | ||||
| 			"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": [ | ||||
| 				{ | ||||
| 					"name": "P", | ||||
|  | ||||
| @ -1,6 +1,7 @@ | ||||
| // | ||||
| // Copyright (C) 2012 Jorge Jimenez (jorge@iryoku.com) | ||||
| // Copyright (C) 2012 Diego Gutierrez (diegog@unizar.es) | ||||
| // Copyright (C) 2025 Onek8 (info@leenkx.com) | ||||
| // All rights reserved. | ||||
| // | ||||
| // Redistribution and use in source and binary forms, with or without | ||||
| @ -33,6 +34,14 @@ | ||||
| // 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 | ||||
|  | ||||
| #include "compiled.inc" | ||||
| @ -49,67 +58,93 @@ out vec4 fragColor; | ||||
|  | ||||
| const float SSSS_FOVY = 108.0; | ||||
|  | ||||
| // Separable SSS Reflectance | ||||
| // const float sssWidth = 0.005; | ||||
| // Temp hash func -  | ||||
| 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() { | ||||
| 	// Quality = 0 | ||||
| 	const int SSSS_N_SAMPLES  = 11; | ||||
| 	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); | ||||
| 	kernel[2] = vec4(0.0192831, 0.00282018, 0.00084214, -1.28); | ||||
| 	kernel[3] = vec4(0.03639, 0.0130999, 0.00643685, -0.72); | ||||
| 	kernel[4] = vec4(0.0821904, 0.0358608, 0.0209261, -0.32); | ||||
| 	kernel[5] = vec4(0.0771802, 0.113491, 0.0793803, -0.08); | ||||
| 	kernel[6] = vec4(0.0771802, 0.113491, 0.0793803, 0.08); | ||||
| 	kernel[7] = vec4(0.0821904, 0.0358608, 0.0209261, 0.32); | ||||
| 	kernel[8] = vec4(0.03639, 0.0130999, 0.00643685, 0.72); | ||||
| 	kernel[9] = vec4(0.0192831, 0.00282018, 0.00084214, 1.28); | ||||
| 	kernel[10] = vec4(0.00471691, 0.000184771, 5.07565e-005, 2); | ||||
| 	const int SSSS_N_SAMPLES = 15; | ||||
| 	vec4 kernel[SSSS_N_SAMPLES]; | ||||
| 	 | ||||
| 	// color neutral kernel weights to prevent color shifting | ||||
| 	kernel[0] = vec4(0.2, 0.2, 0.2, 0.0); | ||||
| 	kernel[1] = vec4(0.12, 0.12, 0.12, 0.2); | ||||
| 	kernel[2] = vec4(0.09, 0.09, 0.09, 0.4); | ||||
| 	kernel[3] = vec4(0.06, 0.06, 0.06, 0.8); | ||||
| 	kernel[4] = vec4(0.04, 0.04, 0.04, 1.2); | ||||
| 	kernel[5] = vec4(0.025, 0.025, 0.025, 1.6); | ||||
| 	kernel[6] = vec4(0.015, 0.015, 0.015, 2.0); | ||||
| 	kernel[7] = vec4(0.005, 0.005, 0.005, 2.5); | ||||
| 	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); | ||||
|  | ||||
| 	// Fetch linear depth of current pixel | ||||
| 	float depth = textureLod(gbufferD, texCoord, 0.0).r; | ||||
| 	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 scale = distanceToProjectionWindow / depthM; | ||||
|  | ||||
| 	// Calculate the final step to fetch the surrounding pixels | ||||
| 	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++) { | ||||
| 		// Fetch color and depth for current sample | ||||
| 		vec2 offset = texCoord + kernel[i].a * finalStep; | ||||
| 		float sampleJitter = hash13(vec3(texCoord.xy * 720.0, float(i) * 37.45)) * 0.1 - 0.05; | ||||
| 		 | ||||
| 		vec2 offset = texCoord + (kernel[i].a + sampleJitter) * finalStep; | ||||
| 		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": | ||||
| 		//float depth = textureLod(tex, offset, 0.0).r; | ||||
| 		//float s = clamp(300.0f * distanceToProjectionWindow * sssWidth * abs(depthM - depth),0.0,1.0); | ||||
| 		//color.rgb = mix(color.rgb, colorM.rgb, s); | ||||
| 		//#endif | ||||
| 		// Accumulate | ||||
| 		colorBlurred.rgb += kernel[i].rgb * color.rgb; | ||||
| 		 | ||||
| 		// ADJUST FOR SURFACE FOLLOWING | ||||
| 		// 0.0 = disabled (maximum SSS but with bleeding), 1.0 = fully enabled (prevents bleeding but might reduce SSS effect) | ||||
| 		const float SURFACE_FOLLOWING_STRENGTH = 0.15; // Reduced to preserve more SSS effect | ||||
| 		 | ||||
| 		if (SURFACE_FOLLOWING_STRENGTH > 0.0) { | ||||
| 			float sampleDepth = textureLod(gbufferD, offset, 0.0).r; | ||||
| 			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); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		colorBlurred += color.rgb * kernel[i].rgb; | ||||
| 		weightSum += kernel[i].rgb; | ||||
| 	} | ||||
|  | ||||
| 	return colorBlurred; | ||||
| 	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() { | ||||
| 	 | ||||
| 	if (textureLod(gbuffer0, texCoord, 0.0).a == 8192.0) { | ||||
| 		fragColor = clamp(SSSSBlur(), 0.0, 1.0); | ||||
| 	} | ||||
| 	else { | ||||
| 		vec4 originalColor = textureLod(tex, texCoord, 0.0); | ||||
| 		vec4 blurredColor = SSSSBlur(); | ||||
| 		vec4 finalColor = mix(blurredColor, originalColor, 0.15); | ||||
| 		 | ||||
| 		fragColor = clamp(finalColor, 0.0, 1.0); | ||||
| 	} else { | ||||
| 		fragColor = textureLod(tex, texCoord, 0.0); | ||||
| 	} | ||||
| } | ||||
|  | ||||
							
								
								
									
										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_ | ||||
| #define _CONETRACE_GLSL_ | ||||
|  | ||||
| #include "std/voxels_constants.glsl" | ||||
| #include "std/constants.glsl" | ||||
|  | ||||
| // References | ||||
| // 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 step_dist = dist; | ||||
| 	vec3 samplePos; | ||||
| 	vec3 start_pos = origin + n * voxelSize0 * voxelgiOffset; | ||||
| 	vec3 start_pos = origin + n * voxelSize0; | ||||
| 	int clipmap_index0 = 0; | ||||
|  | ||||
| 	vec3 aniso_direction = -dir; | ||||
| 	vec3 face_offset = vec3( | ||||
| 		aniso_direction.x > 0.0 ? 0 : 1, | ||||
| 		aniso_direction.y > 0.0 ? 2 : 3, | ||||
| 		aniso_direction.z > 0.0 ? 4 : 5 | ||||
| 		aniso_direction.x > 0.0 ? 0.0 : 1.0, | ||||
| 		aniso_direction.y > 0.0 ? 2.0 : 3.0, | ||||
| 		aniso_direction.z > 0.0 ? 4.0 : 5.0 | ||||
| 	) / (6 + DIFFUSE_CONE_COUNT); | ||||
| 	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) { | ||||
| 			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; | ||||
| @ -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]) { | ||||
| 	float sum = 0.0; | ||||
| 	vec4 amount = vec4(0.0); | ||||
| 	mat3 TBN = makeTangentBasis(normal); | ||||
| 	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); | ||||
| 		if (cosTheta <= 0) | ||||
| 			continue; | ||||
| @ -166,7 +167,7 @@ vec4 traceDiffuse(const vec3 origin, const vec3 normal, const sampler3D voxels, | ||||
| } | ||||
|  | ||||
| vec4 traceSpecular(const vec3 origin, const vec3 normal, const sampler3D voxels, const sampler3D voxelsSDF, const vec3 viewDir, const float roughness, const float clipmaps[voxelgiClipmapCount * 10], const vec2 pixel, const vec2 velocity) { | ||||
| 	vec3 specularDir = reflect(-viewDir, normal); | ||||
| 	vec3 specularDir = reflect(normalize(-viewDir), normal); | ||||
| 	vec3 P = origin + specularDir * ((BayerMatrix8[int(pixel.x + velocity.x) % 8][int(pixel.y + velocity.y) % 8] - 0.5)) * voxelgiStep; | ||||
| 	vec4 amount = traceCone(voxels, voxelsSDF, P, normal, specularDir, 0, true, roughness, voxelgiStep, clipmaps); | ||||
|  | ||||
| @ -176,9 +177,9 @@ vec4 traceSpecular(const vec3 origin, const vec3 normal, const sampler3D voxels, | ||||
| 	return amount * voxelgiOcc; | ||||
| } | ||||
|  | ||||
| vec4 traceRefraction(const vec3 origin, const vec3 normal, sampler3D voxels, sampler3D voxelsSDF, const vec3 viewDir, const float ior, const float roughness, const float clipmaps[voxelgiClipmapCount * 10], const vec2 pixel, const vec2 velocity) { | ||||
|  	const float transmittance = 1.0; | ||||
|  	vec3 refractionDir = refract(-viewDir, normal, 1.0 / ior); | ||||
| vec4 traceRefraction(const vec3 origin, const vec3 normal, sampler3D voxels, sampler3D voxelsSDF, const vec3 viewDir, const float ior, const float roughness, const float clipmaps[voxelgiClipmapCount * 10], const vec2 pixel, const vec2 velocity, const float opacity) { | ||||
|  	const float transmittance = 1.0 - opacity; | ||||
|  	vec3 refractionDir = refract(normalize(-viewDir), normal, 1.0 / ior); | ||||
|  	vec3 P = origin + refractionDir * (BayerMatrix8[int(pixel.x + velocity.x) % 8][int(pixel.y + velocity.y) % 8] - 0.5) * voxelgiStep; | ||||
| 	vec4 amount =  transmittance * traceCone(voxels, voxelsSDF, P, normal, refractionDir, 0, true, roughness, voxelgiStep, clipmaps); | ||||
|  | ||||
| @ -196,14 +197,14 @@ float traceConeAO(const sampler3D voxels, const vec3 origin, const vec3 n, const | ||||
| 	float dist = voxelSize0; | ||||
| 	float step_dist = dist; | ||||
| 	vec3 samplePos; | ||||
| 	vec3 start_pos = origin + n * voxelSize0 * voxelgiOffset; | ||||
| 	vec3 start_pos = origin + n * voxelSize0; | ||||
| 	int clipmap_index0 = 0; | ||||
|  | ||||
| 	vec3 aniso_direction = -dir; | ||||
| 	vec3 face_offset = vec3( | ||||
| 		aniso_direction.x > 0.0 ? 0 : 1, | ||||
| 		aniso_direction.y > 0.0 ? 2 : 3, | ||||
| 		aniso_direction.z > 0.0 ? 4 : 5 | ||||
| 		aniso_direction.x > 0.0 ? 0.0 : 1.0, | ||||
| 		aniso_direction.y > 0.0 ? 2.0 : 3.0, | ||||
| 		aniso_direction.z > 0.0 ? 4.0 : 5.0 | ||||
| 	) / (6 + DIFFUSE_CONE_COUNT); | ||||
| 	vec3 direction_weight = abs(dir); | ||||
|  | ||||
| @ -259,7 +260,6 @@ float traceAO(const vec3 origin, const vec3 normal, const sampler3D voxels, cons | ||||
| } | ||||
| #endif | ||||
|  | ||||
|  | ||||
| #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 sampleCol = 0.0; | ||||
| @ -267,14 +267,14 @@ float traceConeShadow(const sampler3D voxels, const sampler3D voxelsSDF, const v | ||||
| 	float dist = voxelSize0; | ||||
| 	float step_dist = dist; | ||||
| 	vec3 samplePos; | ||||
| 	vec3 start_pos = origin + n * voxelSize0 * voxelgiOffset; | ||||
| 	vec3 start_pos = origin + n * voxelSize0; | ||||
| 	int clipmap_index0 = 0; | ||||
|  | ||||
| 	vec3 aniso_direction = -dir; | ||||
| 	vec3 face_offset = vec3( | ||||
| 		aniso_direction.x > 0.0 ? 0 : 1, | ||||
| 		aniso_direction.y > 0.0 ? 2 : 3, | ||||
| 		aniso_direction.z > 0.0 ? 4 : 5 | ||||
| 		aniso_direction.x > 0.0 ? 0.0 : 1.0, | ||||
| 		aniso_direction.y > 0.0 ? 2.0 : 3.0, | ||||
| 		aniso_direction.z > 0.0 ? 4.0 : 5.0 | ||||
| 	) / (6 + DIFFUSE_CONE_COUNT); | ||||
| 	vec3 direction_weight = abs(dir); | ||||
| 	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); | ||||
| 		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; | ||||
|  | ||||
| 		if ((any(notEqual(samplePos, clamp(samplePos, 0.0, 1.0))))) { | ||||
| @ -328,9 +328,9 @@ 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) { | ||||
|  	vec3 P = origin + dir * (BayerMatrix8[int(pixel.x) % 8][int(pixel.y) % 8] - 0.5) * voxelgiStep; | ||||
| 	float amount = traceConeShadow(voxels, voxelsSDF, P, normal, dir, DIFFUSE_CONE_APERTURE, voxelgiStep, clipmaps); | ||||
| float 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; | ||||
| 	float amount = traceConeShadow(voxels, voxelsSDF, P, normal, dir, SHADOW_CONE_APERTURE, voxelgiStep, clipmaps); | ||||
| 	amount = clamp(amount, 0.0, 1.0); | ||||
| 	return amount * voxelgiOcc; | ||||
| } | ||||
|  | ||||
| @ -21,29 +21,49 @@ THE SOFTWARE. | ||||
|  */ | ||||
| 
 | ||||
| const int DIFFUSE_CONE_COUNT = 16; | ||||
| const float DIFFUSE_CONE_APERTURE = radians(45.0); | ||||
| 
 | ||||
| const vec3 DIFFUSE_CONE_DIRECTIONS[16] = { | ||||
| 	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 SHADOW_CONE_APERTURE = radians(15.0); | ||||
| 
 | ||||
| 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 }, | ||||
| 	{ 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 }, | ||||
| 	{ 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 } | ||||
| }; | ||||
| 
 | ||||
| @ -1,239 +1,679 @@ | ||||
| #ifndef _LIGHT_GLSL_ | ||||
| #define _LIGHT_GLSL_ | ||||
|  | ||||
| #include "compiled.inc" | ||||
| #include "std/brdf.glsl" | ||||
| #include "std/math.glsl" | ||||
| #ifdef _ShadowMap | ||||
| #include "std/shadows.glsl" | ||||
| #endif | ||||
| #ifdef _VoxelShadow | ||||
| #include "std/conetrace.glsl" | ||||
| //!uniform sampler2D voxels_shadows; | ||||
| #endif | ||||
| #ifdef _LTC | ||||
| #include "std/ltc.glsl" | ||||
| #endif | ||||
| #ifdef _LightIES | ||||
| #include "std/ies.glsl" | ||||
| #endif | ||||
| #ifdef _SSRS | ||||
| #include "std/ssrs.glsl" | ||||
| #endif | ||||
| #ifdef _Spot | ||||
| #include "std/light_common.glsl" | ||||
| #endif | ||||
|  | ||||
| #ifdef _ShadowMap | ||||
| 	#ifdef _SinglePoint | ||||
| 		#ifdef _Spot | ||||
| 			#ifndef _LTC | ||||
| 				uniform sampler2DShadow shadowMapSpot[1]; | ||||
| 				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; | ||||
| 		#endif | ||||
| 		#else | ||||
| 		uniform samplerCubeShadow shadowMapPoint[4]; | ||||
| 		uniform samplerCube shadowMapPointTransparent[4]; | ||||
| 		#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 sampler2D shadowMapSpotTransparent[maxLightsCluster]; | ||||
| 		uniform mat4 LWVPSpotArray[maxLightsCluster]; | ||||
| 	#endif | ||||
| 	#endif | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| 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 | ||||
| 	#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 | ||||
| 	#ifdef _VoxelShadow | ||||
| 		, sampler3D voxels, sampler3D voxelsSDF, float clipmaps[10 * voxelgiClipmapCount] | ||||
| 	#endif | ||||
| 	#ifdef _MicroShadowing | ||||
| 		, float occ | ||||
| 	#endif | ||||
| 	#ifdef _SSRS | ||||
| 		, sampler2D gbufferD, mat4 invVP, vec3 eye | ||||
| 	#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 _MicroShadowing | ||||
| 	direct *= clamp(dotNL + 2.0 * occ * occ - 1.0, 0.0, 1.0); | ||||
| 	#endif | ||||
|  | ||||
| 	#ifdef _SSRS | ||||
| 	direct *= traceShadowSS(l, p, gbufferD, invVP, eye); | ||||
| 	#endif | ||||
|  | ||||
| 	#ifdef _VoxelShadow | ||||
| 	direct *= (1.0 - traceShadow(p, n, voxels, voxelsSDF, l, clipmaps, gl_FragCoord.xy).r) * voxelgiShad; | ||||
| 	#endif | ||||
|  | ||||
| 	#ifdef _LTC | ||||
| 	#ifdef _ShadowMap | ||||
| 		if (receiveShadow) { | ||||
| 			#ifdef _SinglePoint | ||||
| 			vec4 lPos = LWVPSpotArray[0] * vec4(p + n * bias * 10, 1.0); | ||||
| 			direct *= 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) direct *= shadowTest(shadowMapSpot[0], shadowMapSpotTransparent[0], lPos.xyz / lPos.w, bias, transparent); | ||||
| 			else if (index == 1) direct *= shadowTest(shadowMapSpot[1], shadowMapSpotTransparent[1], lPos.xyz / lPos.w, bias, transparent); | ||||
| 			else if (index == 2) direct *= shadowTest(shadowMapSpot[2], shadowMapSpotTransparent[2], lPos.xyz / lPos.w, bias, transparent); | ||||
| 			else if (index == 3) direct *= shadowTest(shadowMapSpot[3], shadowMapSpotTransparent[3], lPos.xyz / lPos.w, bias, transparent); | ||||
| 			#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 = LWVPSpot[0] * vec4(p + n * bias * 10, 1.0); | ||||
| 				direct *= 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 | ||||
| 						direct *= shadowTest( | ||||
| 							#ifndef _SingleAtlas | ||||
| 							shadowMapAtlasSpot, shadowMapAtlasSpotTransparent | ||||
| 							#else | ||||
| 							shadowMapAtlas, shadowMapAtlasTransparent | ||||
| 							#endif | ||||
| 							, lPos.xyz / lPos.w, bias, transparent | ||||
| 						); | ||||
| 					#else | ||||
| 							 if (index == 0) direct *= shadowTest(shadowMapSpot[0], shadowMapSpotTransparent[0], lPos.xyz / lPos.w, bias, transparent); | ||||
| 						else if (index == 1) direct *= shadowTest(shadowMapSpot[1], shadowMapSpotTransparent[1], lPos.xyz / lPos.w, bias, transparent); | ||||
| 						else if (index == 2) direct *= shadowTest(shadowMapSpot[2], shadowMapSpotTransparent[2], lPos.xyz / lPos.w, bias, transparent); | ||||
| 						else if (index == 3) direct *= shadowTest(shadowMapSpot[3], shadowMapSpotTransparent[3], lPos.xyz / lPos.w, bias, transparent); | ||||
| 					#endif | ||||
| 				#endif | ||||
| 			} | ||||
| 		#endif | ||||
| 		return direct; | ||||
| 	} | ||||
| 	#endif | ||||
|  | ||||
| 	#ifdef _LightIES | ||||
| 	direct *= iesAttenuation(-l); | ||||
| 	#endif | ||||
|  | ||||
| 	#ifdef _ShadowMap | ||||
| 		if (receiveShadow) { | ||||
| 			#ifdef _SinglePoint | ||||
| 			#ifndef _Spot | ||||
| 			direct *= PCFCube(shadowMapPoint[0], shadowMapPointTransparent[0], ld, -l, bias, lightProj, n, transparent); | ||||
| 			#endif | ||||
| 			#endif | ||||
| 			#ifdef _Clusters | ||||
| 				#ifdef _ShadowMapAtlas | ||||
| 				direct *= PCFFakeCube( | ||||
| 					#ifndef _SingleAtlas | ||||
| 					shadowMapAtlasPoint, shadowMapAtlasPointTransparent | ||||
| 					#else | ||||
| 					shadowMapAtlas, shadowMapAtlasTransparent | ||||
| 					#endif | ||||
| 					, ld, -l, bias, lightProj, n, index, transparent | ||||
| 				); | ||||
| 				#else | ||||
| 					 if (index == 0) direct *= PCFCube(shadowMapPoint[0], shadowMapPointTransparent[0], ld, -l, bias, lightProj, n, transparent); | ||||
| 				else if (index == 1) direct *= PCFCube(shadowMapPoint[1], shadowMapPointTransparent[1], ld, -l, bias, lightProj, n, transparent); | ||||
| 				else if (index == 2) direct *= PCFCube(shadowMapPoint[2], shadowMapPointTransparent[2], ld, -l, bias, lightProj, n, transparent); | ||||
| 				else if (index == 3) direct *= PCFCube(shadowMapPoint[3], shadowMapPointTransparent[3], ld, -l, bias, lightProj, n, transparent); | ||||
| 				#endif | ||||
| 			#endif | ||||
| 		} | ||||
| 	#endif | ||||
|  | ||||
| 	return direct; | ||||
| } | ||||
|  | ||||
| #endif | ||||
| #ifndef _LIGHT_GLSL_ | ||||
| #define _LIGHT_GLSL_ | ||||
|  | ||||
| #include "compiled.inc" | ||||
| #include "std/brdf.glsl" | ||||
| #include "std/math.glsl" | ||||
| #ifdef _ShadowMap | ||||
| #include "std/shadows.glsl" | ||||
| #endif | ||||
| #ifdef _VoxelShadow | ||||
| #include "std/conetrace.glsl" | ||||
| #endif | ||||
| #ifdef _LTC | ||||
| #include "std/ltc.glsl" | ||||
| #endif | ||||
| #ifdef _LightIES | ||||
| #include "std/ies.glsl" | ||||
| #endif | ||||
| #ifdef _SSRS | ||||
| #include "std/ssrs.glsl" | ||||
| #endif | ||||
| #ifdef _Spot | ||||
| #include "std/light_common.glsl" | ||||
| #endif | ||||
| #ifdef _VoxelShadow | ||||
| #include "std/conetrace.glsl" | ||||
| #endif | ||||
|  | ||||
| #ifdef _ShadowMap | ||||
| 	#ifdef _SinglePoint | ||||
| 		#ifdef _Spot | ||||
| 			#ifndef _LTC | ||||
| 				uniform sampler2DShadow shadowMapSpot[1]; | ||||
| 				#ifdef _ShadowMapTransparent | ||||
| 				uniform sampler2D shadowMapSpotTransparent[1]; | ||||
| 				#endif | ||||
| 				uniform mat4 LWVPSpotArray[1]; | ||||
| 			#endif | ||||
| 		#else | ||||
| 			uniform samplerCubeShadow shadowMapPoint[1]; | ||||
| 			#ifdef _ShadowMapTransparent | ||||
| 			uniform samplerCube shadowMapPointTransparent[1]; | ||||
| 			#endif | ||||
| 			uniform vec2 lightProj; | ||||
| 		#endif | ||||
| 	#endif | ||||
| 	#ifdef _Clusters | ||||
| 		#ifdef _SingleAtlas | ||||
| 		//!uniform sampler2DShadow shadowMapAtlas; | ||||
| 		#ifdef _ShadowMapTransparent | ||||
| 		//!uniform sampler2D shadowMapAtlasTransparent; | ||||
| 		#endif | ||||
| 		#endif | ||||
| 		uniform vec2 lightProj; | ||||
| 		#ifdef _ShadowMapAtlas | ||||
| 		#ifndef _SingleAtlas | ||||
| 		uniform sampler2DShadow shadowMapAtlasPoint; | ||||
| 		#ifdef _ShadowMapTransparent | ||||
| 		uniform sampler2D shadowMapAtlasPointTransparent; | ||||
| 		#endif | ||||
| 		#endif | ||||
| 		#else | ||||
| 		uniform samplerCubeShadow shadowMapPoint[4]; | ||||
| 		#ifdef _ShadowMapTransparent | ||||
| 		uniform samplerCube shadowMapPointTransparent[4]; | ||||
| 		#endif | ||||
| 		#endif | ||||
| 		#ifdef _Spot | ||||
| 			#ifdef _ShadowMapAtlas | ||||
| 			#ifndef _SingleAtlas | ||||
| 			uniform sampler2DShadow shadowMapAtlasSpot; | ||||
| 			#ifdef _ShadowMapTransparent | ||||
| 			uniform sampler2D shadowMapAtlasSpotTransparent; | ||||
| 			#endif | ||||
| 			#endif | ||||
| 			#else | ||||
| 			uniform sampler2DShadow shadowMapSpot[4]; | ||||
| 			#ifdef _ShadowMapTransparent | ||||
| 			uniform sampler2D shadowMapSpotTransparent[4]; | ||||
| 			#endif | ||||
| 			#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]; | ||||
| 		#ifdef _ShadowMapTransparent | ||||
| 		uniform sampler2D shadowMapSpotTransparent[1]; | ||||
| 		#endif | ||||
| 		uniform mat4 LWVPSpotArray[1]; | ||||
| 	#endif | ||||
| 	#ifdef _Clusters | ||||
| 		uniform sampler2DShadow shadowMapSpot[maxLightsCluster]; | ||||
| 		#ifdef _ShadowMapTransparent | ||||
| 		uniform sampler2D shadowMapSpotTransparent[maxLightsCluster]; | ||||
| 		#endif | ||||
| 		uniform mat4 LWVPSpotArray[maxLightsCluster]; | ||||
| 	#endif | ||||
| #endif | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| 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 | ||||
| 	#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 | ||||
| 	#ifdef _VoxelShadow | ||||
| 		, sampler3D voxels, sampler3D voxelsSDF, float clipmaps[10 * voxelgiClipmapCount], vec2 velocity | ||||
| 	#endif | ||||
| 	#ifdef _MicroShadowing | ||||
| 		, float occ | ||||
| 	#endif | ||||
| 	#ifdef _SSRS | ||||
| 		, sampler2D gbufferD, mat4 invVP, vec3 eye | ||||
| 	#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 _MicroShadowing | ||||
| 	direct *= clamp(dotNL + 2.0 * occ * occ - 1.0, 0.0, 1.0); | ||||
| 	#endif | ||||
|  | ||||
| 	#ifdef _SSRS | ||||
| 	direct *= traceShadowSS(l, p, gbufferD, invVP, eye); | ||||
| 	#endif | ||||
|  | ||||
| 	#ifdef _VoxelShadow | ||||
| 	vec3 lightDir = l; | ||||
| 	#ifdef _Spot | ||||
| 	if (isSpot) | ||||
| 		lightDir = spotDir; | ||||
| 	#endif | ||||
| 	direct *= (1.0 - traceShadow(p, n, voxels, voxelsSDF, lightDir, clipmaps, gl_FragCoord.xy, velocity).r) * voxelgiShad; | ||||
| 	#endif | ||||
|  | ||||
| 	#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; | ||||
| } | ||||
|  | ||||
| #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 | ||||
|  | ||||
| @ -58,7 +58,15 @@ vec2 sampleCube(vec3 dir, out int faceIndex) { | ||||
| } | ||||
| #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); | ||||
| 	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)); | ||||
| @ -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 = result.xxx / 9.0; | ||||
|  | ||||
| 	#ifdef _ShadowMapTransparent | ||||
| 	if (transparent == false) { | ||||
| 		vec4 shadowmap_transparent = texture(shadowMapTransparent, uv); | ||||
| 		if (shadowmap_transparent.a < compare) | ||||
| 			result *= shadowmap_transparent.rgb; | ||||
| 	} | ||||
| 	#endif | ||||
|  | ||||
| 	return result; | ||||
| } | ||||
| @ -87,7 +97,15 @@ float lpToDepth(vec3 lp, const vec2 lightProj) { | ||||
| 	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... | ||||
| 	float compare = lpToDepth(lp, lightProj) - bias * 1.5; | ||||
| 	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 = result.xxx / 9.0; | ||||
|  | ||||
| 	#ifdef _ShadowMapTransparent | ||||
| 	if (transparent == false) { | ||||
| 		vec4 shadowmap_transparent = texture(shadowMapCubeTransparent, ml); | ||||
| 		if (shadowmap_transparent.a < compare) | ||||
| 			result *= shadowmap_transparent.rgb; | ||||
| 	} | ||||
| 	#endif | ||||
|  | ||||
| 	return result; | ||||
| } | ||||
| @ -209,21 +229,31 @@ vec2 transformOffsetedUV(const int faceIndex, out int newFaceIndex, vec2 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 float compare = lpToDepth(lp, lightProj) - bias * 1.5; | ||||
| 	ml = ml + n * bias * 20; | ||||
|  | ||||
| 	int faceIndex = 0; | ||||
| 	const int lightIndex = index * 6; | ||||
| 	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 | ||||
| 	vec2 uvtiled = pointLightTile.z * uv + pointLightTile.xy; | ||||
| 	#ifdef _FlipY | ||||
| 	uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system | ||||
| 	#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); | ||||
| 	result.x += texture(shadowMap, vec3(uvtiled, compare)); | ||||
| 	// soft shadowing | ||||
| @ -236,14 +266,6 @@ vec3 PCFFakeCube(sampler2DShadow shadowMap, sampler2D shadowMapTransparent, cons | ||||
| 	#endif | ||||
| 	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))); | ||||
| 	pointLightTile = pointLightDataArray[lightIndex + newFaceIndex]; | ||||
| 	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 | ||||
| 	#endif | ||||
|  | ||||
| 	#ifdef _ShadowMapTransparent | ||||
| 	if (transparent == false) { | ||||
| 		vec4 shadowmap_transparent = texture(shadowMapTransparent, uvtiled); | ||||
| 		if (shadowmap_transparent.a < compare) | ||||
| 			result *= shadowmap_transparent.rgb; | ||||
| 	} | ||||
| 	#endif | ||||
|  | ||||
| 	return result; | ||||
| } | ||||
| #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 | ||||
| 	vec2 smSize = smSizeUniform; | ||||
| 	#else | ||||
| 	const vec2 smSize = shadowmapSize; | ||||
| 	#endif | ||||
| 	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 | ||||
| mat4 getCascadeMat(const float d, out int casi, out int casIndex) { | ||||
| 	const int c = shadowmapCascades; | ||||
|  | ||||
| 	// Get cascade index | ||||
| 	// 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)); | ||||
| @ -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].w)); | ||||
| 	casi = int(min(dot(ci, comp), c)); | ||||
|  | ||||
| 	// Get cascade mat | ||||
| 	casIndex = casi * 4; | ||||
|  | ||||
| 	return mat4( | ||||
| 		casData[casIndex    ], | ||||
| 		casData[casIndex + 1], | ||||
| 		casData[casIndex + 2], | ||||
| 		casData[casIndex + 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 | ||||
| 	vec2 smSize = smSizeUniform; | ||||
| 	#else | ||||
| @ -361,16 +405,22 @@ vec3 shadowTestCascade(sampler2DShadow shadowMap, sampler2D shadowMapTransparent | ||||
| 	#endif | ||||
| 	const int c = shadowmapCascades; | ||||
| 	float d = distance(eye, p); | ||||
|  | ||||
| 	int casi; | ||||
| 	int casIndex; | ||||
| 	mat4 LWVP = getCascadeMat(d, casi, casIndex); | ||||
|  | ||||
| 	vec4 lPos = LWVP * vec4(p, 1.0); | ||||
| 	lPos.xyz /= lPos.w; | ||||
|  | ||||
| 	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 | ||||
| 	// https://github.com/TheRealMJP/Shadows | ||||
| @ -389,13 +439,20 @@ vec3 shadowTestCascade(sampler2DShadow shadowMap, sampler2D shadowMapTransparent | ||||
| 		vec4 lPos2 = LWVP2 * vec4(p, 1.0); | ||||
| 		lPos2.xyz /= lPos2.w; | ||||
| 		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); | ||||
| 		return mix(visibility2, visibility, lerpAmt); | ||||
| 	} | ||||
| 	return visibility; | ||||
|  | ||||
| 	// Visualize cascades | ||||
| 	// if (ci == 0) albedo.rgb = vec3(1.0, 0.0, 0.0); | ||||
| 	// if (ci == 4) albedo.rgb = vec3(0.0, 1.0, 0.0); | ||||
| @ -403,4 +460,4 @@ vec3 shadowTestCascade(sampler2DShadow shadowMap, sampler2D shadowMapTransparent | ||||
| 	// if (ci == 12) albedo.rgb = vec3(1.0, 1.0, 0.0); | ||||
| } | ||||
| #endif | ||||
| #endif | ||||
| #endif | ||||
| @ -1,4 +1,3 @@ | ||||
|  | ||||
| vec3 uncharted2Tonemap(const vec3 x) { | ||||
| 	const float A = 0.15; | ||||
| 	const float B = 0.50; | ||||
| @ -12,6 +11,8 @@ vec3 uncharted2Tonemap(const vec3 x) { | ||||
| vec3 tonemapUncharted2(const vec3 color) { | ||||
| 	const float W = 11.2; | ||||
| 	const float exposureBias = 2.0; | ||||
|     // TODO - Find out why black world value of 0.0,0.0,0.0 turns to white pixels | ||||
| 	if (dot(color, color) < 0.001) return vec3(0.001); | ||||
| 	vec3 curr = uncharted2Tonemap(exposureBias * color); | ||||
| 	vec3 whiteScale = 1.0 / uncharted2Tonemap(vec3(W)); | ||||
| 	return curr * whiteScale; | ||||
| @ -36,3 +37,106 @@ vec3 acesFilm(const vec3 x) { | ||||
| vec3 tonemapReinhard(const vec3 color) { | ||||
| 	return color / (color + vec3(1.0)); | ||||
| } | ||||
|  | ||||
| // Blender AgX Implementation  | ||||
| // Troy Sobotka https://github.com/sobotka/AgX | ||||
|  | ||||
| // AGX Simple | ||||
| vec3 tonemapAgXSimple(vec3 x) { | ||||
| 	// TODO CORRECT AND OPTIMIZE | ||||
|     x = max(x, vec3(0.0)); | ||||
|     float exposure = 0.6; | ||||
|     x *= exposure; | ||||
|     const vec3 AgX_A = vec3(0.92, 0.92, 0.72); | ||||
|     const vec3 AgX_B = vec3(0.24, 0.24, 0.36); | ||||
|     const vec3 AgX_C = vec3(0.92, 0.92, 0.72); | ||||
|     const vec3 AgX_D = vec3(0.24, 0.24, 0.36); | ||||
|     const vec3 AgX_E = vec3(0.08, 0.08, 0.12); | ||||
|     const vec3 AgX_F = vec3(0.0); | ||||
|     vec3 result = (x * (AgX_A * x + AgX_B)) / (x * (AgX_C * x + AgX_D) + AgX_E) + AgX_F; | ||||
|     float luma = dot(result, vec3(0.2126, 0.7152, 0.0722)); | ||||
|     result = mix(vec3(luma), result, 0.6); | ||||
|     return clamp(result, vec3(0.0), vec3(1.0)); | ||||
| } | ||||
|  | ||||
| // AGX Full Contrast Approx | ||||
| vec3 agxDefaultContrastApprox(vec3 x) { | ||||
|     vec3 x2 = x * x; | ||||
|     vec3 x4 = x2 * x2; | ||||
|     return + 15.5     * x4 * x2 | ||||
|            - 40.14    * x4 * x | ||||
|            + 31.96    * x4 | ||||
|            - 6.868    * x2 * x | ||||
|            + 0.4298   * x2 | ||||
|            + 0.1191   * x | ||||
|            - 0.00232; | ||||
| } | ||||
| // AGX Full Look | ||||
| vec3 agxLook(vec3 x, float strength) { | ||||
|     const vec3 slope = vec3(1.0); | ||||
|     const vec3 power = vec3(1.35); | ||||
|     const vec3 sat = vec3(1.4); | ||||
|     vec3 lw = vec3(0.2126, 0.7152, 0.0722); | ||||
|     float luma = dot(x, lw); | ||||
|     return pow(x * slope, power) * sat - (pow(luma * slope, power) * (sat - 1.0)); | ||||
| } | ||||
|  | ||||
| // AGX Full | ||||
| vec3 tonemapAgXFull(vec3 x) { | ||||
|     // x *= 2.0 * (1.0/0.8); // Brightness scale to match Blender's default | ||||
|     x = clamp(x, 0.0, 65504.0); | ||||
|     x = log2(x + 1.0); | ||||
|     x = agxDefaultContrastApprox(clamp(x * 0.5 - 10.5, -12.0, 12.0));     | ||||
|     x = mix(x, agxLook(x, 0.5), 0.5); | ||||
|     x = clamp(x, 0.0, 1.0); | ||||
|     return pow(x, vec3(1.0/2.2));  | ||||
| } | ||||
|  | ||||
|  | ||||
| // Interleaved Gradient Noise (Pseudo-random, AKA Blue Noise style) | ||||
| // Based on http://momentsingraphics.de/BlueNoise.html | ||||
| float ditherBlueNoiseStyle(vec2 p) { | ||||
|     return fract(sin(dot(p.xy, vec2(12.9898, 78.233))) * 43758.5453123); | ||||
| } | ||||
|  | ||||
| // White Noise Dithering | ||||
| float ditherWhiteNoise(vec2 p) { | ||||
|     return fract(sin(dot(p, vec2(12.9898, 4.1414))) * 43758.5453); | ||||
| } | ||||
|  | ||||
| // Ordered Dithering (4x4 Bayer Matrix) | ||||
| float ditherOrderedBayer4x4(ivec2 p) { | ||||
|     const float bayer[16] = float[16]( | ||||
|          0.0,  8.0,  2.0, 10.0, | ||||
|         12.0,  4.0, 14.0,  6.0, | ||||
|          3.0, 11.0,  1.0,  9.0, | ||||
|         15.0,  7.0, 13.0,  5.0 | ||||
|     ); | ||||
|     int index = (p.x % 4) * 4 + (p.y % 4); | ||||
|     return bayer[index] / 16.0; | ||||
| } | ||||
|  | ||||
| // Ordered Dithering (8x8 Bayer Matrix) | ||||
| float ditherOrderedBayer8x8(ivec2 p) { | ||||
|     const float bayer8x8[64] = float[64]( | ||||
|          0.0, 32.0,  8.0, 40.0,  2.0, 34.0, 10.0, 42.0, | ||||
|         48.0, 16.0, 56.0, 24.0, 50.0, 18.0, 58.0, 26.0, | ||||
|         12.0, 44.0,  4.0, 36.0, 14.0, 46.0,  6.0, 38.0, | ||||
|         60.0, 28.0, 52.0, 20.0, 62.0, 30.0, 54.0, 22.0, | ||||
|          3.0, 35.0, 11.0, 43.0,  1.0, 33.0,  9.0, 41.0, | ||||
|         51.0, 19.0, 59.0, 27.0, 49.0, 17.0, 57.0, 25.0, | ||||
|         15.0, 47.0,  7.0, 39.0, 13.0, 45.0,  5.0, 37.0, | ||||
|         63.0, 31.0, 55.0, 23.0, 61.0, 29.0, 53.0, 21.0 | ||||
|     ); | ||||
|     int index = (p.x % 8) * 8 + (p.y % 8); | ||||
|     return bayer8x8[index] / 64.0; | ||||
| } | ||||
|  | ||||
|  | ||||
| //vec3 applyDither(vec3 color, vec2 screenCoord) { | ||||
| //    float quantizationLevels = 255.0; | ||||
| //    float noise = randomDither(screenCoord); | ||||
| //    float noiseOffset = (noise - 0.5) / quantizationLevels; | ||||
| //    vec3 ditheredColor = color + noiseOffset; | ||||
| //    return clamp(ditheredColor, 0.0, 1.0); | ||||
| //} | ||||
|  | ||||
| @ -11,6 +11,11 @@ | ||||
| #include "std/light_common.glsl" | ||||
| #endif | ||||
|  | ||||
| #ifdef _CPostprocess | ||||
| uniform vec3 PPComp11; | ||||
| uniform vec4 PPComp17; | ||||
| #endif | ||||
|  | ||||
| uniform sampler2D gbufferD; | ||||
| uniform sampler2D snoise; | ||||
|  | ||||
| @ -87,7 +92,13 @@ out float fragColor; | ||||
| const float tScat = 0.08; | ||||
| const float tAbs = 0.0; | ||||
| const float tExt = tScat + tAbs; | ||||
| const float stepLen = 1.0 / volumSteps; | ||||
| #ifdef _CPostprocess | ||||
| 	float stepLen = 1.0 / int(PPComp11.y); | ||||
| 	float AirTurbidity = PPComp17.w; | ||||
| #else | ||||
| 	const float stepLen = 1.0 / volumSteps; | ||||
| 	float AirTurbidity = volumAirTurbidity; | ||||
| #endif | ||||
| const float lighting = 0.4; | ||||
|  | ||||
| void rayStep(inout vec3 curPos, inout float curOpticalDepth, inout float scatteredLightAmount, float stepLenWorld, vec3 viewVecNorm) { | ||||
| @ -162,5 +173,5 @@ void main() { | ||||
| 		rayStep(curPos, curOpticalDepth, scatteredLightAmount, stepLenWorld, viewVecNorm); | ||||
| 	} | ||||
|  | ||||
| 	fragColor = scatteredLightAmount * volumAirTurbidity; | ||||
| 	fragColor = scatteredLightAmount * AirTurbidity; | ||||
| } | ||||
|  | ||||
| @ -140,6 +140,16 @@ | ||||
| 					"link": "_biasLightWorldViewProjectionMatrixSpot3", | ||||
| 					"ifndef": ["_ShadowMapAtlas"], | ||||
| 					"ifdef": ["_Spot", "_ShadowMap"] | ||||
| 				}, | ||||
| 				{ | ||||
| 					"name": "PPComp11", | ||||
| 					"link": "_PPComp11", | ||||
| 					"ifdef": ["_CPostprocess"] | ||||
| 				}, | ||||
| 				{ | ||||
| 					"name": "PPComp17", | ||||
| 					"link": "_PPComp17", | ||||
| 					"ifdef": ["_CPostprocess"] | ||||
| 				} | ||||
| 			], | ||||
| 			"texture_params": [], | ||||
|  | ||||
| @ -33,6 +33,7 @@ uniform layout(r32ui) uimage3D voxelsLight; | ||||
|  | ||||
| #ifdef _ShadowMap | ||||
| uniform sampler2DShadow shadowMap; | ||||
| uniform sampler2D shadowMapTransparent; | ||||
| uniform sampler2DShadow shadowMapSpot; | ||||
| #ifdef _ShadowMapAtlas | ||||
| uniform sampler2DShadow shadowMapPoint; | ||||
| @ -86,30 +87,28 @@ float lpToDepth(vec3 lp, const vec2 lightProj) { | ||||
|  | ||||
| void main() { | ||||
| 	int res = voxelgiResolution.x; | ||||
|  | ||||
| 	ivec3 dst = ivec3(gl_GlobalInvocationID.xyz); | ||||
| 	dst.y += clipmapLevel * res; | ||||
|  | ||||
| 	vec3 P = (gl_GlobalInvocationID.xyz + 0.5) / voxelgiResolution; | ||||
| 	P = P * 2.0 - 1.0; | ||||
| 	P *= clipmaps[int(clipmapLevel * 10)]; | ||||
| 	P *= voxelgiResolution; | ||||
| 	P += vec3(clipmaps[int(clipmapLevel * 10 + 4)], clipmaps[int(clipmapLevel * 10 + 5)], clipmaps[int(clipmapLevel * 10 + 6)]); | ||||
| 	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]); | ||||
|  | ||||
| 	vec3 visibility; | ||||
| 	vec3 lp = lightPos - P; | ||||
| 	float visibility; | ||||
| 	vec3 lp = lightPos -wposition; | ||||
| 	vec3 l; | ||||
| 	if (lightType == 0) { l = lightDir; visibility = vec3(1.0); } | ||||
| 	else { l = normalize(lp); visibility = vec3(attenuate(distance(P, lightPos))); } | ||||
| 	if (lightType == 0) { l = lightDir; visibility = 1.0; } | ||||
| 	else { l = normalize(lp); visibility = attenuate(distance(wposition, lightPos)); } | ||||
|  | ||||
| #ifdef _ShadowMap | ||||
| 	if (lightShadow == 1) { | ||||
| 		vec4 lightPosition = LVP * vec4(P, 1.0); | ||||
| 		vec4 lightPosition = LVP * vec4(wposition, 1.0); | ||||
| 		vec3 lPos = lightPosition.xyz / lightPosition.w; | ||||
| 		visibility = texture(shadowMap, vec3(lPos.xy, lPos.z - shadowsBias)).rrr; | ||||
| 		visibility = texture(shadowMap, vec3(lPos.xy, lPos.z - shadowsBias)).r; | ||||
| 	} | ||||
| 	else if (lightShadow == 2) { | ||||
| 		vec4 lightPosition = LVP * vec4(P, 1.0); | ||||
| 		vec4 lightPosition = LVP * vec4(wposition, 1.0); | ||||
| 		vec3 lPos = lightPosition.xyz / lightPosition.w; | ||||
| 		visibility *= texture(shadowMapSpot, vec3(lPos.xy, lPos.z - shadowsBias)).r; | ||||
| 	} | ||||
| @ -130,9 +129,7 @@ void main() { | ||||
| 	} | ||||
| #endif | ||||
|  | ||||
| 	vec3 light = visibility * lightColor; | ||||
|  | ||||
| 	imageAtomicAdd(voxelsLight, dst + ivec3(0, 0, 0), uint(light.r * 255)); | ||||
| 	imageAtomicAdd(voxelsLight, dst + ivec3(0, 0, voxelgiResolution.x), uint(light.g * 255)); | ||||
| 	imageAtomicAdd(voxelsLight, dst + ivec3(0, 0, voxelgiResolution.x * 2), uint(light.b * 255)); | ||||
| 	imageAtomicAdd(voxelsLight, dst, uint(visibility * lightColor.r * 255)); | ||||
| 	imageAtomicAdd(voxelsLight, dst + ivec3(0, 0, voxelgiResolution.x), uint(visibility * lightColor.g * 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/gbuffer.glsl" | ||||
| #include "std/imageatomic.glsl" | ||||
| #include "std/voxels_constants.glsl" | ||||
| #include "std/constants.glsl" | ||||
|  | ||||
| #ifdef _VoxelGI | ||||
| uniform layout(rgba8) image3D voxelsB; | ||||
| uniform layout(rgba8) image3D voxelsOut; | ||||
| #else | ||||
| uniform layout(r16) image3D voxelsB; | ||||
| uniform layout(r16) image3D voxelsOut; | ||||
| uniform layout(r8) image3D voxelsB; | ||||
| uniform layout(r8) image3D voxelsOut; | ||||
| #endif | ||||
|  | ||||
| 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/imageatomic.glsl" | ||||
| #include "std/conetrace.glsl" | ||||
| #include "std/brdf.glsl" | ||||
| #include "std/shirr.glsl" | ||||
|  | ||||
| uniform sampler3D voxels; | ||||
| uniform sampler2D gbufferD; | ||||
| uniform sampler2D gbuffer0; | ||||
| uniform layout(r8) image2D voxels_ao; | ||||
| uniform layout(rgba8) image2D voxels_ao; | ||||
|  | ||||
| uniform float clipmaps[voxelgiClipmapCount * 10]; | ||||
| uniform mat4 InvVP; | ||||
| uniform vec2 cameraProj; | ||||
| uniform vec3 eye; | ||||
| uniform vec3 eyeLook; | ||||
| 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() { | ||||
| 	const vec2 pixel = gl_GlobalInvocationID.xy; | ||||
| 	vec2 uv = (pixel + 0.5) / postprocess_resolution; | ||||
| @ -54,12 +73,11 @@ void main() { | ||||
|  | ||||
| 	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; | ||||
| 	vec4 clipPos = vec4(x, y, depth, 1.0); | ||||
|     vec4 worldPos = InvVP * clipPos; | ||||
|     vec3 P = worldPos.xyz / worldPos.w; | ||||
|  | ||||
| 	vec3 P = getPos(eye, eyeLook, normalize(viewRay), depth, cameraProj); | ||||
| 	vec3 v = normalize(eye - P); | ||||
|  | ||||
| 	vec4 g0 = textureLod(gbuffer0, uv, 0.0); | ||||
| 	vec3 n; | ||||
| @ -67,7 +85,89 @@ void main() { | ||||
| 	n.xy = n.z >= 0.0 ? g0.xy : octahedronWrap(g0.xy); | ||||
| 	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,6 +29,8 @@ layout (local_size_x = 8, local_size_y = 8, local_size_z = 1) in; | ||||
| #include "std/gbuffer.glsl" | ||||
| #include "std/imageatomic.glsl" | ||||
| #include "std/conetrace.glsl" | ||||
| #include "std/brdf.glsl" | ||||
| #include "std/shirr.glsl" | ||||
|  | ||||
| uniform sampler3D voxels; | ||||
| uniform sampler2D gbufferD; | ||||
| @ -37,29 +39,44 @@ uniform layout(rgba8) image2D voxels_diffuse; | ||||
|  | ||||
| uniform float clipmaps[voxelgiClipmapCount * 10]; | ||||
| uniform mat4 InvVP; | ||||
| uniform vec2 cameraProj; | ||||
| uniform vec3 eye; | ||||
| uniform vec3 eyeLook; | ||||
| 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() { | ||||
| 	const vec2 pixel = gl_GlobalInvocationID.xy; | ||||
| 	vec2 uv = (pixel + 0.5) / postprocess_resolution; | ||||
| 	#ifdef _InvY | ||||
| 	uv.y = 1.0 - uv.y | ||||
| 	uv.y = 1.0 - uv.y; | ||||
| 	#endif | ||||
|  | ||||
| 	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 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 clipPos = vec4(x, y, depth, 1.0); | ||||
|     vec4 worldPos = InvVP * clipPos; | ||||
|     vec3 P = worldPos.xyz / worldPos.w; | ||||
| 	vec3 v = normalize(eye - P); | ||||
|  | ||||
| 	vec4 g0 = textureLod(gbuffer0, uv, 0.0); | ||||
| 	vec3 n; | ||||
| @ -67,7 +84,94 @@ void main() { | ||||
| 	n.xy = n.z >= 0.0 ? g0.xy : octahedronWrap(g0.xy); | ||||
| 	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,6 +29,7 @@ layout (local_size_x = 8, local_size_y = 8, local_size_z = 1) in; | ||||
| #include "std/gbuffer.glsl" | ||||
| #include "std/imageatomic.glsl" | ||||
| #include "std/conetrace.glsl" | ||||
| #include "std/brdf.glsl" | ||||
|  | ||||
| uniform sampler2D gbufferD; | ||||
| uniform sampler2D gbuffer0; | ||||
| @ -38,9 +39,7 @@ uniform layout(rgba8) image2D voxels_specular; | ||||
|  | ||||
| uniform float clipmaps[voxelgiClipmapCount * 10]; | ||||
| uniform mat4 InvVP; | ||||
| uniform vec2 cameraProj; | ||||
| uniform vec3 eye; | ||||
| uniform vec3 eyeLook; | ||||
| uniform vec2 postprocess_resolution; | ||||
| uniform sampler2D sveloc; | ||||
|  | ||||
| @ -48,7 +47,7 @@ void main() { | ||||
| 	const vec2 pixel = gl_GlobalInvocationID.xy; | ||||
| 	vec2 uv = (pixel + 0.5) / postprocess_resolution; | ||||
| 	#ifdef _InvY | ||||
| 	uv.y = 1.0 - uv.y | ||||
| 	uv.y = 1.0 - uv.y; | ||||
| 	#endif | ||||
|  | ||||
| 	float depth = textureLod(gbufferD, uv, 0.0).r * 2.0 - 1.0; | ||||
| @ -56,12 +55,10 @@ void main() { | ||||
|  | ||||
| 	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; | ||||
| 	vec4 clipPos = vec4(x, y, depth, 1.0); | ||||
|     vec4 worldPos = InvVP * clipPos; | ||||
|     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); | ||||
|  | ||||
| 	vec3 n; | ||||
| @ -71,7 +68,7 @@ void main() { | ||||
|  | ||||
| 	vec2 velocity = -textureLod(sveloc, uv, 0.0).rg; | ||||
|  | ||||
| 	vec3 color = traceSpecular(P, n, voxels, voxelsSDF, normalize(eye - P), g0.z, clipmaps, pixel, velocity).rgb; | ||||
| 	vec3 color = traceSpecular(P, n, voxels, voxelsSDF, normalize(eye - P), g0.z * g0.z, clipmaps, pixel, velocity).rgb; | ||||
|  | ||||
| 	imageStore(voxels_specular, ivec2(pixel), vec4(color, 1.0)); | ||||
| } | ||||
|  | ||||
| @ -23,8 +23,8 @@ THE SOFTWARE. | ||||
|  | ||||
| #include "compiled.inc" | ||||
|  | ||||
| uniform layout(r16) image3D input_sdf; | ||||
| uniform layout(r16) image3D output_sdf; | ||||
| uniform layout(r8) image3D input_sdf; | ||||
| uniform layout(r8) image3D output_sdf; | ||||
|  | ||||
| uniform float jump_size; | ||||
| uniform int clipmapLevel; | ||||
|  | ||||
| @ -46,15 +46,15 @@ uniform layout(r32ui) uimage3D voxels; | ||||
| uniform layout(r32ui) uimage3D voxelsLight; | ||||
| uniform layout(rgba8) image3D voxelsB; | ||||
| uniform layout(rgba8) image3D voxelsOut; | ||||
| uniform layout(r16) image3D SDF; | ||||
| uniform layout(r8) image3D SDF; | ||||
| #else | ||||
| #ifdef _VoxelAOvar | ||||
| #ifdef _VoxelShadow | ||||
| uniform layout(r16) image3D SDF; | ||||
| uniform layout(r8) image3D SDF; | ||||
| #endif | ||||
| uniform layout(r32ui) uimage3D voxels; | ||||
| uniform layout(r16) image3D voxelsB; | ||||
| uniform layout(r16) image3D voxelsOut; | ||||
| uniform layout(r8) image3D voxelsB; | ||||
| uniform layout(r8) image3D voxelsOut; | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| @ -74,14 +74,9 @@ void main() { | ||||
| 	#endif | ||||
| 	#endif | ||||
|  | ||||
| 	ivec3 src = ivec3(gl_GlobalInvocationID.xyz); | ||||
| 	#ifdef _VoxelGI | ||||
| 	vec3 light = vec3(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; | ||||
| 	light /= 3; | ||||
| 	#endif | ||||
| 	int nor_count = 0; | ||||
| 	vec3 avgNormal = vec3(0.0); | ||||
| 	mat3 TBN = mat3(0.0); | ||||
|  | ||||
| 	for (int i = 0; i < 6 + DIFFUSE_CONE_COUNT; i++) | ||||
| 	{ | ||||
| @ -91,7 +86,7 @@ void main() { | ||||
| 		float aniso_colors[6]; | ||||
| 		#endif | ||||
|  | ||||
| 		src = ivec3(gl_GlobalInvocationID.xyz); | ||||
| 		ivec3 src = ivec3(gl_GlobalInvocationID.xyz); | ||||
| 		src.x += i * res; | ||||
| 		ivec3 dst = src; | ||||
| 		dst.y += clipmapLevel * res; | ||||
| @ -104,44 +99,67 @@ void main() { | ||||
|  | ||||
| 		if (i < 6) { | ||||
| 			#ifdef _VoxelGI | ||||
| 			vec4 basecol = vec4(0.0); | ||||
| 			basecol.r = float(imageLoad(voxels, src)) / 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.a = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 3))) / 255; | ||||
| 			basecol /= 4; | ||||
| 			vec3 emission = vec3(0.0); | ||||
| 			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.b = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 6))) / 255; | ||||
| 			emission /= 3; | ||||
| 			vec3 N = vec3(0.0); | ||||
| 			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 /= 2; | ||||
| 			vec3 wnormal = decode_oct(N.rg * 2 - 1); | ||||
| 			vec3 envl = vec3(0.0); | ||||
| 			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.b = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 11))) / 255; | ||||
| 			envl /= 3; | ||||
| 			envl *= 100; | ||||
| 			int count = int(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 15))); | ||||
| 			if (count > 0) { | ||||
| 				vec4 basecol = vec4(0.0); | ||||
| 				basecol.r = float(imageLoad(voxels, src)) / 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.a = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 3))) / 255; | ||||
| 				basecol /= count; | ||||
| 				vec3 emission = vec3(0.0); | ||||
| 				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.b = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 6))) / 255; | ||||
| 				emission /= count; | ||||
| 				vec3 N = vec3(0.0); | ||||
| 				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 /= count; | ||||
| 				N = decode_oct(N.rg * 2.0 - 1.0); | ||||
|  | ||||
| 			//clipmap to world | ||||
| 			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]); | ||||
| 				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); | ||||
| 				} | ||||
|  | ||||
| 			radiance = basecol; | ||||
| 			vec4 trace = traceDiffuse(wposition, wnormal, voxelsSampler, clipmaps); | ||||
| 			vec3 indirect = trace.rgb + envl.rgb * (1.0 - trace.a); | ||||
| 			radiance.rgb *= light + indirect; | ||||
| 			radiance.rgb += emission.rgb; | ||||
| 				vec3 envl = vec3(0.0); | ||||
| 				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.b = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 11))) / 255; | ||||
| 				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 | ||||
| 				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]); | ||||
|  | ||||
| 				radiance = basecol; | ||||
| 				vec4 trace = traceDiffuse(wposition, N, voxelsSampler, clipmaps); | ||||
| 				vec3 indirect = trace.rgb + envl.rgb * (1.0 - trace.a); | ||||
| 				radiance.rgb *= light + indirect; | ||||
| 				radiance.rgb += emission.rgb; | ||||
| 			} | ||||
| 			#else | ||||
| 			opac = float(imageLoad(voxels, src)) / 255; | ||||
| 			int count = int(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x))); | ||||
| 			if (count > 0) { | ||||
| 				opac = float(imageLoad(voxels, src)) / 255; | ||||
| 				opac /= count; | ||||
| 			} | ||||
| 			#endif | ||||
|  | ||||
| 			#ifdef _VoxelGI | ||||
| @ -195,7 +213,7 @@ void main() { | ||||
| 		} | ||||
| 		else { | ||||
| 			// precompute cone sampling: | ||||
| 			vec3 coneDirection = DIFFUSE_CONE_DIRECTIONS[i - 6]; | ||||
| 			vec3 coneDirection = TBN * DIFFUSE_CONE_DIRECTIONS[i - 6]; | ||||
| 			vec3 aniso_direction = -coneDirection; | ||||
| 			uvec3 face_offsets = uvec3( | ||||
| 				aniso_direction.x > 0 ? 0 : 1, | ||||
| @ -236,4 +254,4 @@ void main() { | ||||
| 	imageStore(SDF, dst_sdf, vec4(sdf)); | ||||
| 	#endif | ||||
| 	#endif | ||||
| } | ||||
| } | ||||
| @ -75,16 +75,17 @@ vec4 binarySearch(vec3 dir) { | ||||
| } | ||||
|  | ||||
| vec4 rayCast(vec3 dir) { | ||||
| 	#ifdef _CPostprocess | ||||
| 		dir *= PPComp9.x; | ||||
| 	#else | ||||
| 		dir *= ssrRayStep; | ||||
| 	#endif | ||||
| 	for (int i = 0; i < maxSteps; i++) { | ||||
| 		hitCoord += dir; | ||||
| 		if (getDeltaDepth(hitCoord) > 0.0) return binarySearch(dir); | ||||
| 	} | ||||
| 	return vec4(0.0); | ||||
|     float ddepth; | ||||
|     dir *= ss_refractionRayStep; | ||||
|     for (int i = 0; i < maxSteps; i++) { | ||||
|         hitCoord += dir; | ||||
|         ddepth = getDeltaDepth(hitCoord); | ||||
|         if (ddepth > 0.0) | ||||
|             return binarySearch(dir); | ||||
|     } | ||||
|     // No hit — fallback to projecting the ray to UV space | ||||
|     vec2 fallbackUV = getProjectedCoord(hitCoord); | ||||
|     return vec4(fallbackUV, 0.0, 0.5); // We set .w lower to indicate fallback | ||||
| } | ||||
| #endif //SSR | ||||
|  | ||||
|  | ||||
| @ -12,6 +12,7 @@ class App { | ||||
| 	static var traitInits: Array<Void->Void> = []; | ||||
| 	static var traitUpdates: Array<Void->Void> = []; | ||||
| 	static var traitLateUpdates: Array<Void->Void> = []; | ||||
| 	static var traitFixedUpdates: Array<Void->Void> = []; | ||||
| 	static var traitRenders: Array<kha.graphics4.Graphics->Void> = []; | ||||
| 	static var traitRenders2D: Array<kha.graphics2.Graphics->Void> = []; | ||||
| 	public static var framebuffer: kha.Framebuffer; | ||||
| @ -23,6 +24,8 @@ class App { | ||||
| 	public static var renderPathTime: Float; | ||||
| 	public static var endFrameCallbacks: Array<Void->Void> = []; | ||||
| 	#end | ||||
| 	static var last = 0.0; | ||||
| 	static var time = 0.0; | ||||
| 	static var lastw = -1; | ||||
| 	static var lasth = -1; | ||||
| 	public static var onResize: Void->Void = null; | ||||
| @ -34,13 +37,14 @@ class App { | ||||
| 	function new(done: Void->Void) { | ||||
| 		done(); | ||||
| 		kha.System.notifyOnFrames(render); | ||||
| 		kha.Scheduler.addTimeTask(update, 0, iron.system.Time.delta); | ||||
| 		kha.Scheduler.addTimeTask(update, 0, iron.system.Time.step); | ||||
| 	} | ||||
|  | ||||
| 	public static function reset() { | ||||
| 		traitInits = []; | ||||
| 		traitUpdates = []; | ||||
| 		traitLateUpdates = []; | ||||
| 		traitFixedUpdates = []; | ||||
| 		traitRenders = []; | ||||
| 		traitRenders2D = []; | ||||
| 		if (onResets != null) for (f in onResets) f(); | ||||
| @ -48,6 +52,24 @@ class App { | ||||
|  | ||||
| 	static function update() { | ||||
| 		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 lnx_debug | ||||
| @ -56,6 +78,14 @@ class App { | ||||
|  | ||||
| 		Scene.active.updateFrame(); | ||||
|  | ||||
|  | ||||
| 		time += iron.system.Time.delta; | ||||
|  | ||||
| 		while (time >= iron.system.Time.fixedStep) { | ||||
| 			for (f in traitFixedUpdates) f(); | ||||
| 			time -= iron.system.Time.fixedStep; | ||||
| 		} | ||||
|  | ||||
| 		var i = 0; | ||||
| 		var l = traitUpdates.length; | ||||
| 		while (i < l) { | ||||
| @ -84,29 +114,13 @@ class App { | ||||
| 		for (cb in endFrameCallbacks) cb(); | ||||
| 		updateTime = kha.Scheduler.realTime() - startTime; | ||||
| 		#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>) { | ||||
| 		var frame = frames[0]; | ||||
| 		framebuffer = frame; | ||||
|  | ||||
| 		iron.system.Time.update(); | ||||
| 		iron.system.Time.render(); | ||||
|  | ||||
| 		if (Scene.active == null || !Scene.active.ready) { | ||||
| 			render2D(frame); | ||||
| @ -172,6 +186,14 @@ class App { | ||||
| 		traitLateUpdates.remove(f); | ||||
| 	} | ||||
|  | ||||
| 	public static function notifyOnFixedUpdate(f: Void->Void) { | ||||
| 		traitFixedUpdates.push(f); | ||||
| 	} | ||||
|  | ||||
| 	public static function removeFixedUpdate(f: Void->Void) { | ||||
| 		traitFixedUpdates.remove(f); | ||||
| 	} | ||||
|  | ||||
| 	public static function notifyOnRender(f: kha.graphics4.Graphics->Void) { | ||||
| 		traitRenders.push(f); | ||||
| 	} | ||||
|  | ||||
| @ -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 { | ||||
| 			#if rp_depth_texture | ||||
| 			var depthDiff = boolToInt(a.depthRead) - boolToInt(b.depthRead); | ||||
| 			if (depthDiff != 0) return depthDiff; | ||||
| 			#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) { | ||||
| @ -399,7 +402,7 @@ class RenderPath { | ||||
| 			#if lnx_batch | ||||
| 			sortMeshesDistance(Scene.active.meshBatch.nonBatched); | ||||
| 			#else | ||||
| 			drawOrder == DrawOrder.Shader ? sortMeshesShader(meshes) : sortMeshesDistance(meshes); | ||||
| 			drawOrder == DrawOrder.Index ? sortMeshesIndex(meshes) : sortMeshesDistance(meshes); | ||||
| 			#end | ||||
| 			meshesSorted = true; | ||||
| 		} | ||||
| @ -518,12 +521,44 @@ class RenderPath { | ||||
| 		return Reflect.field(kha.Shaders, handle + "_comp"); | ||||
| 	} | ||||
|  | ||||
| 	#if (kha_krom && lnx_vr) | ||||
| 	public function drawStereo(drawMeshes: Int->Void) { | ||||
| 		for (eye in 0...2) { | ||||
| 			Krom.vrBeginRender(eye); | ||||
| 			drawMeshes(eye); | ||||
| 			Krom.vrEndRender(eye); | ||||
| 	#if lnx_vr | ||||
| 	public function drawStereo(drawMeshes: Void->Void) { | ||||
| 		var vr = kha.vr.VrInterface.instance; | ||||
| 		var appw = iron.App.w(); | ||||
| 		var apph = iron.App.h(); | ||||
| 		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 | ||||
| @ -882,6 +917,6 @@ class CachedShaderContext { | ||||
|  | ||||
| @:enum abstract DrawOrder(Int) from Int { | ||||
| 	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 | ||||
| } | ||||
|  | ||||
| @ -775,6 +775,7 @@ class Scene { | ||||
| 			// Attach particle systems | ||||
| 			#if lnx_particles | ||||
| 			if (o.particle_refs != null) { | ||||
| 				cast(object, MeshObject).render_emitter = o.render_emitter; | ||||
| 				for (ref in o.particle_refs) cast(object, MeshObject).setupParticleSystem(sceneName, ref); | ||||
| 			} | ||||
| 			#end | ||||
| @ -782,6 +783,11 @@ class Scene { | ||||
| 			if (o.tilesheet_ref != null) { | ||||
| 				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); | ||||
| 		}); | ||||
| 	} | ||||
| @ -881,8 +887,12 @@ class Scene { | ||||
| 						var ptype: String = t.props[i * 3 + 1]; | ||||
| 						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)); | ||||
| 						} else if (ptype == "TSceneFormat" && pval != "") { | ||||
| 							Data.getSceneRaw(pval, function (r: TSceneFormat) { | ||||
| 								Reflect.setProperty(traitInst, pname, r); | ||||
| 							}); | ||||
| 						} | ||||
| 						else { | ||||
| 							switch (ptype) { | ||||
|  | ||||
| @ -16,6 +16,7 @@ class Trait { | ||||
| 	var _remove: Array<Void->Void> = null; | ||||
| 	var _update: Array<Void->Void> = null; | ||||
| 	var _lateUpdate: Array<Void->Void> = null; | ||||
| 	var _fixedUpdate: Array<Void->Void> = null; | ||||
| 	var _render: Array<kha.graphics4.Graphics->Void> = null; | ||||
| 	var _render2D: Array<kha.graphics2.Graphics->Void> = null; | ||||
|  | ||||
| @ -87,6 +88,23 @@ class Trait { | ||||
| 		App.removeLateUpdate(f); | ||||
| 	} | ||||
|  | ||||
|     /** | ||||
|       Add fixed game logic handler. | ||||
|     **/ | ||||
| 	public function notifyOnFixedUpdate(f: Void->Void) { | ||||
| 		if (_fixedUpdate == null) _fixedUpdate = []; | ||||
| 		_fixedUpdate.push(f); | ||||
| 		App.notifyOnFixedUpdate(f); | ||||
| 	} | ||||
|  | ||||
|     /** | ||||
|       Remove fixed game logic handler. | ||||
|     **/ | ||||
| 	public function removeFixedUpdate(f: Void->Void) { | ||||
| 		_fixedUpdate.remove(f); | ||||
| 		App.removeFixedUpdate(f); | ||||
| 	} | ||||
|  | ||||
|     /** | ||||
|       Add render handler. | ||||
|     **/ | ||||
|  | ||||
| @ -9,6 +9,7 @@ import iron.data.SceneFormat; | ||||
| class MeshData { | ||||
|  | ||||
| 	public var name: String; | ||||
| 	public var sortingIndex: Int; | ||||
| 	public var raw: TMeshData; | ||||
| 	public var format: TSceneFormat; | ||||
| 	public var geom: Geometry; | ||||
| @ -23,7 +24,8 @@ class MeshData { | ||||
| 	public function new(raw: TMeshData, done: MeshData->Void) { | ||||
| 		this.raw = raw; | ||||
| 		this.name = raw.name; | ||||
|  | ||||
| 		this.sortingIndex = raw.sorting_index; | ||||
| 		 | ||||
| 		if (raw.scale_pos != null) scalePos = raw.scale_pos; | ||||
| 		if (raw.scale_tex != null) scaleTex = raw.scale_tex; | ||||
|  | ||||
|  | ||||
| @ -49,6 +49,7 @@ typedef TMeshData = { | ||||
| @:structInit class TMeshData { | ||||
| #end | ||||
| 	public var name: String; | ||||
| 	public var sorting_index: Int; | ||||
| 	public var vertex_arrays: Array<TVertexArray>; | ||||
| 	public var index_arrays: Array<TIndexArray>; | ||||
| 	@:optional public var dynamic_usage: Null<Bool>; | ||||
| @ -222,6 +223,7 @@ typedef TShaderData = { | ||||
| @:structInit class TShaderData { | ||||
| #end | ||||
| 	public var name: String; | ||||
| 	public var next_pass: String; | ||||
| 	public var contexts: Array<TShaderContext>; | ||||
| } | ||||
|  | ||||
| @ -392,6 +394,9 @@ typedef TParticleData = { | ||||
| #end | ||||
| 	public var name: String; | ||||
| 	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 count: Int; | ||||
| 	public var frame_start: FastFloat; | ||||
| @ -439,6 +444,7 @@ typedef TObj = { | ||||
| 	@:optional public var traits: Array<TTrait>; | ||||
| 	@:optional public var properties: Array<TProperty>; | ||||
| 	@:optional public var vertex_groups: Array<TVertex_groups>; | ||||
| 	@:optional public var camera_list: Array<String>; | ||||
| 	@:optional public var constraints: Array<TConstraint>; | ||||
| 	@:optional public var dimensions: Float32Array; // Geometry objects | ||||
| 	@:optional public var object_actions: Array<String>; | ||||
|  | ||||
| @ -22,6 +22,7 @@ using StringTools; | ||||
| class ShaderData { | ||||
|  | ||||
| 	public var name: String; | ||||
| 	public var nextPass: String; | ||||
| 	public var raw: TShaderData; | ||||
| 	public var contexts: Array<ShaderContext> = []; | ||||
|  | ||||
| @ -33,6 +34,7 @@ class ShaderData { | ||||
| 	public function new(raw: TShaderData, done: ShaderData->Void, overrideContext: TShaderOverride = null) { | ||||
| 		this.raw = raw; | ||||
| 		this.name = raw.name; | ||||
| 		this.nextPass = raw.next_pass; | ||||
|  | ||||
| 		for (c in raw.contexts) contexts.push(null); | ||||
| 		var contextsLoaded = 0; | ||||
|  | ||||
							
								
								
									
										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
									
								
							
							
						
						| @ -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
									
								
							
							
						
						| @ -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
									
								
							
							
						
						| @ -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); | ||||
|   } | ||||
| } | ||||
| @ -66,12 +66,32 @@ class Quat { | ||||
| 	} | ||||
|  | ||||
| 	public inline function fromAxisAngle(axis: Vec4, angle: FastFloat): Quat { | ||||
| 		var s: FastFloat = Math.sin(angle * 0.5); | ||||
| 		x = axis.x * s; | ||||
| 		y = axis.y * s; | ||||
| 		z = axis.z * s; | ||||
| 		w = Math.cos(angle * 0.5); | ||||
| 		return normalize(); | ||||
| 		//var s: FastFloat = Math.sin(angle * 0.5); | ||||
| 		//x = axis.x * s; | ||||
| 		//y = axis.y * s; | ||||
| 		//z = axis.z * s; | ||||
| 		//w = Math.cos(angle * 0.5); | ||||
| 		//return normalize(); | ||||
| 		// Normalize the axis vector first | ||||
| 		var axisLen = Math.sqrt(axis.x * axis.x + axis.y * axis.y + axis.z * axis.z); | ||||
| 		if (axisLen > 0.00001) { | ||||
| 			var aL = 1.0 / axisLen; | ||||
| 			var nX = axis.x * aL; | ||||
| 			var nY = axis.y * aL; | ||||
| 			var nZ = axis.z * aL; | ||||
| 			var halfAngle = angle * 0.5; | ||||
| 			var s: FastFloat = Math.sin(halfAngle); | ||||
| 			x = nX * s; | ||||
| 			y = nY * s; | ||||
| 			z = nZ * s; | ||||
| 			w = Math.cos(halfAngle); | ||||
| 		} else { | ||||
| 			x = 0.0; | ||||
| 			y = 0.0; | ||||
| 			z = 0.0; | ||||
| 			w = 1.0; | ||||
| 		} | ||||
| 		return this; | ||||
| 	} | ||||
|  | ||||
| 	public inline function toAxisAngle(axis: Vec4): FastFloat { | ||||
| @ -379,17 +399,33 @@ class Quat { | ||||
| 		@return	This quaternion. | ||||
| 	**/ | ||||
| 	public inline function fromEulerOrdered(e: Vec4, order: String): Quat { | ||||
| 		var c1 = Math.cos(e.x / 2); | ||||
| 		var c2 = Math.cos(e.y / 2); | ||||
| 		var c3 = Math.cos(e.z / 2); | ||||
| 		var s1 = Math.sin(e.x / 2); | ||||
| 		var s2 = Math.sin(e.y / 2); | ||||
| 		var s3 = Math.sin(e.z / 2); | ||||
|  | ||||
| 		 | ||||
| 		var mappedAngles = new Vec4(); | ||||
| 		switch (order) { | ||||
| 			case "XYZ": | ||||
| 				mappedAngles.set(e.x, e.y, e.z); | ||||
| 			case "XZY": | ||||
| 				mappedAngles.set(e.x, e.z, e.y); | ||||
| 			case "YXZ":  | ||||
| 				mappedAngles.set(e.y, e.x, e.z); | ||||
| 			case "YZX":  | ||||
| 				mappedAngles.set(e.y, e.z, e.x); | ||||
| 			case "ZXY":  | ||||
| 				mappedAngles.set(e.z, e.x, e.y); | ||||
| 			case "ZYX":  | ||||
| 				mappedAngles.set(e.z, e.y, e.x); | ||||
| 		} | ||||
| 		var c1 = Math.cos(mappedAngles.x / 2); | ||||
| 		var c2 = Math.cos(mappedAngles.y / 2); | ||||
| 		var c3 = Math.cos(mappedAngles.z / 2); | ||||
| 		var s1 = Math.sin(mappedAngles.x / 2); | ||||
| 		var s2 = Math.sin(mappedAngles.y / 2); | ||||
| 		var s3 = Math.sin(mappedAngles.z / 2); | ||||
| 		var qx = new Quat(s1, 0, 0, c1); | ||||
| 		var qy = new Quat(0, s2, 0, c2); | ||||
| 		var qz = new Quat(0, 0, s3, c3); | ||||
|  | ||||
| 		// Original multiplication sequence (implements reverse of 'order') | ||||
| 		if (order.charAt(2) == 'X') | ||||
| 			this.setFrom(qx); | ||||
| 		else if (order.charAt(2) == 'Y') | ||||
| @ -409,6 +445,12 @@ class Quat { | ||||
| 		else | ||||
| 			this.mult(qz); | ||||
|  | ||||
| 		// TO DO quick fix somethings wrong.. | ||||
| 		this.x = -this.x; | ||||
| 		this.y = -this.y; | ||||
| 		this.z = -this.z; | ||||
| 		this.w = -this.w; | ||||
| 		 | ||||
| 		return this; | ||||
| 	} | ||||
|  | ||||
|  | ||||
| @ -159,9 +159,17 @@ class Animation { | ||||
| 			if(markerEvents.get(sampler) != null){ | ||||
| 				for (i in 0...anim.marker_frames.length) { | ||||
| 					if (frameIndex == anim.marker_frames[i]) { | ||||
| 						var marketAct = markerEvents.get(sampler); | ||||
| 						var ar = marketAct.get(anim.marker_names[i]); | ||||
| 						var markerAct = markerEvents.get(sampler); | ||||
| 						var ar = markerAct.get(anim.marker_names[i]); | ||||
| 						if (ar != null) for (f in ar) f(); | ||||
| 					} else { | ||||
| 						for (j in 0...(frameIndex - lastFrameIndex)) { | ||||
| 							if (lastFrameIndex + j + 1 == anim.marker_frames[i]) { | ||||
| 								var markerAct = markerEvents.get(sampler); | ||||
| 								var ar = markerAct.get(anim.marker_names[i]); | ||||
| 								if (ar != null) for (f in ar) f(); | ||||
| 							} | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 				lastFrameIndex = frameIndex; | ||||
| @ -411,12 +419,23 @@ class ActionSampler { | ||||
| 	 */ | ||||
| 	public inline function setBoneAction(actionData: Array<TObj>) { | ||||
| 		this.actionData = actionData; | ||||
| 		this.totalFrames = actionData[0].anim.tracks[0].frames.length; | ||||
| 		if(actionData[0].anim.root_motion_pos) this.rootMotionPos = true; | ||||
| 		if(actionData[0].anim.root_motion_rot) this.rootMotionRot = true; | ||||
| 		if (actionData != null && actionData.length > 0 && actionData[0] != null && actionData[0].anim != null) { | ||||
| 			if (actionData[0].anim.tracks != null && actionData[0].anim.tracks.length > 0) { | ||||
| 				this.totalFrames = actionData[0].anim.tracks[0].frames.length; | ||||
| 			} | ||||
| 			else { | ||||
| 				this.totalFrames = 0; | ||||
| 			} | ||||
| 			if(actionData[0].anim.root_motion_pos) this.rootMotionPos = true; | ||||
| 			if(actionData[0].anim.root_motion_rot) this.rootMotionRot = true; | ||||
| 		} | ||||
| 		else { | ||||
| 			this.totalFrames = 0; | ||||
| 		} | ||||
| 		actionDataInit = true; | ||||
| 	} | ||||
|  | ||||
|  | ||||
| 	/** | ||||
| 	 * Cache raw object data for object animation. | ||||
| 	 * @param actionData Raw object data. | ||||
|  | ||||
| @ -30,12 +30,22 @@ class CameraObject extends Object { | ||||
| 	static var sphereCenter = new Vec4(); | ||||
| 	static var vcenter = 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) { | ||||
| 		super(); | ||||
|  | ||||
| 		this.data = data; | ||||
|  | ||||
| 		#if lnx_vr | ||||
| 		iron.system.VR.initButton(); | ||||
| 		#end | ||||
| 		 | ||||
| 		buildProjection(); | ||||
|  | ||||
| 		V = Mat4.identity(); | ||||
| @ -117,6 +127,26 @@ class CameraObject extends Object { | ||||
| 		V.getInverse(transform.world); | ||||
| 		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) { | ||||
| 			buildViewFrustum(VP, frustumPlanes); | ||||
| 		} | ||||
|  | ||||
| @ -155,8 +155,13 @@ class LightObject extends Object { | ||||
| 	} | ||||
|  | ||||
| 	public function setCascade(camera: CameraObject, cascade: Int) { | ||||
| 		m.setFrom(camera.V); | ||||
|  | ||||
| 		#if lnx_vr | ||||
| 		m.setFrom(camera.leftV); | ||||
| 		#else | ||||
| 		m.setFrom(camera.V); | ||||
| 		#end | ||||
| 		 | ||||
| 		#if lnx_csm | ||||
| 		if (camSlicedP == null) { | ||||
| 			camSlicedP = []; | ||||
|  | ||||
| @ -21,8 +21,10 @@ class MeshObject extends Object { | ||||
| 	public var particleChildren: Array<MeshObject> = null; | ||||
| 	public var particleOwner: MeshObject = null; // Particle object | ||||
| 	public var particleIndex = -1; | ||||
| 	public var render_emitter = true; | ||||
| 	#end | ||||
| 	public var cameraDistance: Float; | ||||
| 	public var cameraList: Array<String> = null; | ||||
| 	public var screenSize = 0.0; | ||||
| 	public var frustumCulling = true; | ||||
| 	public var activeTilesheet: Tilesheet = null; | ||||
| @ -234,6 +236,8 @@ class MeshObject extends Object { | ||||
| 		if (cullMesh(context, Scene.active.camera, RenderPath.active.light)) return; | ||||
| 		var meshContext = raw != null ? context == "mesh" : false; | ||||
|  | ||||
| 		if (cameraList != null && cameraList.indexOf(Scene.active.camera.name) < 0) return; | ||||
|  | ||||
| 		#if lnx_particles | ||||
| 		if (raw != null && raw.is_particle && particleOwner == null) return; // Instancing not yet set-up by particle system owner | ||||
| 		if (particleSystems != null && meshContext) { | ||||
| @ -244,6 +248,7 @@ class MeshObject extends Object { | ||||
| 					Scene.active.spawnObject(psys.data.raw.instance_object, null, function(o: Object) { | ||||
| 						if (o != null) { | ||||
| 							var c: MeshObject = cast o; | ||||
|     						c.cameraList = this.cameraList; | ||||
| 							particleChildren.push(c); | ||||
| 							c.particleOwner = this; | ||||
| 							c.particleIndex = particleChildren.length - 1; | ||||
| @ -255,11 +260,11 @@ class MeshObject extends Object { | ||||
| 				particleSystems[i].update(particleChildren[i], this); | ||||
| 			} | ||||
| 		} | ||||
| 		if (particleSystems != null && particleSystems.length > 0 && !raw.render_emitter) return; | ||||
| 		if (particleSystems != null && particleSystems.length > 0 && !render_emitter) return; | ||||
|         if (particleSystems == null && cullMaterial(context)) return; | ||||
|         #else | ||||
|         if (cullMaterial(context)) return; | ||||
| 		#end | ||||
|  | ||||
| 		if (cullMaterial(context)) return; | ||||
|  | ||||
| 		// Get lod | ||||
| 		var mats = materials; | ||||
| 		var lod = this; | ||||
| @ -297,6 +302,10 @@ class MeshObject extends Object { | ||||
|  | ||||
| 		// Render mesh | ||||
| 		var ldata = lod.data; | ||||
| 		 | ||||
| 		// Next pass rendering first (inverse order) | ||||
| 		renderNextPass(g, context, bindParams, lod); | ||||
| 		 | ||||
| 		for (i in 0...ldata.geom.indexBuffers.length) { | ||||
|  | ||||
| 			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); | ||||
| 			t._init = null; | ||||
| 		} | ||||
| 		if (t._fixedUpdate != null) { | ||||
| 			for (f in t._fixedUpdate) App.removeFixedUpdate(f); | ||||
| 			t._fixedUpdate = null; | ||||
| 		} | ||||
| 		if (t._update != null) { | ||||
| 			for (f in t._update) App.removeUpdate(f); | ||||
| 			t._update = null; | ||||
|  | ||||
| @ -24,6 +24,9 @@ class ObjectAnimation extends Animation { | ||||
|  | ||||
| 	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", | ||||
| 											   		"xrot", "yrot", "zrot", | ||||
| 											   		"qwrot", "qxrot", "qyrot", "qzrot", | ||||
| @ -39,7 +42,6 @@ class ObjectAnimation extends Animation { | ||||
| 		isSkinned = false; | ||||
| 		super(); | ||||
| 	} | ||||
|  | ||||
| 	function getAction(action: String): TObj { | ||||
| 		for (a in oactions) if (a != null && a.objects[0].name == action) return a.objects[0]; | ||||
| 		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) { | ||||
| 		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); | ||||
| 		if (oaction != null) { | ||||
| 			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(); | ||||
| 		#end | ||||
|  | ||||
| 		if(transformMap == null) transformMap = new Map(); | ||||
| 		if (transformMap == null) transformMap = new Map(); | ||||
| 		transformMap = initTransformMap(); | ||||
|  | ||||
| 		super.update(delta); | ||||
| 		if (defaultSampler != null) defaultSampler.paused = paused; | ||||
| 		if (paused) return; | ||||
| 		if(updateAnimation == null) return; | ||||
| 		if (updateAnimation == null) return; | ||||
| 		if (!isSkinned) updateObjectAnimation(); | ||||
|  | ||||
| 		#if lnx_debug | ||||
|  | ||||
| @ -2,11 +2,14 @@ package iron.object; | ||||
|  | ||||
| #if lnx_particles | ||||
|  | ||||
| import kha.FastFloat; | ||||
| import kha.graphics4.Usage; | ||||
| import kha.arrays.Float32Array; | ||||
| import iron.data.Data; | ||||
| import iron.data.ParticleData; | ||||
| import iron.data.SceneFormat; | ||||
| import iron.data.Geometry; | ||||
| import iron.data.MeshData; | ||||
| import iron.system.Time; | ||||
| import iron.math.Mat4; | ||||
| import iron.math.Quat; | ||||
| @ -16,10 +19,13 @@ import iron.math.Vec4; | ||||
| class ParticleSystem { | ||||
| 	public var data: ParticleData; | ||||
| 	public var speed = 1.0; | ||||
| 	public var dynamicEmitter: Bool = true; | ||||
| 	var currentSpeed = 0.0; | ||||
| 	var particles: Array<Particle>; | ||||
| 	var ready: Bool; | ||||
| 	var frameRate = 24; | ||||
| 	var lifetime = 0.0; | ||||
| 	var looptime = 0.0; | ||||
| 	var animtime = 0.0; | ||||
| 	var time = 0.0; | ||||
| 	var spawnRate = 0.0; | ||||
| @ -46,14 +52,31 @@ class ParticleSystem { | ||||
| 	var ownerLoc = new Vec4(); | ||||
| 	var ownerRot = new Quat(); | ||||
| 	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) { | ||||
| 		seed = pref.seed; | ||||
| 		currentSpeed = speed; | ||||
| 		speed = 0; | ||||
| 		particles = []; | ||||
| 		ready = false; | ||||
| 		 | ||||
| 		Data.getParticle(sceneName, pref.particle, function(b: ParticleData) { | ||||
| 			data = b; | ||||
| 			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) { | ||||
| 				gx = Scene.active.raw.gravity[0] * r.weight_gravity; | ||||
| 				gy = Scene.active.raw.gravity[1] * r.weight_gravity; | ||||
| @ -64,32 +87,73 @@ class ParticleSystem { | ||||
| 				gy = 0; | ||||
| 				gz = -9.81 * r.weight_gravity; | ||||
| 			} | ||||
| 			alignx = r.object_align_factor[0] / 2; | ||||
| 			aligny = r.object_align_factor[1] / 2; | ||||
| 			alignz = r.object_align_factor[2] / 2; | ||||
| 			alignx = r.object_align_factor[0]; | ||||
| 			aligny = r.object_align_factor[1]; | ||||
| 			alignz = r.object_align_factor[2]; | ||||
| 			looptime = (r.frame_end - r.frame_start) / frameRate; | ||||
| 			lifetime = r.lifetime / frameRate; | ||||
| 			animtime = (r.frame_end - r.frame_start) / frameRate; | ||||
| 			animtime = r.loop ? looptime : looptime + lifetime; | ||||
| 			spawnRate = ((r.frame_end - r.frame_start) / r.count) / frameRate; | ||||
| 			for (i in 0...r.count) particles.push(new Particle(i)); | ||||
|  | ||||
| 			for (i in 0...r.count) { | ||||
| 				particles.push(new Particle(i)); | ||||
| 			} | ||||
|  | ||||
| 			ready = true; | ||||
| 			if (r.auto_start){ | ||||
| 				start(); | ||||
| 			} | ||||
| 		}); | ||||
| 	} | ||||
|  | ||||
| 	public function start() { | ||||
| 		if (r.is_unique) random = Math.random(); | ||||
| 		lifetime = r.lifetime / frameRate; | ||||
| 		time = 0; | ||||
| 		lap = 0; | ||||
| 		lapTime = 0; | ||||
| 		speed = currentSpeed; | ||||
| 		lastSpawnedCount = 0; | ||||
| 		instancedData = null; | ||||
| 	} | ||||
|  | ||||
| 	public function pause() { | ||||
| 		lifetime = 0; | ||||
| 		speed = 0; | ||||
| 	} | ||||
|  | ||||
| 	public function resume() { | ||||
| 		lifetime = r.lifetime / frameRate; | ||||
| 		speed = currentSpeed; | ||||
| 	} | ||||
|  | ||||
|  | ||||
|  | ||||
| 	// TODO: interrupt smoothly | ||||
| 	public function stop() { | ||||
| 		end(); | ||||
| 	} | ||||
|  | ||||
| 	function end() { | ||||
| 		lifetime = 0; | ||||
| 		speed = 0; | ||||
| 		lap = 0; | ||||
| 	} | ||||
| 	 | ||||
| 	public function update(object: MeshObject, owner: MeshObject) { | ||||
| 		if (!ready || object == null || speed == 0.0) return; | ||||
| 		if (iron.App.pauseUpdates) return; | ||||
| 		 | ||||
| 		var prevLap = lap; | ||||
|  | ||||
| 		// Copy owner world transform but discard scale | ||||
| 		owner.transform.world.decompose(ownerLoc, ownerRot, ownerScl); | ||||
| 		object.transform.loc = ownerLoc; | ||||
| 		object.transform.rot = ownerRot; | ||||
| 		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.rot = ownerRot; | ||||
| 		} | ||||
|  | ||||
| 		// Set particle size per particle system | ||||
| 		object.transform.scale = new Vec4(r.particle_size, r.particle_size, r.particle_size, 1); | ||||
| @ -108,16 +172,25 @@ class ParticleSystem { | ||||
| 		} | ||||
|  | ||||
| 		// Animate | ||||
| 		time += Time.realDelta * speed; | ||||
| 		time += Time.renderDelta * speed; // realDelta to renderDelta | ||||
| 		lap = Std.int(time / animtime); | ||||
| 		lapTime = time - lap * animtime; | ||||
| 		count = Std.int(lapTime / spawnRate); | ||||
|  | ||||
| 		if (lap > prevLap && !r.loop) { | ||||
| 			end(); | ||||
| 		} | ||||
|  | ||||
| 		if (lap > prevLap && r.loop) { | ||||
| 			lastSpawnedCount = 0; | ||||
| 		} | ||||
| 		 | ||||
| 		updateGpu(object, owner); | ||||
| 	} | ||||
|  | ||||
| 	public function getData(): Mat4 { | ||||
| 		var hair = r.type == 1; | ||||
| 		// Store loop flag in the sign: positive -> loop, negative -> no loop | ||||
| 		m._00 = r.loop ? animtime : -animtime; | ||||
| 		m._01 = hair ? 1 / particles.length : spawnRate; | ||||
| 		m._02 = hair ? 1 : lifetime; | ||||
| @ -126,9 +199,9 @@ class ParticleSystem { | ||||
| 		m._11 = hair ? 0 : aligny; | ||||
| 		m._12 = hair ? 0 : alignz; | ||||
| 		m._13 = hair ? 0 : r.factor_random; | ||||
| 		m._20 = hair ? 0 : gx * r.mass; | ||||
| 		m._21 = hair ? 0 : gy * r.mass; | ||||
| 		m._22 = hair ? 0 : gz * r.mass; | ||||
| 		m._20 = hair ? 0 : gx; | ||||
| 		m._21 = hair ? 0 : gy; | ||||
| 		m._22 = hair ? 0 : gz; | ||||
| 		m._23 = hair ? 0 : r.lifetime_random; | ||||
| 		m._30 = tilesx; | ||||
| 		m._31 = tilesy; | ||||
| @ -137,9 +210,30 @@ class ParticleSystem { | ||||
| 		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) { | ||||
| 		if (!object.data.geom.instanced) setupGeomGpu(object, owner); | ||||
| 		// GPU particles transform is attached to owner object | ||||
| 		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); | ||||
| 		} | ||||
| 		// GPU particles transform is attached to owner object in static mode | ||||
| 	} | ||||
|  | ||||
| 	function setupGeomGpu(object: MeshObject, owner: MeshObject) { | ||||
| @ -200,18 +294,134 @@ class ParticleSystem { | ||||
| 		object.data.geom.setupInstanced(instancedData, 1, Usage.StaticUsage); | ||||
| 	} | ||||
|  | ||||
| 	function fhash(n: Int): Float { | ||||
| 		var s = n + 1.0; | ||||
| 		s *= 9301.0 % s; | ||||
| 		s = (s * 9301.0 + 49297.0) % 233280.0; | ||||
| 		return s / 233280.0; | ||||
| 	// 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; | ||||
|     s *= 9301.0 % s; | ||||
|     s = (s * 9301.0 + 49297.0) % 233280.0; | ||||
|     return s / 233280.0; | ||||
| } | ||||
|  | ||||
| 	public function remove() {} | ||||
|  | ||||
| 	/** | ||||
| 		Generates a random point in the triangle with vertex positions abc. | ||||
|  | ||||
| 		 | ||||
| 		Please note that the given position vectors are changed in-place by this | ||||
| 		function and can be considered garbage afterwards, so make sure to clone | ||||
| 		them first if needed. | ||||
| @ -236,9 +446,11 @@ class ParticleSystem { | ||||
|  | ||||
| class Particle { | ||||
| 	public var i: Int; | ||||
| 	 | ||||
| 	public var x = 0.0; | ||||
| 	public var y = 0.0; | ||||
| 	public var z = 0.0; | ||||
|  | ||||
| 	public var cameraDistance: Float; | ||||
|  | ||||
| 	public function new(i: Int) { | ||||
|  | ||||
| @ -80,7 +80,7 @@ class Tilesheet { | ||||
| 	function update() { | ||||
| 		if (!ready || paused || action.start >= action.end) return; | ||||
|  | ||||
| 		time += Time.realDelta; | ||||
| 		time += Time.renderDelta; | ||||
|  | ||||
| 		var frameTime = 1 / raw.framerate; | ||||
| 		var framesToAdvance = 0; | ||||
|  | ||||
| @ -181,11 +181,15 @@ class Uniforms { | ||||
| 						// Multiple voxel volumes, always set params | ||||
| 						g.setImageTexture(context.textureUnits[j], rt.image); // image2D/3D | ||||
| 						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")) | ||||
| 						{ | ||||
| 							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 | ||||
| 						{ | ||||
| @ -1109,6 +1113,26 @@ class Uniforms { | ||||
| 				case "_texUnpack": { | ||||
| 					f = texUnpack != null ? texUnpack : 1.0; | ||||
| 				} | ||||
| 				#if lnx_particles | ||||
| 				case "_particleSizeRandom": { | ||||
| 					var mo = cast(object, MeshObject); | ||||
| 					if (mo.particleOwner != null && mo.particleOwner.particleSystems != null) { | ||||
| 						f = mo.particleOwner.particleSystems[mo.particleIndex].getSizeRandom(); | ||||
| 					} | ||||
| 				} | ||||
| 				case "_particleRandom": { | ||||
| 					var mo = cast(object, MeshObject); | ||||
| 					if (mo.particleOwner != null && mo.particleOwner.particleSystems != null) { | ||||
| 						f = mo.particleOwner.particleSystems[mo.particleIndex].getRandom(); | ||||
| 					} | ||||
| 				} | ||||
| 				case "_particleSize": { | ||||
| 					var mo = cast(object, MeshObject); | ||||
| 					if (mo.particleOwner != null && mo.particleOwner.particleSystems != null) { | ||||
| 						f = mo.particleOwner.particleSystems[mo.particleIndex].getSize(); | ||||
| 					} | ||||
| 				} | ||||
| 				#end | ||||
| 			} | ||||
|  | ||||
| 			if (f == null && externalFloatLinks != null) { | ||||
|  | ||||
| @ -160,6 +160,7 @@ class LnxPack { | ||||
| 			case "anim": TAnimation; | ||||
| 			case "tracks": TTrack; | ||||
| 			case "morph_target": TMorphTarget; | ||||
| 			case "vertex_groups": TVertex_groups; | ||||
| 			case _: TSceneFormat; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @ -1,37 +1,58 @@ | ||||
| package iron.system; | ||||
|  | ||||
| class Time { | ||||
|  | ||||
| 	public static var scale = 1.0; | ||||
| 	 | ||||
| 	static var frequency: Null<Int> = null; | ||||
| 	static function initFrequency() { | ||||
| 		frequency = kha.Display.primary != null ? kha.Display.primary.frequency : 60; | ||||
| 	} | ||||
| 	 | ||||
| 	public static var step(get, never): Float; | ||||
| 	static function get_step(): Float { | ||||
| 		if (frequency == null) initFrequency(); | ||||
| 		return 1 / frequency; | ||||
| 	} | ||||
| 	 | ||||
| 	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; | ||||
| 	} | ||||
|  | ||||
| 	public static var scale = 1.0; | ||||
| 	static var lastTime = 0.0; | ||||
| 	static var _delta = 0.0; | ||||
| 	public static var delta(get, never): Float; | ||||
| 	static function get_delta(): Float { | ||||
| 		if (frequency == null) initFrequency(); | ||||
| 		return (1 / frequency) * scale; | ||||
| 		return _delta; | ||||
| 	} | ||||
|  | ||||
| 	static var last = 0.0; | ||||
| 	public static var realDelta = 0.0; | ||||
| 	 | ||||
| 	static var lastRenderTime = 0.0; | ||||
| 	static var _renderDelta = 0.0; | ||||
| 	public static var renderDelta(get, never): Float; | ||||
| 	static function get_renderDelta(): Float { | ||||
| 		return _renderDelta; | ||||
| 	} | ||||
| 		 | ||||
| 	public static inline function time(): Float { | ||||
| 		return kha.Scheduler.time(); | ||||
| 		return kha.Scheduler.time() * scale; | ||||
| 	} | ||||
| 	 | ||||
| 	public static inline function realTime(): Float { | ||||
| 		return kha.Scheduler.realTime(); | ||||
| 	} | ||||
|  | ||||
| 	static var frequency: Null<Int> = null; | ||||
|  | ||||
| 	static function initFrequency() { | ||||
| 		frequency = kha.Display.primary != null ? kha.Display.primary.frequency : 60; | ||||
| 		return kha.Scheduler.realTime() * scale; | ||||
| 	} | ||||
|  | ||||
| 	public static function update() { | ||||
| 		realDelta = realTime() - last; | ||||
| 		last = realTime(); | ||||
| 		_delta = realTime() - lastTime; | ||||
| 		lastTime = realTime(); | ||||
| 	} | ||||
|  | ||||
| 	public static function render() { | ||||
| 		_renderDelta = realTime() - lastRenderTime; | ||||
| 		lastRenderTime = realTime(); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -94,34 +94,34 @@ class Tween { | ||||
|  | ||||
| 				// Way too much Reflect trickery.. | ||||
| 				var ps = Reflect.fields(a.props); | ||||
| 				for (i in 0...ps.length) { | ||||
| 					var p = ps[i]; | ||||
| 				for (j in 0...ps.length) { | ||||
| 					var p = ps[j]; | ||||
| 					var k = a._time / a.duration; | ||||
| 					if (k > 1) k = 1; | ||||
|  | ||||
| 					if (a._comps[i] == 1) { | ||||
| 						var fromVal: Float = a._x[i]; | ||||
| 					if (a._comps[j] == 1) { | ||||
| 						var fromVal: Float = a._x[j]; | ||||
| 						var toVal: Float = Reflect.getProperty(a.props, p); | ||||
| 						var val: Float = fromVal + (toVal - fromVal) * eases[a.ease](k); | ||||
| 						Reflect.setProperty(a.target, p, val); | ||||
| 					} | ||||
| 					else { // _comps[i] == 4 | ||||
| 					else { // _comps[j] == 4 | ||||
| 						var obj = Reflect.getProperty(a.props, p); | ||||
| 						var toX: Float = Reflect.getProperty(obj, "x"); | ||||
| 						var toY: Float = Reflect.getProperty(obj, "y"); | ||||
| 						var toZ: Float = Reflect.getProperty(obj, "z"); | ||||
| 						var toW: Float = Reflect.getProperty(obj, "w"); | ||||
| 						if (a._normalize[i]) { | ||||
| 							var qdot = (a._x[i] * toX) + (a._y[i] * toY) + (a._z[i] * toZ) + (a._w[i] * toW); | ||||
| 						if (a._normalize[j]) { | ||||
| 							var qdot = (a._x[j] * toX) + (a._y[j] * toY) + (a._z[j] * toZ) + (a._w[j] * toW); | ||||
| 							if (qdot < 0.0) { | ||||
| 								toX = -toX; toY = -toY; toZ = -toZ; toW = -toW; | ||||
| 							} | ||||
| 						} | ||||
| 						var x: Float = a._x[i] + (toX - a._x[i]) * eases[a.ease](k); | ||||
| 						var y: Float = a._y[i] + (toY - a._y[i]) * eases[a.ease](k); | ||||
| 						var z: Float = a._z[i] + (toZ - a._z[i]) * eases[a.ease](k); | ||||
| 						var w: Float = a._w[i] + (toW - a._w[i]) * eases[a.ease](k); | ||||
| 						if (a._normalize[i]) { | ||||
| 						var x: Float = a._x[j] + (toX - a._x[j]) * eases[a.ease](k); | ||||
| 						var y: Float = a._y[j] + (toY - a._y[j]) * eases[a.ease](k); | ||||
| 						var z: Float = a._z[j] + (toZ - a._z[j]) * eases[a.ease](k); | ||||
| 						var w: Float = a._w[j] + (toW - a._w[j]) * eases[a.ease](k); | ||||
| 						if (a._normalize[j]) { | ||||
| 							var l = Math.sqrt(x * x + y * y + z * z + w * w); | ||||
| 							if (l > 0.0) { | ||||
| 								l = 1.0 / l; | ||||
|  | ||||
							
								
								
									
										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 bytes = haxe.io.Bytes.ofString(haxe.Json.stringify(raw)); | ||||
| 		#if kha_krom | ||||
| 		if (iron.data.Data.dataPath == '') path = Krom.getFilesLocation() + "/config.lnx"; | ||||
| 		Krom.fileSaveBytes(path, bytes.getData()); | ||||
| 		#elseif kha_kore | ||||
| 		sys.io.File.saveBytes(path, bytes); | ||||
| @ -47,6 +48,7 @@ typedef TConfig = { | ||||
| 	@:optional var rp_ssr: Null<Bool>; | ||||
| 	@:optional var rp_ssrefr: Null<Bool>; | ||||
| 	@:optional var rp_bloom: Null<Bool>; | ||||
| 	@:optional var rp_chromatic_aberration: Null<Bool>; | ||||
| 	@:optional var rp_motionblur: Null<Bool>; | ||||
| 	@:optional var rp_gi: Null<Bool>; // voxelao | ||||
| 	@:optional var rp_dynres: Null<Bool>; // dynamic resolution scaling | ||||
|  | ||||
							
								
								
									
										99
									
								
								leenkx/Sources/leenkx/logicnode/AddParticleToObjectNode.hx
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -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); | ||||
| 	} | ||||
| } | ||||
| @ -2,9 +2,11 @@ package leenkx.logicnode; | ||||
|  | ||||
| import iron.object.Object; | ||||
|  | ||||
| #if lnx_physics | ||||
| #if lnx_bullet | ||||
| import leenkx.trait.physics.PhysicsConstraint; | ||||
| import leenkx.trait.physics.bullet.PhysicsConstraint.ConstraintType; | ||||
| #elseif lnx_oimo | ||||
| // TODO | ||||
| #end | ||||
|  | ||||
| class AddPhysicsConstraintNode extends LogicNode { | ||||
| @ -25,7 +27,7 @@ class AddPhysicsConstraintNode extends LogicNode { | ||||
|  | ||||
| 		if (pivotObject == null || rb1 == null || rb2 == null) return; | ||||
|  | ||||
| #if lnx_physics | ||||
| #if lnx_bullet | ||||
|  | ||||
| 		var disableCollisions: Bool = inputs[4].get(); | ||||
| 		var breakable: Bool = inputs[5].get(); | ||||
| @ -108,6 +110,8 @@ class AddPhysicsConstraintNode extends LogicNode { | ||||
| 			} | ||||
| 			pivotObject.addTrait(con); | ||||
| 		} | ||||
| #elseif lnx_oimo | ||||
| // TODO | ||||
| #end | ||||
| 		runOutput(0); | ||||
| 	} | ||||
|  | ||||
| @ -4,7 +4,7 @@ import iron.object.Object; | ||||
|  | ||||
| #if lnx_physics | ||||
| import leenkx.trait.physics.RigidBody; | ||||
| import leenkx.trait.physics.bullet.RigidBody.Shape; | ||||
| import leenkx.trait.physics.RigidBody.Shape; | ||||
| #end | ||||
|  | ||||
|  | ||||
|  | ||||
							
								
								
									
										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); | ||||
| 	} | ||||
| } | ||||
| @ -21,7 +21,7 @@ class ApplyForceNode extends LogicNode { | ||||
|  | ||||
| #if lnx_physics | ||||
| 		var rb: RigidBody = object.getTrait(RigidBody); | ||||
|  | ||||
| 		if (rb == null) return; | ||||
| 		!local ? rb.applyForce(force) : rb.applyForce(object.transform.worldVecToOrientation(force)); | ||||
| #end | ||||
|  | ||||
|  | ||||
							
								
								
									
										26
									
								
								leenkx/Sources/leenkx/logicnode/ArrayIndexListNode.hx
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,26 @@ | ||||
| package leenkx.logicnode; | ||||
|  | ||||
| class ArrayIndexListNode extends LogicNode { | ||||
|  | ||||
| 	public function new(tree: LogicTree) { | ||||
| 		super(tree); | ||||
| 	} | ||||
|  | ||||
| 	override function get(from: Int): Dynamic { | ||||
| 		var array: Array<Dynamic> = inputs[0].get(); | ||||
| 		array = array.map(item -> Std.string(item)); | ||||
| 		var value: Dynamic = inputs[1].get(); | ||||
| 		var from: Int = 0; | ||||
|  | ||||
| 		var arrayList: Array<Int> = []; | ||||
|  | ||||
| 		var index: Int = array.indexOf(Std.string(value), from); | ||||
|  | ||||
| 		while(index != -1){ | ||||
| 			arrayList.push(index); | ||||
| 			index = array.indexOf(Std.string(value), index+1); | ||||
| 		} | ||||
|  | ||||
| 		return arrayList; | ||||
| 	} | ||||
| } | ||||
| @ -1,7 +1,7 @@ | ||||
| package leenkx.logicnode; | ||||
| import aura.Aura; | ||||
| import aura.Types; | ||||
| import aura.types.HRTFData; | ||||
| import aura.types.HRTF; | ||||
| import aura.dsp.panner.HRTFPanner; | ||||
|  | ||||
| class AudioHRTFPannerNode extends LogicNode { | ||||
|  | ||||
							
								
								
									
										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
									
								
							
							
						
						| @ -0,0 +1,15 @@ | ||||
| package leenkx.logicnode; | ||||
|  | ||||
| class AutoExposureSetNode extends LogicNode { | ||||
|  | ||||
| 	public function new(tree:LogicTree) { | ||||
| 		super(tree); | ||||
| 	} | ||||
|  | ||||
| 	override function run(from:Int) { | ||||
|         leenkx.renderpath.Postprocess.auto_exposure_uniforms[0] = inputs[1].get(); | ||||
|         leenkx.renderpath.Postprocess.auto_exposure_uniforms[1] = inputs[2].get(); | ||||
|  | ||||
| 		runOutput(0); | ||||
| 	} | ||||
| } | ||||
| @ -1,26 +1,49 @@ | ||||
| package leenkx.logicnode; | ||||
|  | ||||
| class CameraSetNode extends LogicNode { | ||||
|  | ||||
| 	 | ||||
| 	public var property0: String; | ||||
| 	 | ||||
| 	public function new(tree:LogicTree) { | ||||
| 		super(tree); | ||||
| 	} | ||||
|  | ||||
| 	override function run(from:Int) { | ||||
| 		leenkx.renderpath.Postprocess.camera_uniforms[0] = inputs[1].get();//Camera: F-Number | ||||
| 		leenkx.renderpath.Postprocess.camera_uniforms[1] = inputs[2].get();//Camera: Shutter time | ||||
| 		leenkx.renderpath.Postprocess.camera_uniforms[2] = inputs[3].get();//Camera: ISO | ||||
| 		leenkx.renderpath.Postprocess.camera_uniforms[3] = inputs[4].get();//Camera: Exposure Compensation | ||||
| 		leenkx.renderpath.Postprocess.camera_uniforms[4] = inputs[5].get();//Fisheye Distortion | ||||
| 		leenkx.renderpath.Postprocess.camera_uniforms[5] = inputs[6].get();//DoF AutoFocus §§ If true, it ignores the DoF Distance setting | ||||
| 		leenkx.renderpath.Postprocess.camera_uniforms[6] = inputs[7].get();//DoF Distance | ||||
| 		leenkx.renderpath.Postprocess.camera_uniforms[7] = inputs[8].get();//DoF Focal Length mm | ||||
| 		leenkx.renderpath.Postprocess.camera_uniforms[8] = inputs[9].get();//DoF F-Stop | ||||
| 		leenkx.renderpath.Postprocess.camera_uniforms[9] = inputs[10].get();//Tonemapping Method | ||||
| 		leenkx.renderpath.Postprocess.camera_uniforms[10] = inputs[11].get();//Distort | ||||
| 		leenkx.renderpath.Postprocess.camera_uniforms[11] = inputs[12].get();//Film Grain | ||||
| 		leenkx.renderpath.Postprocess.camera_uniforms[12] = inputs[13].get();//Sharpen | ||||
| 		leenkx.renderpath.Postprocess.camera_uniforms[13] = inputs[14].get();//Vignette | ||||
|  | ||||
| 		switch (property0) { | ||||
| 			case 'F-stop': | ||||
| 				leenkx.renderpath.Postprocess.camera_uniforms[0] = inputs[1].get();//Camera: F-Number | ||||
| 			case 'Shutter Time':	 | ||||
| 				leenkx.renderpath.Postprocess.camera_uniforms[1] = inputs[1].get();//Camera: Shutter time | ||||
| 			case 'ISO': | ||||
| 				leenkx.renderpath.Postprocess.camera_uniforms[2] = inputs[1].get();//Camera: ISO | ||||
| 			case 'Exposure Compensation': | ||||
| 				leenkx.renderpath.Postprocess.camera_uniforms[3] = inputs[1].get();//Camera: Exposure Compensation | ||||
| 			case 'Fisheye Distortion': | ||||
| 				leenkx.renderpath.Postprocess.camera_uniforms[4] = inputs[1].get();//Fisheye Distortion | ||||
| 			case 'Auto Focus': | ||||
| 				leenkx.renderpath.Postprocess.camera_uniforms[5] = inputs[1].get();//DoF AutoFocus §§ If true, it ignores the DoF Distance setting | ||||
| 			case 'DoF Distance': | ||||
| 				leenkx.renderpath.Postprocess.camera_uniforms[6] = inputs[1].get();//DoF Distance | ||||
| 			case 'DoF Length': | ||||
| 				leenkx.renderpath.Postprocess.camera_uniforms[7] = inputs[1].get();//DoF Focal Length mm | ||||
| 			case 'DoF F-Stop': | ||||
| 				leenkx.renderpath.Postprocess.camera_uniforms[8] = inputs[1].get();//DoF F-Stop | ||||
| 			case 'Tonemapping': | ||||
| 				leenkx.renderpath.Postprocess.camera_uniforms[9] = inputs[1].get();//Tonemapping Method | ||||
| 			case 'Distort': | ||||
| 				leenkx.renderpath.Postprocess.camera_uniforms[10] = inputs[1].get();//Distort | ||||
| 			case 'Film Grain': | ||||
| 				leenkx.renderpath.Postprocess.camera_uniforms[11] = inputs[1].get();//Film Grain | ||||
| 			case 'Sharpen': | ||||
| 				leenkx.renderpath.Postprocess.camera_uniforms[12] = inputs[1].get();//Sharpen | ||||
| 			case 'Vignette': | ||||
| 				leenkx.renderpath.Postprocess.camera_uniforms[13] = inputs[1].get();//Vignette | ||||
| 			case 'Exposure': | ||||
| 				leenkx.renderpath.Postprocess.exposure_uniforms[0] = inputs[1].get();//Exposure | ||||
| 			default:  | ||||
| 				null; | ||||
| 			} | ||||
|  | ||||
| 		runOutput(0); | ||||
| 	} | ||||
|  | ||||
| @ -10,6 +10,7 @@ class ChromaticAberrationGetNode extends LogicNode { | ||||
| 		return switch (from) { | ||||
| 			case 0: leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[0]; | ||||
| 			case 1: leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[1]; | ||||
| 			case 2: leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[2]; | ||||
| 			default: 0.0; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @ -10,6 +10,7 @@ class ChromaticAberrationSetNode extends LogicNode { | ||||
|  | ||||
|         leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[0] = inputs[1].get(); | ||||
|         leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[1] = inputs[2].get(); | ||||
| 		leenkx.renderpath.Postprocess.chromatic_aberration_uniforms[2] = inputs[3].get(); | ||||
|  | ||||
| 		runOutput(0); | ||||
| 	} | ||||
|  | ||||
| @ -2,6 +2,9 @@ package leenkx.logicnode; | ||||
|  | ||||
| import iron.Scene; | ||||
| import iron.object.CameraObject; | ||||
| import iron.math.Vec4; | ||||
| import iron.math.Quat; | ||||
| import leenkx.math.Helper; | ||||
|  | ||||
| import leenkx.renderpath.RenderPathCreator; | ||||
|  | ||||
| @ -27,11 +30,19 @@ class DrawCameraTextureNode extends LogicNode { | ||||
| 				final c = inputs[2].get(); | ||||
| 				assert(Error, Std.isOfType(c, CameraObject), "Camera must be a camera object!"); | ||||
| 				cam = cast(c, CameraObject); | ||||
| 				rt = kha.Image.createRenderTarget(iron.App.w(), iron.App.h()); | ||||
| 				rt = kha.Image.createRenderTarget(iron.App.w(), iron.App.h(), | ||||
| 					kha.graphics4.TextureFormat.RGBA32, | ||||
| 					kha.graphics4.DepthStencilFormat.NoDepthAndStencil); | ||||
|  | ||||
| 				assert(Error, mo.materials[matSlot].contexts[0].textures != null, 'Object "${mo.name}" has no diffuse texture to render to'); | ||||
| 				mo.materials[matSlot].contexts[0].textures[0] = rt; // Override diffuse texture | ||||
|  | ||||
|                 final n = inputs[5].get(); | ||||
| 				for (i => node in mo.materials[matSlot].contexts[0].raw.bind_textures){ | ||||
| 					if (node.name == n){ | ||||
| 						mo.materials[matSlot].contexts[0].textures[i] = rt; // Override diffuse texture | ||||
| 						break; | ||||
| 					} | ||||
| 				} | ||||
| 				tree.notifyOnRender(render); | ||||
| 				runOutput(0); | ||||
|  | ||||
| @ -48,8 +59,20 @@ class DrawCameraTextureNode extends LogicNode { | ||||
| 		iron.Scene.active.camera = cam; | ||||
| 		cam.renderTarget = rt; | ||||
|  | ||||
| 		#if kha_html5 | ||||
| 		var q: Quat = new Quat(); | ||||
| 		q.fromAxisAngle(new Vec4(0, 0, 1, 1), Helper.degToRad(180)); | ||||
| 		cam.transform.rot.mult(q); | ||||
| 		cam.transform.buildMatrix(); | ||||
| 		#end | ||||
|  | ||||
| 		cam.renderFrame(g); | ||||
|  | ||||
| 		#if kha_html5 | ||||
| 		cam.transform.rot.mult(q); | ||||
| 		cam.transform.buildMatrix(); | ||||
| 		#end | ||||
|  | ||||
| 		cam.renderTarget = oldRT; | ||||
| 		iron.Scene.active.camera = sceneCam; | ||||
| 	} | ||||
|  | ||||
| @ -99,8 +99,6 @@ class DrawImageSequenceNode extends LogicNode { | ||||
| 		final colorVec = inputs[4].get(); | ||||
| 		g.color = Color.fromFloats(colorVec.x, colorVec.y, colorVec.z, colorVec.w); | ||||
|  | ||||
| 		trace(currentImgIdx); | ||||
|  | ||||
| 		g.drawScaledImage(images[currentImgIdx], inputs[5].get(), inputs[6].get(), inputs[7].get(), inputs[8].get()); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -62,7 +62,7 @@ class DrawStringNode extends LogicNode { | ||||
|  | ||||
| 	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); | ||||
| 			 | ||||
| 	} | ||||
| } | ||||
|  | ||||