Compare commits
873 Commits
cd6930c56b
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 5357b5ce25 | |||
| 1372c687f0 | |||
| 6a914782a5 | |||
| f4ada6ba50 | |||
| 4211317c03 | |||
| 9126175569 | |||
| 394ab38a80 | |||
| cc95912a7e | |||
| 85a44b930d | |||
| cd3090817a | |||
| d45c632dcd | |||
| 1c3c30e6ce | |||
| c9839c9be6 | |||
| 6a17251520 | |||
| 0adcafd697 | |||
| 423807c62f | |||
| 5598161b40 | |||
| e6ac30e57f | |||
| 5d1132b24c | |||
| 232ae3e7bc | |||
| a861665c98 | |||
| 4852a40848 | |||
| a00f3506ed | |||
| 9aa01e6436 | |||
| 18c564048f | |||
| da19096658 | |||
| 06343dcca1 | |||
| 4375087d3a | |||
| 825f783cbe | |||
| 2f9a24753e | |||
| 07efcaffdb | |||
| a6bef6b35a | |||
| b88f471f0f | |||
| 7e31a73d28 | |||
| 7fa4be0b07 | |||
| d5f3f05ab6 | |||
| 3bee97a560 | |||
| 4f4f28d62f | |||
| 7076fb6b7e | |||
| b72a22b5e9 | |||
| b265ab863c | |||
| 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 | |||
| 1958342a74 | |||
| 16e8e00783 | |||
| bcdcbfb106 | |||
| 28afefbbf7 | |||
| 3d2130e26a | |||
| 9761719dd5 | |||
| b2a781c7c2 | |||
| 7121737297 | |||
| b0991a8928 | |||
| b84fc93899 | |||
| 06c0c430a8 | |||
| 0f0c67dc07 | |||
| 3bb2d65faa | |||
| 20e33afeac | |||
| 9c5fc5d1d3 | |||
| 6bed0cbc6d | |||
| 0eb4effeb3 | |||
| 238acaad0a | |||
| f4f5665835 | |||
| eb15dddd38 | |||
| 8c238c320d | |||
| ef27ce45ae | |||
| 61a4bf0ff8 | |||
| b985c5949b |
2
.gitattributes
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
*.hdr binary
|
||||
blender/lnx/props.py ident
|
||||
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
__pycache__/
|
||||
*.pyc
|
||||
*.DS_Store
|
||||
**/workspace.xml
|
||||
**/vcs.xml
|
||||
@ -227,7 +227,7 @@ class SystemImpl {
|
||||
}
|
||||
|
||||
static inline var maxGamepads: Int = 4;
|
||||
static var frame: Framebuffer;
|
||||
public static var frame: Framebuffer;
|
||||
static var keyboard: Keyboard = null;
|
||||
static var mouse: kha.input.Mouse;
|
||||
static var surface: Surface;
|
||||
@ -388,7 +388,8 @@ class SystemImpl {
|
||||
{
|
||||
alpha: false,
|
||||
antialias: options.framebuffer.samplesPerPixel > 1,
|
||||
stencil: true
|
||||
stencil: true,
|
||||
xrCompatible: true
|
||||
}); // preserveDrawingBuffer: true } ); Warning: preserveDrawingBuffer can cause huge performance issues on mobile browsers
|
||||
SystemImpl.gl.pixelStorei(GL.UNPACK_PREMULTIPLY_ALPHA_WEBGL, 1);
|
||||
|
||||
@ -417,7 +418,8 @@ class SystemImpl {
|
||||
{
|
||||
alpha: false,
|
||||
antialias: options.framebuffer.samplesPerPixel > 1,
|
||||
stencil: true
|
||||
stencil: true,
|
||||
xrCompatible: true
|
||||
}); // preserveDrawingBuffer: true } ); WARNING: preserveDrawingBuffer causes huge performance issues (on mobile browser)!
|
||||
SystemImpl.gl.pixelStorei(GL.UNPACK_PREMULTIPLY_ALPHA_WEBGL, 1);
|
||||
SystemImpl.gl.getExtension("OES_texture_float");
|
||||
@ -547,6 +549,12 @@ class SystemImpl {
|
||||
];
|
||||
|
||||
function animate(timestamp) {
|
||||
if (untyped Browser.window._khaSkipWindowRender == true) {
|
||||
if (requestAnimationFrame != null)
|
||||
requestAnimationFrame(animate);
|
||||
return;
|
||||
}
|
||||
|
||||
if (requestAnimationFrame == null)
|
||||
Browser.window.setTimeout(animate, 1000.0 / 60.0);
|
||||
else
|
||||
|
||||
@ -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;
|
||||
@ -155,4 +157,5 @@ extern class Krom {
|
||||
static function getConstantLocationCompute(shader: Dynamic, name: String): Dynamic;
|
||||
static function getTextureUnitCompute(shader: Dynamic, name: String): Dynamic;
|
||||
static function compute(x: Int, y: Int, z: Int): Void;
|
||||
static function viewportSetCamera(posX: Float, posY: Float, posZ: Float, rotX: Float, rotY: Float, rotZ: Float, rotW: Float): Void;
|
||||
}
|
||||
|
||||
@ -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
@ -1 +0,0 @@
|
||||
# armorcore_bin
|
||||
14
README.md
@ -6,22 +6,12 @@ Welcome to Leenkx!
|
||||
|
||||
|
||||
<br>
|
||||
- <a style="color:#2AE0E0;" class="text primary primary-text" href="https://leenkx.com/files/LeenkxSDK3_RC.zip">LeenkxSDKV3.6 lts</a>
|
||||
<br>
|
||||
- <a style="color:#2AE0E0;" class="text primary primary-text" href="https://leenkx.com/files/lx/Leenkx.js">Leenkx.js</a>
|
||||
<br>
|
||||
- Run your own private p2p torrent socket changing Leenkx javascript file directly in /lnxsdk/lib/leenkx_tools/lxjs/Leenkx.js or by configuring the OPTS map in the create Leenkx node.
|
||||
- Run your own private p2p torrent socket changing Leenkx javascript file directly in /lnxsdk/lib/leenkx_tools/lnxjs/Leenkx.js or by configuring the OPTS map in the create Leenkx node.
|
||||
<br>
|
||||
- All works are open source ZLIB / MIT and any compatible licence that guarantee the softwares freedom from my additions to the previous maintainers
|
||||
<br>
|
||||
- LxJS Works as a standalone library
|
||||
- LNXJS Works as a standalone library
|
||||
<br>
|
||||
- The SDK is not ready for production, use for educational purposes. Help the team by reaching out at Leenkx.com!
|
||||
<br>
|
||||
- This build is based on QuantumCoder's whole new core animation system packed with new features! Timmodrians Aura library is also built into this build when audio is enabled!
|
||||
<br>
|
||||
- The SDK is still undergoing many changes so working on large projects is not recommended.
|
||||
<br>
|
||||
- Special thanks to all contributors from the following projects!
|
||||
<br>
|
||||
* https://github.com/armory3d/armory/graphs/contributors<br>
|
||||
|
||||
@ -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'])
|
||||
|
||||
49
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/')
|
||||
|
||||
@ -182,7 +190,7 @@ class LeenkxAddonPreferences(AddonPreferences):
|
||||
description=(
|
||||
"Whether to use OpenCL processing to generate radiance maps with CMFT."
|
||||
" If you experience extremely long build times caused by CMFT, try disabling this option."
|
||||
" For more information see https://github.com/leenkx3d/leenkx/issues/2760"
|
||||
" For more information see https://dev.leenkx.com/LeenkxTeam/LNXSDK/issues/2760"
|
||||
))
|
||||
legacy_shaders: BoolProperty(name="Legacy Shaders", description="Attempt to compile shaders runnable on older hardware, use this for WebGL1 or GLES2 support in mobile render path", default=False)
|
||||
relative_paths: BoolProperty(name="Generate Relative Paths", description="Write relative paths in khafile", default=False)
|
||||
@ -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] != 3 or bpy.app.version[1] != 6:
|
||||
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, you need Blender 3.6 LTS.")
|
||||
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:
|
||||
@ -617,8 +625,6 @@ def try_os_call(func: Callable, *args, **kwargs) -> bool:
|
||||
|
||||
|
||||
def git_clone(done: Callable[[bool], None], rootdir: str, gitn: str, subdir: str, recursive=False):
|
||||
print('Download SDK manually from https://leenkx.com...')
|
||||
return False
|
||||
rootdir = os.path.normpath(rootdir)
|
||||
path = rootdir + '/' + subdir if subdir != '' else rootdir
|
||||
|
||||
@ -629,14 +635,12 @@ def git_clone(done: Callable[[bool], None], rootdir: str, gitn: str, subdir: str
|
||||
shutil.rmtree(path, onerror=remove_readonly)
|
||||
|
||||
if recursive:
|
||||
run_proc(['git', 'clone', '--recursive', 'https://github.com/' + gitn, path, '--depth', '1', '--shallow-submodules', '--jobs', '4'], done)
|
||||
run_proc(['git', 'clone', '--recursive', 'https://dev.leenkx.com/' + gitn, path, '--depth', '1', '--shallow-submodules', '--jobs', '4'], done)
|
||||
else:
|
||||
run_proc(['git', 'clone', 'https://github.com/' + gitn, path, '--depth', '1'], done)
|
||||
run_proc(['git', 'clone', 'https://dev.leenkx.com/' + gitn, path, '--depth', '1'], done)
|
||||
|
||||
|
||||
def git_test(self: bpy.types.Operator, required_version=None):
|
||||
print('Download SDK manually from https://leenkx.com...')
|
||||
return False
|
||||
try:
|
||||
p = subprocess.Popen(['git', '--version'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
output, _ = p.communicate()
|
||||
@ -789,7 +793,7 @@ def download_sdk(self: bpy.types.Operator, context):
|
||||
else:
|
||||
done(False)
|
||||
|
||||
git_clone(done_clone, sdk_path, 'leenkx3d/lnxsdk', '', recursive=True)
|
||||
git_clone(done_clone, sdk_path, 'LeenkxTeam/LNXSDK', '', recursive=True)
|
||||
|
||||
|
||||
class LnxAddonRestoreButton(bpy.types.Operator):
|
||||
@ -812,7 +816,7 @@ class LnxAddonHelpButton(bpy.types.Operator):
|
||||
"""Updater help"""
|
||||
bl_idname = "lnx_addon.help"
|
||||
bl_label = "Help"
|
||||
bl_description = "Leenkx Updater is currently disabled. Download SDK manually from https://leenkx.com"
|
||||
bl_description = "Leenkx Updater to get the latest SDK from https://dev.leenkx.com/LeenkxTeam/LNXSDK"
|
||||
|
||||
def execute(self, context):
|
||||
webbrowser.open('https://leenkx.com/support')
|
||||
@ -844,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)
|
||||
|
||||
|
||||
@ -918,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;
|
||||
@ -14,7 +14,7 @@ out vec4 fragColor;
|
||||
vec2 barrelDistortion(vec2 coord, float amt) {
|
||||
vec2 cc = coord - 0.5;
|
||||
float dist = dot(cc, cc);
|
||||
return coord + cc * dist * amt;
|
||||
return coord - cc * dist * amt;
|
||||
}
|
||||
float sat(float value)
|
||||
{
|
||||
@ -43,17 +43,19 @@ 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);
|
||||
vec2 uv = (texCoord.xy/resolution.xy);
|
||||
vec4 sumcol = vec4(0.0);
|
||||
vec4 sumw = vec4(0.0);
|
||||
for (int i=0; i < num_iter; ++i)
|
||||
@ -61,18 +63,21 @@ void main() {
|
||||
float t = float(i) * reci_num_iter_f;
|
||||
vec4 w = spectrum_offset(t);
|
||||
sumw += w;
|
||||
sumcol += w * texture(tex, barrelDistortion(uv, 0.6 * max_distort * t));
|
||||
vec2 distortedUV = barrelDistortion(texCoord, 0.6 * max_distort * t);
|
||||
sumcol += w * texture(tex, distortedUV);
|
||||
}
|
||||
|
||||
fragColor = sumcol / sumw;
|
||||
if (on == 1) fragColor = sumcol / sumw; else fragColor = texture(tex, texCoord);
|
||||
}
|
||||
|
||||
// Simple
|
||||
// inward sampling to avoid edge artifacts
|
||||
else {
|
||||
vec3 col = vec3(0.0);
|
||||
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);
|
||||
vec2 toCenter = (vec2(0.5) - texCoord) * max_distort / 500.0;
|
||||
col.x = texture(tex, texCoord + toCenter * 0.0).x;
|
||||
col.y = texture(tex, texCoord + toCenter * 0.5).y;
|
||||
col.z = texture(tex, texCoord + toCenter * 1.0).z;
|
||||
if (on == 1) fragColor = vec4(col.x, col.y, col.z, 1.0);
|
||||
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;
|
||||
@ -344,21 +357,33 @@ void main() {
|
||||
#else
|
||||
fragColor = textureLod(tex, texCo, 0.0);
|
||||
#endif
|
||||
|
||||
// TODO: re-investigate white artifacts
|
||||
fragColor.rgb = clamp(fragColor.rgb, vec3(0.0), vec3(65504.0));
|
||||
if (any(isnan(fragColor.rgb)) || any(isinf(fragColor.rgb))) {
|
||||
fragColor.rgb = vec3(0.0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#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 +432,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 +444,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 +509,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 +534,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 +657,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;
|
||||
@ -58,6 +59,10 @@ uniform vec3 backgroundCol;
|
||||
uniform sampler2D ssaotex;
|
||||
#endif
|
||||
|
||||
#ifdef _SSGI
|
||||
uniform sampler2D ssgitex;
|
||||
#endif
|
||||
|
||||
#ifdef _SSS
|
||||
uniform vec2 lightPlane;
|
||||
#endif
|
||||
@ -97,8 +102,23 @@ uniform mat4 invVP;
|
||||
#endif
|
||||
|
||||
uniform vec2 cameraProj;
|
||||
#ifdef _VRStereo
|
||||
uniform vec3 eye; // center camera position
|
||||
uniform vec3 eyeLook; // center camera look
|
||||
uniform vec3 eyeLeft;
|
||||
uniform vec3 eyeRight;
|
||||
uniform vec3 eyeLookLeft;
|
||||
uniform vec3 eyeLookRight;
|
||||
uniform mat4 invVPLeft;
|
||||
uniform mat4 invVPRight;
|
||||
#ifdef _SinglePoint
|
||||
uniform vec3 pointPosLeft;
|
||||
uniform vec3 pointPosRight;
|
||||
#endif
|
||||
#else
|
||||
uniform vec3 eye;
|
||||
uniform vec3 eyeLook;
|
||||
#endif
|
||||
|
||||
#ifdef _Clusters
|
||||
uniform vec4 lightsArray[maxLights * 3];
|
||||
@ -113,11 +133,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 +149,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 +195,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];
|
||||
@ -177,7 +215,9 @@ uniform vec3 sunCol;
|
||||
#endif
|
||||
|
||||
#ifdef _SinglePoint // Fast path for single light
|
||||
#ifndef _VRStereo
|
||||
uniform vec3 pointPos;
|
||||
#endif
|
||||
uniform vec3 pointCol;
|
||||
#ifdef _ShadowMap
|
||||
uniform float pointBias;
|
||||
@ -202,6 +242,8 @@ out vec4 fragColor;
|
||||
|
||||
void main() {
|
||||
vec4 g0 = textureLod(gbuffer0, texCoord, 0.0); // Normal.xy, roughness, metallic/matid
|
||||
vec4 g1 = textureLod(gbuffer1, texCoord, 0.0); // Basecolor.rgb, spec/occ
|
||||
float depth = textureLod(gbufferD, texCoord, 0.0).r * 2.0 - 1.0;
|
||||
|
||||
vec3 n;
|
||||
n.z = 1.0 - abs(g0.x) - abs(g0.y);
|
||||
@ -213,31 +255,50 @@ void main() {
|
||||
uint matid;
|
||||
unpackFloatInt16(g0.a, metallic, matid);
|
||||
|
||||
vec4 g1 = textureLod(gbuffer1, texCoord, 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 depth = textureLod(gbufferD, texCoord, 0.0).r * 2.0 - 1.0;
|
||||
// re-investigate clamp basecolor to prevent extreme values causing glitches
|
||||
vec3 basecolor = min(g1.rgb, vec3(2.0));
|
||||
vec3 albedo = surfaceAlbedo(basecolor, metallic);
|
||||
vec3 f0 = surfaceF0(basecolor, metallic);
|
||||
|
||||
#ifdef _VRStereo
|
||||
bool isLeftEye = texCoord.x < 0.5;
|
||||
vec3 eyePos = isLeftEye ? eyeLeft : eyeRight;
|
||||
mat4 invVP_eye = isLeftEye ? invVPLeft : invVPRight;
|
||||
|
||||
vec2 eyeTexCoord = vec2(
|
||||
isLeftEye ? texCoord.x * 2.0 : (texCoord.x - 0.5) * 2.0,
|
||||
texCoord.y
|
||||
);
|
||||
|
||||
vec3 p = getPos2(invVP_eye, depth, eyeTexCoord);
|
||||
vec3 v = normalize(eyePos - p);
|
||||
#else
|
||||
vec3 p = getPos(eye, eyeLook, normalize(viewRay), depth, cameraProj);
|
||||
vec3 v = normalize(eye - p);
|
||||
#endif
|
||||
float dotNV = max(dot(n, v), 0.0);
|
||||
|
||||
#ifdef _gbuffer2
|
||||
vec4 g2 = textureLod(gbuffer2, texCoord, 0.0);
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _MicroShadowing
|
||||
occspec.x = mix(1.0, occspec.x, dotNV); // AO Fresnel
|
||||
#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
|
||||
@ -259,6 +320,7 @@ void main() {
|
||||
vec3 reflectionWorld = reflect(-v, n);
|
||||
float lod = getMipFromRoughness(roughness, envmapNumMipmaps);
|
||||
vec3 prefilteredColor = textureLod(senvmapRadiance, envMapEquirect(reflectionWorld), lod).rgb;
|
||||
prefilteredColor = min(prefilteredColor, vec3(20.0));
|
||||
#endif
|
||||
|
||||
#ifdef _EnvLDR
|
||||
@ -271,33 +333,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);
|
||||
@ -312,11 +374,12 @@ void main() {
|
||||
// fragColor.rgb = texture(ssaotex, texCoord).rrr;
|
||||
|
||||
#ifdef _SSAO
|
||||
// #ifdef _RTGI
|
||||
// fragColor.rgb *= textureLod(ssaotex, texCoord, 0.0).rgb;
|
||||
// #else
|
||||
fragColor.rgb *= textureLod(ssaotex, texCoord, 0.0).r;
|
||||
// #endif
|
||||
#endif
|
||||
|
||||
#ifdef _SSGI
|
||||
vec3 ssgiColor = textureLod(ssgitex, texCoord, 0.0).rgb;
|
||||
fragColor.rgb += ssgiColor * albedo;
|
||||
#endif
|
||||
|
||||
#ifdef _EmissionShadeless
|
||||
@ -350,39 +413,69 @@ void main() {
|
||||
#ifdef _CSM
|
||||
svisibility = shadowTestCascade(
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifdef _ShadowMapTransparent
|
||||
#ifndef _SingleAtlas
|
||||
shadowMapAtlasSun, shadowMapAtlasSunTransparent
|
||||
#else
|
||||
shadowMapAtlas, shadowMapAtlasTransparent
|
||||
#endif
|
||||
#else
|
||||
#ifndef _SingleAtlas
|
||||
shadowMapAtlasSun
|
||||
#else
|
||||
shadowMapAtlas
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
shadowMap, shadowMapTransparent
|
||||
#ifdef _ShadowMapTransparent
|
||||
shadowMap, shadowMapTransparent
|
||||
#else
|
||||
shadowMap
|
||||
#endif
|
||||
#endif
|
||||
, eye, p + n * shadowsBias * 10, shadowsBias, false
|
||||
);
|
||||
, eye, p + n * shadowsBias * 2, shadowsBias
|
||||
#ifdef _ShadowMapTransparent
|
||||
, false
|
||||
#endif
|
||||
);
|
||||
#else
|
||||
vec4 lPos = LWVP * vec4(p + n * shadowsBias * 100, 1.0);
|
||||
vec4 lPos = LWVP * vec4(p + n * shadowsBias * 2, 1.0);
|
||||
if (lPos.w > 0.0) {
|
||||
svisibility = shadowTest(
|
||||
#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
|
||||
, lPos.xyz / lPos.w, shadowsBias, false
|
||||
);
|
||||
#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);
|
||||
@ -436,16 +529,25 @@ void main() {
|
||||
|
||||
#ifdef _SinglePoint
|
||||
|
||||
#ifdef _VRStereo
|
||||
vec3 lightPos = pointPosLeft;
|
||||
#else
|
||||
vec3 lightPos = pointPos;
|
||||
#endif
|
||||
|
||||
fragColor.rgb += sampleLight(
|
||||
p, n, v, dotNV, pointPos, pointCol, albedo, roughness, occspec.y, f0
|
||||
p, n, v, dotNV, lightPos, 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
|
||||
@ -457,7 +559,9 @@ void main() {
|
||||
|
||||
#ifdef _Spot
|
||||
#ifdef _SSS
|
||||
if (matid == 2) fragColor.rgb += fragColor.rgb * SSSSTransmittance(LWVPSpot[0], p, n, normalize(pointPos - p), lightPlane.y, shadowMapSpot[0]);//TODO implement transparent shadowmaps into the SSSSTransmittance()
|
||||
#ifdef _ShadowMap
|
||||
if (matid == 2) fragColor.rgb += fragColor.rgb * SSSSTransmittance(LWVPSpot[0], p, n, normalize(lightPos - p), lightPlane.y, shadowMapSpot[0]);//TODO implement transparent shadowmaps into the SSSSTransmittance()
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@ -492,7 +596,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 +610,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 +621,11 @@ 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.rgb = clamp(fragColor.rgb, vec3(0.0), vec3(65504.0));
|
||||
if (any(isnan(fragColor.rgb)) || any(isinf(fragColor.rgb))) {
|
||||
fragColor.rgb = vec3(0.0);
|
||||
}
|
||||
|
||||
fragColor.a = 1.0; // Mark as opaque
|
||||
}
|
||||
|
||||
@ -20,6 +20,36 @@
|
||||
"name": "eyeLook",
|
||||
"link": "_cameraLook"
|
||||
},
|
||||
{
|
||||
"name": "eyeLeft",
|
||||
"link": "_eyeLeft",
|
||||
"ifdef": ["_VRStereo"]
|
||||
},
|
||||
{
|
||||
"name": "eyeRight",
|
||||
"link": "_eyeRight",
|
||||
"ifdef": ["_VRStereo"]
|
||||
},
|
||||
{
|
||||
"name": "eyeLookLeft",
|
||||
"link": "_eyeLookLeft",
|
||||
"ifdef": ["_VRStereo"]
|
||||
},
|
||||
{
|
||||
"name": "eyeLookRight",
|
||||
"link": "_eyeLookRight",
|
||||
"ifdef": ["_VRStereo"]
|
||||
},
|
||||
{
|
||||
"name": "invVPLeft",
|
||||
"link": "_inverseViewProjectionMatrixLeft",
|
||||
"ifdef": ["_VRStereo"]
|
||||
},
|
||||
{
|
||||
"name": "invVPRight",
|
||||
"link": "_inverseViewProjectionMatrixRight",
|
||||
"ifdef": ["_VRStereo"]
|
||||
},
|
||||
{
|
||||
"name": "clipmaps",
|
||||
"link": "_clipmaps",
|
||||
@ -176,8 +206,19 @@
|
||||
{
|
||||
"name": "pointPos",
|
||||
"link": "_pointPosition",
|
||||
"ifndef": ["_VRStereo"],
|
||||
"ifdef": ["_SinglePoint"]
|
||||
},
|
||||
{
|
||||
"name": "pointPosLeft",
|
||||
"link": "_pointPositionLeft",
|
||||
"ifdef": ["_VRStereo", "_SinglePoint"]
|
||||
},
|
||||
{
|
||||
"name": "pointPosRight",
|
||||
"link": "_pointPositionRight",
|
||||
"ifdef": ["_VRStereo", "_SinglePoint"]
|
||||
},
|
||||
{
|
||||
"name": "pointCol",
|
||||
"link": "_pointColor",
|
||||
|
||||
@ -97,6 +97,31 @@
|
||||
"link": "_cascadeData",
|
||||
"ifdef": ["_Sun", "_ShadowMap", "_CSM"]
|
||||
},
|
||||
{
|
||||
"name": "eyeLookRight",
|
||||
"link": "_eyeLookRight",
|
||||
"ifdef": ["_VRStereo"]
|
||||
},
|
||||
{
|
||||
"name": "invVPLeft",
|
||||
"link": "_inverseViewProjectionMatrixLeft",
|
||||
"ifdef": ["_VRStereo"]
|
||||
},
|
||||
{
|
||||
"name": "invVPRight",
|
||||
"link": "_inverseViewProjectionMatrixRight",
|
||||
"ifdef": ["_VRStereo"]
|
||||
},
|
||||
{
|
||||
"name": "invVP",
|
||||
"link": "_viewProjectionMatrix",
|
||||
"ifdef": ["_SSRS"]
|
||||
},
|
||||
{
|
||||
"name": "smSizeUniform",
|
||||
"link": "_shadowMapSize",
|
||||
"ifdef": ["_SMSizeUniform"]
|
||||
},
|
||||
{
|
||||
"name": "lightPlane",
|
||||
"link": "_lightPlane",
|
||||
@ -108,8 +133,6 @@
|
||||
"ifdef": ["_SSRS"]
|
||||
},
|
||||
{
|
||||
"name": "smSizeUniform",
|
||||
"link": "_shadowMapSize",
|
||||
"ifdef": ["_SMSizeUniform"]
|
||||
},
|
||||
{
|
||||
@ -120,8 +143,19 @@
|
||||
{
|
||||
"name": "pointPos",
|
||||
"link": "_pointPosition",
|
||||
"ifndef": ["_VRStereo"],
|
||||
"ifdef": ["_SinglePoint"]
|
||||
},
|
||||
{
|
||||
"name": "pointPosLeft",
|
||||
"link": "_pointPositionLeft",
|
||||
"ifdef": ["_VRStereo", "_SinglePoint"]
|
||||
},
|
||||
{
|
||||
"name": "pointPosRight",
|
||||
"link": "_pointPositionRight",
|
||||
"ifdef": ["_VRStereo", "_SinglePoint"]
|
||||
},
|
||||
{
|
||||
"name": "pointCol",
|
||||
"link": "_pointColor",
|
||||
|
||||
9
leenkx/Shaders/fsr1_easu_pass/LICENSE.txt
Normal file
@ -0,0 +1,9 @@
|
||||
https://gpuopen.com/manuals/fidelityfx_sdk/license/
|
||||
|
||||
Copyright © 2024 Advanced Micro Devices, Inc.
|
||||
|
||||
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.
|
||||
157
leenkx/Shaders/fsr1_easu_pass/fsr1_easu_pass.frag.glsl
Normal file
@ -0,0 +1,157 @@
|
||||
#version 450
|
||||
|
||||
// AMD FidelityFX Super Resolution 1.0.2 - EASU (Edge Adaptive Spatial Upsampling)
|
||||
|
||||
#include "compiled.inc"
|
||||
|
||||
uniform sampler2D tex;
|
||||
uniform vec2 screenSize;
|
||||
|
||||
in vec2 texCoord;
|
||||
out vec4 fragColor;
|
||||
|
||||
// Helper functions from AMD ffx_a.h
|
||||
float APrxLoRcpF1(float a) {
|
||||
return uintBitsToFloat(uint(0x7ef07ebb) - floatBitsToUint(a));
|
||||
}
|
||||
|
||||
float AMax3F1(float x, float y, float z) {
|
||||
return max(x, max(y, z));
|
||||
}
|
||||
|
||||
float AMin3F1(float x, float y, float z) {
|
||||
return min(x, min(y, z));
|
||||
}
|
||||
|
||||
// Attempt to use textureGather for efficiency when available
|
||||
#if __VERSION__ >= 400
|
||||
|
||||
void FsrEasuTap(
|
||||
inout vec3 aC,
|
||||
inout float aW,
|
||||
vec2 off,
|
||||
vec2 dir,
|
||||
vec2 len,
|
||||
float lob,
|
||||
float clp,
|
||||
vec3 c
|
||||
) {
|
||||
vec2 v = off * dir;
|
||||
float d2 = v.x + v.y;
|
||||
d2 = clamp(d2 * APrxLoRcpF1(max(abs(v.x), abs(v.y))), 0.0, 1.0);
|
||||
d2 = d2 * d2;
|
||||
d2 = d2 * len.x + len.y;
|
||||
float wB = 2.0 / 5.0 * d2 - 1.0;
|
||||
float wA = lob * d2 - 1.0;
|
||||
wB *= wB;
|
||||
wA *= wA;
|
||||
float w = 25.0 / 16.0 * wA * wB;
|
||||
w = min(w, clp);
|
||||
w = max(w, 0.0);
|
||||
aC += c * w;
|
||||
aW += w;
|
||||
}
|
||||
|
||||
vec3 FsrEasuF(vec2 ip) {
|
||||
vec2 inputSize = textureSize(tex, 0);
|
||||
vec2 inputRcp = 1.0 / inputSize;
|
||||
|
||||
// Position in input pixels
|
||||
vec2 pp = ip * inputSize - 0.5;
|
||||
vec2 fp = floor(pp);
|
||||
pp -= fp;
|
||||
|
||||
// 12-tap kernel
|
||||
// b c
|
||||
// e f g h
|
||||
// i j k l
|
||||
// n o
|
||||
ivec2 sp = ivec2(fp);
|
||||
|
||||
vec3 b = texelFetch(tex, sp + ivec2(0, -1), 0).rgb;
|
||||
vec3 c = texelFetch(tex, sp + ivec2(1, -1), 0).rgb;
|
||||
vec3 e = texelFetch(tex, sp + ivec2(-1, 0), 0).rgb;
|
||||
vec3 f = texelFetch(tex, sp + ivec2(0, 0), 0).rgb;
|
||||
vec3 g = texelFetch(tex, sp + ivec2(1, 0), 0).rgb;
|
||||
vec3 h = texelFetch(tex, sp + ivec2(2, 0), 0).rgb;
|
||||
vec3 i = texelFetch(tex, sp + ivec2(-1, 1), 0).rgb;
|
||||
vec3 j = texelFetch(tex, sp + ivec2(0, 1), 0).rgb;
|
||||
vec3 k = texelFetch(tex, sp + ivec2(1, 1), 0).rgb;
|
||||
vec3 l = texelFetch(tex, sp + ivec2(2, 1), 0).rgb;
|
||||
vec3 n = texelFetch(tex, sp + ivec2(0, 2), 0).rgb;
|
||||
vec3 o = texelFetch(tex, sp + ivec2(1, 2), 0).rgb;
|
||||
|
||||
// Luma for edge detection (using green channel approximation)
|
||||
float bL = b.g + 0.5 * (b.r + b.b);
|
||||
float cL = c.g + 0.5 * (c.r + c.b);
|
||||
float eL = e.g + 0.5 * (e.r + e.b);
|
||||
float fL = f.g + 0.5 * (f.r + f.b);
|
||||
float gL = g.g + 0.5 * (g.r + g.b);
|
||||
float hL = h.g + 0.5 * (h.r + h.b);
|
||||
float iL = i.g + 0.5 * (i.r + i.b);
|
||||
float jL = j.g + 0.5 * (j.r + j.b);
|
||||
float kL = k.g + 0.5 * (k.r + k.b);
|
||||
float lL = l.g + 0.5 * (l.r + l.b);
|
||||
float nL = n.g + 0.5 * (n.r + n.b);
|
||||
float oL = o.g + 0.5 * (o.r + o.b);
|
||||
|
||||
// Gradient detection
|
||||
float dirX = (cL - bL) + (gL - fL) + (kL - jL) + (oL - nL);
|
||||
float dirY = (eL - iL) + (fL - jL) + (gL - kL) + (hL - lL);
|
||||
|
||||
// Normalize direction
|
||||
float dirR = APrxLoRcpF1(max(abs(dirX), abs(dirY)));
|
||||
dirX *= dirR;
|
||||
dirY *= dirR;
|
||||
|
||||
// Calculate stretch based on edge direction
|
||||
float len = length(vec2(dirX, dirY));
|
||||
len = len * 0.5;
|
||||
len *= len;
|
||||
float stretch = (dirX * dirX + dirY * dirY) * APrxLoRcpF1(max(abs(dirX), abs(dirY)));
|
||||
vec2 len2 = vec2(1.0 + (stretch - 1.0) * len, 1.0 - 0.5 * len);
|
||||
float lob = 0.5 + (0.25 - 0.04 - 0.5) * len;
|
||||
float clp = APrxLoRcpF1(lob);
|
||||
|
||||
// Accumulate samples
|
||||
vec3 aC = vec3(0.0);
|
||||
float aW = 0.0;
|
||||
vec2 dir = vec2(dirX, dirY);
|
||||
|
||||
FsrEasuTap(aC, aW, vec2(0.0, -1.0) - pp, dir, len2, lob, clp, b);
|
||||
FsrEasuTap(aC, aW, vec2(1.0, -1.0) - pp, dir, len2, lob, clp, c);
|
||||
FsrEasuTap(aC, aW, vec2(-1.0, 0.0) - pp, dir, len2, lob, clp, e);
|
||||
FsrEasuTap(aC, aW, vec2(0.0, 0.0) - pp, dir, len2, lob, clp, f);
|
||||
FsrEasuTap(aC, aW, vec2(1.0, 0.0) - pp, dir, len2, lob, clp, g);
|
||||
FsrEasuTap(aC, aW, vec2(2.0, 0.0) - pp, dir, len2, lob, clp, h);
|
||||
FsrEasuTap(aC, aW, vec2(-1.0, 1.0) - pp, dir, len2, lob, clp, i);
|
||||
FsrEasuTap(aC, aW, vec2(0.0, 1.0) - pp, dir, len2, lob, clp, j);
|
||||
FsrEasuTap(aC, aW, vec2(1.0, 1.0) - pp, dir, len2, lob, clp, k);
|
||||
FsrEasuTap(aC, aW, vec2(2.0, 1.0) - pp, dir, len2, lob, clp, l);
|
||||
FsrEasuTap(aC, aW, vec2(0.0, 2.0) - pp, dir, len2, lob, clp, n);
|
||||
FsrEasuTap(aC, aW, vec2(1.0, 2.0) - pp, dir, len2, lob, clp, o);
|
||||
|
||||
// Normalize
|
||||
vec3 pix = aC / aW;
|
||||
|
||||
// Clamp to neighborhood min/max to prevent ringing
|
||||
vec3 mn = min(min(min(f, g), j), k);
|
||||
vec3 mx = max(max(max(f, g), j), k);
|
||||
pix = clamp(pix, mn, mx);
|
||||
|
||||
return pix;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// Fallback for older GLSL - simple bilinear
|
||||
vec3 FsrEasuF(vec2 ip) {
|
||||
return texture(tex, ip).rgb;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void main() {
|
||||
vec3 col = FsrEasuF(texCoord);
|
||||
fragColor = vec4(col, 1.0);
|
||||
}
|
||||
19
leenkx/Shaders/fsr1_easu_pass/fsr1_easu_pass.json
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"contexts": [
|
||||
{
|
||||
"name": "fsr1_easu_pass",
|
||||
"depth_write": false,
|
||||
"compare_mode": "always",
|
||||
"cull_mode": "none",
|
||||
"links": [
|
||||
{
|
||||
"name": "screenSize",
|
||||
"link": "_screenSize"
|
||||
}
|
||||
],
|
||||
"texture_params": [],
|
||||
"vertex_shader": "../include/pass.vert.glsl",
|
||||
"fragment_shader": "fsr1_easu_pass.frag.glsl"
|
||||
}
|
||||
]
|
||||
}
|
||||
9
leenkx/Shaders/fsr1_rcas_pass/LICENSE.txt
Normal file
@ -0,0 +1,9 @@
|
||||
https://gpuopen.com/manuals/fidelityfx_sdk/license/
|
||||
|
||||
Copyright © 2024 Advanced Micro Devices, Inc.
|
||||
|
||||
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.
|
||||
116
leenkx/Shaders/fsr1_rcas_pass/fsr1_rcas_pass.frag.glsl
Normal file
@ -0,0 +1,116 @@
|
||||
#version 450
|
||||
|
||||
// AMD FidelityFX Super Resolution 1.0.2 - RCAS (Robust Contrast Adaptive Sharpening)
|
||||
|
||||
#include "compiled.inc"
|
||||
|
||||
uniform sampler2D tex;
|
||||
|
||||
// Sharpness in "stops": 0.0 = maximum sharpness, higher = less sharp
|
||||
// Converted to linear via exp2(-sharpness)
|
||||
#ifdef _FSR1_Ultra_Quality
|
||||
const float SHARPNESS_STOPS = 0.0;
|
||||
#elif defined(_FSR1_Balanced)
|
||||
const float SHARPNESS_STOPS = 1.0;
|
||||
#elif defined(_FSR1_Performance)
|
||||
const float SHARPNESS_STOPS = 2.0;
|
||||
#elif defined(_FSR1_Custom)
|
||||
uniform vec4 PPComp15;
|
||||
#define SHARPNESS_STOPS (PPComp15.x * 2.0)
|
||||
#else
|
||||
const float SHARPNESS_STOPS = 0.5; // Quality (default)
|
||||
#endif
|
||||
|
||||
// FSR RCAS limit - prevents unnatural sharpening artifacts
|
||||
#define FSR_RCAS_LIMIT (0.25 - (1.0 / 16.0))
|
||||
|
||||
in vec2 texCoord;
|
||||
out vec4 fragColor;
|
||||
|
||||
// AMD helper functions from ffx_a.h
|
||||
float AMin3F1(float x, float y, float z) { return min(x, min(y, z)); }
|
||||
float AMax3F1(float x, float y, float z) { return max(x, max(y, z)); }
|
||||
|
||||
// High precision reciprocal (required for limiters per AMD docs)
|
||||
// Added epsilon to prevent division by zero in dark areas
|
||||
float ARcpF1(float a) {
|
||||
return 1.0 / max(a, 1e-8);
|
||||
}
|
||||
|
||||
// Medium precision reciprocal approximation (from AMD ffx_a.h)
|
||||
// Only used for noise detection and final resolve
|
||||
float APrxMedRcpF1(float a) {
|
||||
return uintBitsToFloat(uint(0x7ef19fff) - floatBitsToUint(a));
|
||||
}
|
||||
|
||||
void main() {
|
||||
// Get texture size and texel offset
|
||||
vec2 texSize = vec2(textureSize(tex, 0));
|
||||
vec2 texelSize = 1.0 / texSize;
|
||||
|
||||
// Algorithm uses minimal 3x3 pixel neighborhood
|
||||
// b
|
||||
// d e f
|
||||
// h
|
||||
// Clamp inputs to [0,1] - FSR expects sRGB normalized input
|
||||
vec3 b = clamp(texture(tex, texCoord + vec2(0.0, -texelSize.y)).rgb, 0.0, 1.0);
|
||||
vec3 d = clamp(texture(tex, texCoord + vec2(-texelSize.x, 0.0)).rgb, 0.0, 1.0);
|
||||
vec4 ee = texture(tex, texCoord);
|
||||
vec3 e = clamp(ee.rgb, 0.0, 1.0);
|
||||
vec3 f = clamp(texture(tex, texCoord + vec2(texelSize.x, 0.0)).rgb, 0.0, 1.0);
|
||||
vec3 h = clamp(texture(tex, texCoord + vec2(0.0, texelSize.y)).rgb, 0.0, 1.0);
|
||||
|
||||
// Luma times 2 (AMD's luma calculation: B*0.5 + R*0.5 + G)
|
||||
float bL = b.b * 0.5 + (b.r * 0.5 + b.g);
|
||||
float dL = d.b * 0.5 + (d.r * 0.5 + d.g);
|
||||
float eL = e.b * 0.5 + (e.r * 0.5 + e.g);
|
||||
float fL = f.b * 0.5 + (f.r * 0.5 + f.g);
|
||||
float hL = h.b * 0.5 + (h.r * 0.5 + h.g);
|
||||
|
||||
// Noise detection (official AMD algorithm with safety for flat areas)
|
||||
float nz = 0.25 * bL + 0.25 * dL + 0.25 * fL + 0.25 * hL - eL;
|
||||
float range = AMax3F1(AMax3F1(bL, dL, eL), fL, hL) - AMin3F1(AMin3F1(bL, dL, eL), fL, hL);
|
||||
// Use safe division instead of APrxMedRcpF1 for range to avoid NaN in flat areas
|
||||
nz = clamp(abs(nz) / max(range, 1e-5), 0.0, 1.0);
|
||||
nz = -0.5 * nz + 1.0;
|
||||
|
||||
// Min and max of ring (per channel)
|
||||
float mn4R = min(AMin3F1(b.r, d.r, f.r), h.r);
|
||||
float mn4G = min(AMin3F1(b.g, d.g, f.g), h.g);
|
||||
float mn4B = min(AMin3F1(b.b, d.b, f.b), h.b);
|
||||
float mx4R = max(AMax3F1(b.r, d.r, f.r), h.r);
|
||||
float mx4G = max(AMax3F1(b.g, d.g, f.g), h.g);
|
||||
float mx4B = max(AMax3F1(b.b, d.b, f.b), h.b);
|
||||
|
||||
// Immediate constants for peak range
|
||||
vec2 peakC = vec2(1.0, -4.0);
|
||||
|
||||
// Limiters - these need HIGH PRECISION reciprocals (per AMD docs)
|
||||
float hitMinR = min(mn4R, e.r) * ARcpF1(4.0 * mx4R);
|
||||
float hitMinG = min(mn4G, e.g) * ARcpF1(4.0 * mx4G);
|
||||
float hitMinB = min(mn4B, e.b) * ARcpF1(4.0 * mx4B);
|
||||
float hitMaxR = (peakC.x - max(mx4R, e.r)) * ARcpF1(4.0 * mn4R + peakC.y);
|
||||
float hitMaxG = (peakC.x - max(mx4G, e.g)) * ARcpF1(4.0 * mn4G + peakC.y);
|
||||
float hitMaxB = (peakC.x - max(mx4B, e.b)) * ARcpF1(4.0 * mn4B + peakC.y);
|
||||
float lobeR = max(-hitMinR, hitMaxR);
|
||||
float lobeG = max(-hitMinG, hitMaxG);
|
||||
float lobeB = max(-hitMinB, hitMaxB);
|
||||
|
||||
// Apply sharpness (convert from stops to linear)
|
||||
float sharpness = exp2(-SHARPNESS_STOPS);
|
||||
float lobe = max(-FSR_RCAS_LIMIT, min(AMax3F1(lobeR, lobeG, lobeB), 0.0)) * sharpness;
|
||||
|
||||
// Apply noise removal
|
||||
lobe *= nz;
|
||||
|
||||
// Resolve using safe reciprocal to avoid any edge case issues
|
||||
float denom = 4.0 * lobe + 1.0;
|
||||
float rcpL = 1.0 / max(denom, 0.25); // denom should be in [0.25, 1.0] range
|
||||
vec3 pix;
|
||||
pix.r = (lobe * b.r + lobe * d.r + lobe * h.r + lobe * f.r + e.r) * rcpL;
|
||||
pix.g = (lobe * b.g + lobe * d.g + lobe * h.g + lobe * f.g + e.g) * rcpL;
|
||||
pix.b = (lobe * b.b + lobe * d.b + lobe * h.b + lobe * f.b + e.b) * rcpL;
|
||||
|
||||
// Ensure output is clamped to valid range
|
||||
fragColor = vec4(clamp(pix, 0.0, 1.0), ee.a);
|
||||
}
|
||||
24
leenkx/Shaders/fsr1_rcas_pass/fsr1_rcas_pass.json
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"contexts": [
|
||||
{
|
||||
"name": "fsr1_rcas_pass",
|
||||
"depth_write": false,
|
||||
"compare_mode": "always",
|
||||
"cull_mode": "none",
|
||||
"links": [
|
||||
{
|
||||
"name": "screenSize",
|
||||
"link": "_screenSize"
|
||||
},
|
||||
{
|
||||
"name": "PPComp15",
|
||||
"link": "_PPComp15",
|
||||
"ifdef": ["_FSR1_Custom"]
|
||||
}
|
||||
],
|
||||
"texture_params": [],
|
||||
"vertex_shader": "../include/pass.vert.glsl",
|
||||
"fragment_shader": "fsr1_rcas_pass.frag.glsl"
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -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"
|
||||
|
||||
@ -8,6 +8,7 @@ uniform sampler2D gbufferD;
|
||||
uniform sampler2D gbuffer0;
|
||||
uniform sampler2D gbuffer1;
|
||||
uniform mat4 invVP;
|
||||
uniform mat4 invW;
|
||||
uniform vec3 probep;
|
||||
uniform vec3 eye;
|
||||
|
||||
@ -25,19 +26,27 @@ void main() {
|
||||
|
||||
float roughness = g0.b;
|
||||
if (roughness > 0.95) {
|
||||
fragColor.rgb = vec3(0.0);
|
||||
fragColor = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
float spec = fract(textureLod(gbuffer1, texCoord, 0.0).a);
|
||||
if (spec == 0.0) {
|
||||
fragColor.rgb = vec3(0.0);
|
||||
fragColor = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
float depth = textureLod(gbufferD, texCoord, 0.0).r * 2.0 - 1.0;
|
||||
vec3 wp = getPos2(invVP, depth, texCoord);
|
||||
|
||||
vec3 localPos = (invW * vec4(wp, 1.0)).xyz;
|
||||
|
||||
// return if surface is inside probe volume bounds
|
||||
if (abs(localPos.x) > 1.0 || abs(localPos.y) > 1.0 || abs(localPos.z) > 1.0) {
|
||||
fragColor = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
vec2 enc = g0.rg;
|
||||
vec3 n;
|
||||
n.z = 1.0 - abs(enc.x) - abs(enc.y);
|
||||
@ -50,5 +59,5 @@ void main() {
|
||||
r.y = -r.y;
|
||||
#endif
|
||||
float intensity = clamp((1.0 - roughness) * dot(wp - probep, n), 0.0, 1.0);
|
||||
fragColor.rgb = texture(probeTex, r).rgb * intensity;
|
||||
fragColor = vec4(texture(probeTex, r).rgb * intensity, 1.0);
|
||||
}
|
||||
|
||||
@ -20,6 +20,10 @@
|
||||
"name": "invVP",
|
||||
"link": "_inverseViewProjectionMatrix"
|
||||
},
|
||||
{
|
||||
"name": "invW",
|
||||
"link": "_inverseWorldMatrix"
|
||||
},
|
||||
{
|
||||
"name": "probep",
|
||||
"link": "_probePosition"
|
||||
|
||||
@ -25,13 +25,13 @@ void main() {
|
||||
|
||||
float roughness = g0.b;
|
||||
if (roughness > 0.95) {
|
||||
fragColor.rgb = vec3(0.0);
|
||||
fragColor = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
float spec = fract(textureLod(gbuffer1, texCoord, 0.0).a);
|
||||
if (spec == 0.0) {
|
||||
fragColor.rgb = vec3(0.0);
|
||||
fragColor = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -50,5 +50,5 @@ void main() {
|
||||
n = normalize(n);
|
||||
|
||||
float intensity = clamp((1.0 - roughness) * dot(n, proben), 0.0, 1.0);
|
||||
fragColor.rgb = texture(probeTex, tc).rgb * intensity;
|
||||
fragColor = vec4(texture(probeTex, tc).rgb * intensity, 1.0);
|
||||
}
|
||||
|
||||
@ -5,42 +5,56 @@
|
||||
|
||||
uniform sampler2D tex;
|
||||
uniform sampler2D gbuffer0;
|
||||
uniform sampler2D gbufferD;
|
||||
|
||||
uniform vec2 dirInv; // texStep
|
||||
|
||||
in vec2 texCoord;
|
||||
out float fragColor;
|
||||
out vec3 fragColor;
|
||||
|
||||
const float blurWeights[5] = float[] (0.227027, 0.1945946, 0.1216216, 0.054054, 0.016216);
|
||||
// const float blurWeights[10] = float[] (0.132572, 0.125472, 0.106373, 0.08078, 0.05495, 0.033482, 0.018275, 0.008934, 0.003912, 0.001535);
|
||||
const float discardThreshold = 0.95;
|
||||
|
||||
float doBlur(const float blurWeight, const int pos, const vec3 nor, const vec2 texCoord) {
|
||||
const float posadd = pos + 0.5;
|
||||
|
||||
vec3 nor2 = getNor(textureLod(gbuffer0, texCoord + pos * dirInv, 0.0).rg);
|
||||
float influenceFactor = step(discardThreshold, dot(nor2, nor));
|
||||
float col = textureLod(tex, texCoord + posadd * dirInv, 0.0).r;
|
||||
fragColor += col * blurWeight * influenceFactor;
|
||||
float weight = blurWeight * influenceFactor;
|
||||
|
||||
nor2 = getNor(textureLod(gbuffer0, texCoord - pos * dirInv, 0.0).rg);
|
||||
influenceFactor = step(discardThreshold, dot(nor2, nor));
|
||||
col = textureLod(tex, texCoord - posadd * dirInv, 0.0).r;
|
||||
fragColor += col * blurWeight * influenceFactor;
|
||||
weight += blurWeight * influenceFactor;
|
||||
|
||||
return weight;
|
||||
}
|
||||
const int KERNEL_SIZE = 13;
|
||||
const float blurWeights[13] = float[](0.1, 0.09, 0.08, 0.07, 0.06, 0.05, 0.04, 0.03, 0.025, 0.02, 0.015, 0.01, 0.005);
|
||||
|
||||
void main() {
|
||||
vec3 nor = getNor(textureLod(gbuffer0, texCoord, 0.0).rg);
|
||||
vec3 centerNor = getNor(textureLod(gbuffer0, texCoord, 0.0).rg);
|
||||
float centerDepth = textureLod(gbufferD, texCoord, 0.0).r;
|
||||
|
||||
fragColor = textureLod(tex, texCoord, 0.0).r * blurWeights[0];
|
||||
float weight = blurWeights[0];
|
||||
for (int i = 1; i < 5; i++) {
|
||||
weight += doBlur(blurWeights[i], i, nor, texCoord);
|
||||
// skip sky pixels
|
||||
if (centerDepth == 1.0) {
|
||||
fragColor = vec3(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
fragColor = textureLod(tex, texCoord, 0.0).rgb * blurWeights[0];
|
||||
float totalWeight = blurWeights[0];
|
||||
|
||||
for (int i = 1; i < KERNEL_SIZE; i++) {
|
||||
vec2 offset = float(i) * dirInv;
|
||||
|
||||
vec2 uvPos = texCoord + offset;
|
||||
vec3 norPos = getNor(textureLod(gbuffer0, uvPos, 0.0).rg);
|
||||
float depthPos = textureLod(gbufferD, uvPos, 0.0).r;
|
||||
|
||||
float normalWeight = max(0.0, dot(norPos, centerNor));
|
||||
normalWeight = pow(normalWeight, 8.0); // Softer normal falloff for better blending
|
||||
float depthWeight = 1.0 - smoothstep(0.0, 0.02, abs(depthPos - centerDepth));
|
||||
float w = blurWeights[i] * normalWeight * depthWeight;
|
||||
|
||||
fragColor += textureLod(tex, uvPos, 0.0).rgb * w;
|
||||
totalWeight += w;
|
||||
|
||||
vec2 uvNeg = texCoord - offset;
|
||||
vec3 norNeg = getNor(textureLod(gbuffer0, uvNeg, 0.0).rg);
|
||||
float depthNeg = textureLod(gbufferD, uvNeg, 0.0).r;
|
||||
|
||||
normalWeight = max(0.0, dot(norNeg, centerNor));
|
||||
normalWeight = pow(normalWeight, 8.0);
|
||||
depthWeight = 1.0 - smoothstep(0.0, 0.02, abs(depthNeg - centerDepth));
|
||||
w = blurWeights[i] * normalWeight * depthWeight;
|
||||
|
||||
fragColor += textureLod(tex, uvNeg, 0.0).rgb * w;
|
||||
totalWeight += w;
|
||||
}
|
||||
|
||||
fragColor = fragColor / weight;
|
||||
fragColor /= totalWeight;
|
||||
}
|
||||
@ -4,37 +4,34 @@
|
||||
#include "std/math.glsl"
|
||||
#include "std/gbuffer.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;
|
||||
|
||||
uniform vec2 cameraProj;
|
||||
|
||||
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;
|
||||
#ifdef _EmissionShaded
|
||||
uniform sampler2D gbufferEmission;
|
||||
#endif
|
||||
|
||||
uniform mat4 P;
|
||||
uniform mat4 invP;
|
||||
uniform mat3 V3;
|
||||
|
||||
#ifdef _Sun
|
||||
uniform vec3 sunDir;
|
||||
uniform vec3 sunCol;
|
||||
#endif
|
||||
|
||||
#ifdef _CPostprocess
|
||||
uniform vec3 PPComp12;
|
||||
#endif
|
||||
|
||||
in vec3 viewRay;
|
||||
in vec2 texCoord;
|
||||
out float fragColor;
|
||||
out vec4 fragColor;
|
||||
|
||||
vec3 hitCoord;
|
||||
vec2 coord;
|
||||
float depth;
|
||||
// #ifdef _RTGI
|
||||
// vec3 col = vec3(0.0);
|
||||
// #endif
|
||||
vec3 vpos;
|
||||
const float GOLDEN_ANGLE = 2.39996323;
|
||||
const int RAY_STEPS = 12;
|
||||
|
||||
vec2 getProjectedCoord(vec3 hitCoord) {
|
||||
vec4 projectedCoord = P * vec4(hitCoord, 1.0);
|
||||
vec2 getProjectedCoord(const vec3 viewPos) {
|
||||
vec4 projectedCoord = P * vec4(viewPos, 1.0);
|
||||
projectedCoord.xy /= projectedCoord.w;
|
||||
projectedCoord.xy = projectedCoord.xy * 0.5 + 0.5;
|
||||
#ifdef _InvY
|
||||
@ -43,65 +40,149 @@ vec2 getProjectedCoord(vec3 hitCoord) {
|
||||
return projectedCoord.xy;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
vec3 cosineSampleHemisphere(vec3 n, vec2 rand) {
|
||||
float phi = PI * 2.0 * rand.x;
|
||||
float cosTheta = sqrt(1.0 - rand.y);
|
||||
float sinTheta = sqrt(rand.y);
|
||||
|
||||
vec3 h = vec3(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta);
|
||||
|
||||
vec3 tangent, bitangent;
|
||||
vec3 absN = abs(n);
|
||||
|
||||
if (absN.x <= absN.y && absN.x <= absN.z) {
|
||||
tangent = normalize(cross(n, vec3(1.0, 0.0, 0.0)));
|
||||
} else if (absN.y <= absN.z) {
|
||||
tangent = normalize(cross(n, vec3(0.0, 1.0, 0.0)));
|
||||
} else {
|
||||
tangent = normalize(cross(n, vec3(0.0, 0.0, 1.0)));
|
||||
}
|
||||
fragColor += dist;
|
||||
// #ifdef _RTGI
|
||||
// col += textureLod(gbuffer1, coord, 0.0).rgb * ((ssgiRayStep * ssgiMaxSteps) - dist);
|
||||
// #endif
|
||||
bitangent = cross(n, tangent);
|
||||
|
||||
return normalize(tangent * h.x + bitangent * h.y + n * h.z);
|
||||
}
|
||||
|
||||
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 traceRay(vec3 origin, vec3 dir, float maxDist, float minDist) {
|
||||
float stepSize = maxDist / float(RAY_STEPS);
|
||||
vec3 pos = origin + dir * minDist;
|
||||
|
||||
float prevDepthDiff = 0.0;
|
||||
float hadValidPrev = 0.0;
|
||||
|
||||
for (int i = 1; i <= RAY_STEPS; i++) {
|
||||
pos += dir * stepSize;
|
||||
vec2 uv = getProjectedCoord(pos);
|
||||
|
||||
vec2 sampleUV = clamp(uv, vec2(0.001), vec2(0.999));
|
||||
|
||||
float sampleDepth = textureLod(gbufferD, sampleUV, 0.0).r * 2.0 - 1.0;
|
||||
if (sampleDepth == 1.0) {
|
||||
hadValidPrev = 0.0;
|
||||
continue;
|
||||
}
|
||||
|
||||
vec3 sampleViewPos = getPosView2(invP, sampleDepth, sampleUV);
|
||||
float depthDiff = pos.z - sampleViewPos.z;
|
||||
float rayDist = length(pos - origin);
|
||||
float thickness = 0.15 + rayDist * 0.25;
|
||||
|
||||
float crossed = hadValidPrev * step(0.0, prevDepthDiff) * step(depthDiff, 0.0);
|
||||
float withinThickness = step(abs(depthDiff), thickness);
|
||||
|
||||
if (crossed > 0.5 || withinThickness > 0.5) {
|
||||
float distWeight = 1.0 - (rayDist / maxDist);
|
||||
distWeight = max(0.0, distWeight * distWeight);
|
||||
|
||||
return vec3(sampleUV, distWeight);
|
||||
}
|
||||
|
||||
prevDepthDiff = depthDiff;
|
||||
hadValidPrev = 1.0;
|
||||
}
|
||||
|
||||
return vec3(-1.0);
|
||||
}
|
||||
|
||||
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 * 2.0 - 1.0;
|
||||
if (depth == 1.0) {
|
||||
fragColor = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
return;
|
||||
}
|
||||
|
||||
vec4 g0 = textureLod(gbuffer0, texCoord, 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);
|
||||
n = normalize(V3 * n);
|
||||
n = normalize(n);
|
||||
|
||||
vpos = getPosView(viewRay, d, cameraProj);
|
||||
vec3 viewNormal = V3 * n;
|
||||
vec3 viewPos = getPosView2(invP, depth, texCoord);
|
||||
|
||||
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));
|
||||
|
||||
#ifdef _SSGICone9
|
||||
rayCast(mix(n, -o1, angleMix));
|
||||
rayCast(mix(n, -o2, angleMix));
|
||||
rayCast(mix(n, c1, angleMix));
|
||||
rayCast(mix(n, c2, angleMix));
|
||||
#ifdef _CPostprocess
|
||||
float radius = PPComp12.y;
|
||||
float strength = PPComp12.x;
|
||||
#else
|
||||
float radius = ssgiRadius;
|
||||
float strength = ssgiStrength;
|
||||
#endif
|
||||
|
||||
float noise = fract(52.9829189 * fract(0.06711056 * texCoord.x * 1000.0 + 0.00583715 * texCoord.y * 1000.0));
|
||||
|
||||
vec3 gi = vec3(0.0);
|
||||
int validSamples = 0;
|
||||
|
||||
// min distance to avoid self shadowing artiffacts
|
||||
float minDist = radius * 0.05;
|
||||
|
||||
for (int i = 0; i < ssgiSamples; i++) {
|
||||
float fi = float(i) + noise;
|
||||
vec2 rand = vec2(
|
||||
fract(fi * 0.7548776662 + noise),
|
||||
fract(fi * 0.5698402909 + noise * 1.5)
|
||||
);
|
||||
|
||||
vec3 rayDir = cosineSampleHemisphere(viewNormal, rand);
|
||||
vec3 hitResult = traceRay(viewPos, rayDir, radius, minDist);
|
||||
|
||||
if (hitResult.x < 0.0) continue;
|
||||
|
||||
vec2 hitUV = hitResult.xy;
|
||||
float distWeight = hitResult.z;
|
||||
|
||||
vec3 hitAlbedo = textureLod(gbuffer1, hitUV, 1.0).rgb;
|
||||
|
||||
#ifdef _Sun
|
||||
vec4 hitG0 = textureLod(gbuffer0, hitUV, 0.0);
|
||||
vec2 hitEnc = hitG0.rg;
|
||||
vec3 hitN;
|
||||
hitN.z = 1.0 - abs(hitEnc.x) - abs(hitEnc.y);
|
||||
hitN.xy = hitN.z >= 0.0 ? hitEnc.xy : octahedronWrap(hitEnc.xy);
|
||||
hitN = normalize(hitN);
|
||||
float hitNdotL = max(0.0, dot(hitN, sunDir));
|
||||
vec3 hitRadiance = hitAlbedo * sunCol * hitNdotL;
|
||||
#else
|
||||
vec3 hitRadiance = hitAlbedo * 0.5;
|
||||
#endif
|
||||
|
||||
#ifdef _EmissionShaded
|
||||
hitRadiance += textureLod(gbufferEmission, hitUV, 0.0).rgb;
|
||||
#endif
|
||||
|
||||
gi += hitRadiance * distWeight;
|
||||
validSamples++;
|
||||
}
|
||||
|
||||
if (validSamples > 0) {
|
||||
gi /= float(validSamples);
|
||||
}
|
||||
|
||||
gi *= strength;
|
||||
|
||||
#ifdef _EmissionShaded
|
||||
gi += textureLod(gbufferEmission, texCoord, 0.0).rgb * 0.3;
|
||||
#endif
|
||||
|
||||
fragColor = vec4(min(gi, vec3(2.0)), 1.0);
|
||||
}
|
||||
|
||||
@ -10,21 +10,32 @@
|
||||
"name": "P",
|
||||
"link": "_projectionMatrix"
|
||||
},
|
||||
{
|
||||
"name": "V3",
|
||||
"link": "_viewMatrix3"
|
||||
},
|
||||
{
|
||||
"name": "invP",
|
||||
"link": "_inverseProjectionMatrix"
|
||||
},
|
||||
{
|
||||
"name": "cameraProj",
|
||||
"link": "_cameraPlaneProj"
|
||||
"name": "V3",
|
||||
"link": "_viewMatrix3"
|
||||
},
|
||||
{
|
||||
"name": "sunDir",
|
||||
"link": "_sunDirection",
|
||||
"ifdef": ["_Sun"]
|
||||
},
|
||||
{
|
||||
"name": "sunCol",
|
||||
"link": "_sunColor",
|
||||
"ifdef": ["_Sun"]
|
||||
},
|
||||
{
|
||||
"name": "PPComp12",
|
||||
"link": "_PPComp12",
|
||||
"ifdef": ["_CPostprocess"]
|
||||
}
|
||||
],
|
||||
"texture_params": [],
|
||||
"vertex_shader": "../include/pass_viewray2.vert.glsl",
|
||||
"vertex_shader": "../include/pass.vert.glsl",
|
||||
"fragment_shader": "ssgi_pass.frag.glsl"
|
||||
}
|
||||
]
|
||||
|
||||
@ -64,20 +64,26 @@ vec4 rayCast(vec3 dir) {
|
||||
ddepth = getDeltaDepth(hitCoord);
|
||||
if (ddepth > 0.0) return binarySearch(dir);
|
||||
}
|
||||
return vec4(texCoord, 0.0, 1.0);
|
||||
return vec4(texCoord, 0.0, 0.0);
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec4 g0 = textureLod(gbuffer0, texCoord, 0.0);
|
||||
float roughness = g0.z;
|
||||
vec4 gr = textureLod(gbuffer_refraction, texCoord, 0.0);
|
||||
float ior = gr.x;
|
||||
float opac = 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;
|
||||
float transmittance = gr.y;
|
||||
float surfaceDepth = gr.z;
|
||||
float d = surfaceDepth * 2.0 - 1.0;
|
||||
|
||||
vec4 sceneSample = textureLod(tex, texCoord, 0.0);
|
||||
if (surfaceDepth == 0.0 || transmittance == 0.0 || ior == 1.0) {
|
||||
vec3 background = textureLod(tex1, texCoord, 0.0).rgb;
|
||||
fragColor.rgb = sceneSample.rgb + background * (1.0 - sceneSample.a);
|
||||
fragColor.a = 1.0;
|
||||
return;
|
||||
}
|
||||
|
||||
vec4 g0 = textureLod(gbuffer0, texCoord, 0.0);
|
||||
float roughness = g0.z;
|
||||
vec2 enc = g0.rg;
|
||||
vec3 n;
|
||||
n.z = 1.0 - abs(enc.x) - abs(enc.y);
|
||||
@ -86,21 +92,32 @@ void main() {
|
||||
|
||||
vec3 viewNormal = V3 * n;
|
||||
vec3 viewPos = getPosView(viewRay, d, cameraProj);
|
||||
vec3 refracted = refract(viewPos, viewNormal, 1.0 / ior);
|
||||
vec3 incident = normalize(viewPos);
|
||||
vec3 refracted = refract(incident, viewNormal, 1.0 / ior);
|
||||
if (length(refracted) < 0.001) {
|
||||
vec3 background = textureLod(tex1, texCoord, 0.0).rgb;
|
||||
fragColor.rgb = sceneSample.rgb + background * (1.0 - sceneSample.a);
|
||||
fragColor.a = 1.0;
|
||||
return;
|
||||
}
|
||||
|
||||
hitCoord = viewPos;
|
||||
|
||||
vec3 dir = refracted * (1.0 - rand(texCoord) * ss_refractionJitter * roughness) * 2.0;
|
||||
vec4 coords = rayCast(dir);
|
||||
vec2 deltaCoords = abs(vec2(0.5, 0.5) - coords.xy);
|
||||
float screenEdgeFactor = clamp(1.0 - (deltaCoords.x + deltaCoords.y), 0.0, 1.0);
|
||||
|
||||
vec2 screenEdge = smoothstep(0.0, 0.1, coords.xy) * smoothstep(0.0, 0.1, 1.0 - coords.xy);
|
||||
float screenEdgeFactor = screenEdge.x * screenEdge.y;
|
||||
float refractivity = 1.0 - roughness;
|
||||
float intensity = pow(refractivity, ss_refractionFalloffExp) * screenEdgeFactor * \
|
||||
clamp(-refracted.z, 0.0, 1.0) * clamp((length(viewPos - hitCoord)), 0.0, 1.0) * coords.w;
|
||||
|
||||
float intensity = pow(refractivity, ss_refractionFalloffExp) * screenEdgeFactor * 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;
|
||||
|
||||
fragColor.rgb = mix(refractionCol, color, opac);
|
||||
vec3 refractedBackground = textureLod(tex1, coords.xy, 0.0).rgb;
|
||||
vec3 straightBackground = textureLod(tex1, texCoord, 0.0).rgb;
|
||||
|
||||
vec3 behindColor = mix(straightBackground, refractedBackground, intensity);
|
||||
|
||||
fragColor.rgb = sceneSample.rgb + behindColor * (1.0 - sceneSample.a);
|
||||
fragColor.a = 1.0;
|
||||
}
|
||||
|
||||
@ -5,6 +5,9 @@
|
||||
"depth_write": false,
|
||||
"compare_mode": "always",
|
||||
"cull_mode": "none",
|
||||
"blend_source": "blend_one",
|
||||
"blend_destination": "blend_zero",
|
||||
"blend_operation": "add",
|
||||
"links": [
|
||||
{
|
||||
"name": "P",
|
||||
|
||||
@ -36,6 +36,7 @@
|
||||
#version 450
|
||||
|
||||
#include "compiled.inc"
|
||||
#include "std/gbuffer.glsl"
|
||||
|
||||
uniform sampler2D gbufferD;
|
||||
uniform sampler2D gbuffer0;
|
||||
@ -47,69 +48,92 @@ uniform vec2 cameraProj;
|
||||
in vec2 texCoord;
|
||||
out vec4 fragColor;
|
||||
|
||||
const float SSSS_FOVY = 108.0;
|
||||
const vec3 SKIN_SSS_RADIUS = vec3(4.8, 2.4, 1.5);
|
||||
const float SSS_DISTANCE_SCALE = 0.001;
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// Separable SSS Reflectance
|
||||
// const float sssWidth = 0.005;
|
||||
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];
|
||||
|
||||
kernel[0] = vec4(0.233, 0.455, 0.649, 0.0); // Center sample
|
||||
kernel[1] = vec4(0.100, 0.336, 0.344, 0.37); // +0.37mm
|
||||
kernel[2] = vec4(0.118, 0.198, 0.0, 0.97); // +0.97mm
|
||||
kernel[3] = vec4(0.113, 0.007, 0.007, 1.93); // +1.93mm
|
||||
kernel[4] = vec4(0.358, 0.004, 0.0, 3.87); // +3.87mm
|
||||
kernel[5] = vec4(0.078, 0.0, 0.0, 6.53); // +6.53mm (red only)
|
||||
kernel[6] = vec4(0.0, 0.0, 0.0, 0.0); // Unused
|
||||
kernel[7] = vec4(0.0, 0.0, 0.0, 0.0); // Unused
|
||||
kernel[8] = vec4(0.100, 0.336, 0.344, -0.37); // -0.37mm
|
||||
kernel[9] = vec4(0.118, 0.198, 0.0, -0.97); // -0.97mm
|
||||
kernel[10] = vec4(0.113, 0.007, 0.007, -1.93); // -1.93mm
|
||||
kernel[11] = vec4(0.358, 0.004, 0.0, -3.87); // -3.87mm
|
||||
kernel[12] = vec4(0.078, 0.0, 0.0, -6.53); // -6.53mm (red only)
|
||||
kernel[13] = vec4(0.0, 0.0, 0.0, 0.0); // Unused
|
||||
kernel[14] = vec4(0.0, 0.0, 0.0, 0.0); // Unused
|
||||
|
||||
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;
|
||||
float distanceScale = 1.0 / max(depthM, 0.1);
|
||||
|
||||
vec2 finalStep = sssWidth * distanceScale * dir * SSS_DISTANCE_SCALE;
|
||||
|
||||
|
||||
// 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;
|
||||
|
||||
finalStep *= (1.0 + jitterOffset);
|
||||
vec3 colorBlurred = vec3(0.0);
|
||||
vec3 weightSum = vec3(0.0);
|
||||
colorBlurred += colorM.rgb * kernel[0].rgb;
|
||||
weightSum += kernel[0].rgb;
|
||||
|
||||
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;
|
||||
const float DEPTH_THRESHOLD = 0.05;
|
||||
float sampleDepth = textureLod(gbufferD, offset, 0.0).r;
|
||||
float sampleDepthM = cameraProj.y / (sampleDepth - cameraProj.x);
|
||||
|
||||
float depthDiff = abs(depthM - sampleDepthM);
|
||||
float depthWeight = exp(-depthDiff * 10.0);
|
||||
|
||||
if (depthDiff > DEPTH_THRESHOLD) {
|
||||
color.rgb = mix(colorM.rgb, color.rgb, depthWeight);
|
||||
}
|
||||
|
||||
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;
|
||||
normalizedColor = max(normalizedColor + vec3(dither), vec3(0.0));
|
||||
return vec4(normalizedColor, colorM.a);
|
||||
}
|
||||
|
||||
void main() {
|
||||
if (textureLod(gbuffer0, texCoord, 0.0).a == 8192.0) {
|
||||
fragColor = clamp(SSSSBlur(), 0.0, 1.0);
|
||||
}
|
||||
else {
|
||||
vec4 g0 = textureLod(gbuffer0, texCoord, 0.0);
|
||||
float metallic;
|
||||
uint matid;
|
||||
unpackFloatInt16(g0.a, metallic, matid);
|
||||
|
||||
if (matid == 2u) {
|
||||
vec4 originalColor = textureLod(tex, texCoord, 0.0);
|
||||
vec4 blurredColor = SSSSBlur();
|
||||
vec4 sssContribution = blurredColor - originalColor;
|
||||
vec4 combined = originalColor + max(vec4(0.0), sssContribution) * 0.8;
|
||||
fragColor = max(vec4(0.0), min(combined, vec4(10.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
|
||||
@ -36,7 +36,8 @@ float d_ggx(const float nh, const float a) {
|
||||
|
||||
vec3 specularBRDF(const vec3 f0, const float roughness, const float nl, const float nh, const float nv, const float vh) {
|
||||
float a = roughness * roughness;
|
||||
return d_ggx(nh, a) * g2_approx(nl, nv, a) * f_schlick(f0, vh) / max(4.0 * nv, 1e-5); //NdotL cancels out later
|
||||
vec3 result = d_ggx(nh, a) * g2_approx(nl, nv, a) * f_schlick(f0, vh) / max(4.0 * nv, 1e-5); //NdotL cancels out later
|
||||
return min(result, vec3(200.0));
|
||||
}
|
||||
|
||||
// John Hable - Optimizing GGX Shaders
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
88
leenkx/Shaders/std/constants.glsl
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
const int DIFFUSE_CONE_COUNT = 16;
|
||||
|
||||
const float SHADOW_CONE_APERTURE = radians(15.0);
|
||||
|
||||
const float DIFFUSE_CONE_APERTURE = 0.872665;
|
||||
|
||||
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 },
|
||||
{ 9.0 / 65.0, 57.0 / 65.0, 5.0 / 65.0, 53.0 / 65.0, 12.0 / 65.0, 60.0 / 65.0, 8.0 / 65.0, 56.0 / 65.0 },
|
||||
{ 41.0 / 65.0, 25.0 / 65.0, 37.0 / 65.0, 21.0 / 65.0, 44.0 / 65.0, 28.0 / 65.0, 40.0 / 65.0, 24.0 / 65.0 },
|
||||
{ 3.0 / 65.0, 51.0 / 65.0, 15.0 / 65.0, 63.0 / 65.0, 2.0 / 65.0, 50.0 / 65.0, 14.0 / 65.0, 62.0 / 65.0 },
|
||||
{ 35.0 / 65.0, 19.0 / 65.0, 47.0 / 65.0, 31.0 / 65.0, 34.0 / 65.0, 18.0 / 65.0, 46.0 / 65.0, 30.0 / 65.0 },
|
||||
{ 11.0 / 65.0, 59.0 / 65.0, 7.0 / 65.0, 55.0 / 65.0, 10.0 / 65.0, 58.0 / 65.0, 6.0 / 65.0, 54.0 / 65.0 },
|
||||
{ 43.0 / 65.0, 27.0 / 65.0, 39.0 / 65.0, 23.0 / 65.0, 42.0 / 65.0, 26.0 / 65.0, 38.0 / 65.0, 22.0 / 65.0 }
|
||||
};
|
||||
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 }
|
||||
};
|
||||
|
||||
@ -8,10 +8,10 @@
|
||||
// const float compoDOFLength = 160.0; // Focal length in mm 18-200
|
||||
// const float compoDOFFstop = 128.0; // F-stop value
|
||||
|
||||
const int samples = 6; // Samples on the first ring
|
||||
const int samples = 8; // Samples on the first ring
|
||||
const int rings = 6; // Ring count
|
||||
const vec2 focus = vec2(0.5, 0.5);
|
||||
const float coc = 0.11; // Circle of confusion size in mm (35mm film = 0.03mm)
|
||||
const float coc = 0.03; // Circle of confusion size in mm (35mm film = 0.03mm)
|
||||
const float maxblur = 1.0;
|
||||
const float threshold = 0.5; // Highlight threshold
|
||||
const float gain = 2.0; // Highlight gain
|
||||
@ -55,21 +55,26 @@ vec3 dof(
|
||||
float f = DOFLength; // Focal length in mm
|
||||
float d = fDepth * 1000.0; // Focal plane in mm
|
||||
float o = depth * 1000.0; // Depth in mm
|
||||
float a = (o * f) / (o - f);
|
||||
float b = (d * f) / (d - f);
|
||||
float c = (d - f) / (d * DOFFStop * coc);
|
||||
float a = (o > f) ? (o * f) / (o - f) : 0.0;
|
||||
float b = (d > f) ? (d * f) / (d - f) : 0.0;
|
||||
float sensorSize = max(DOFFStop, 10.0);
|
||||
float c = (d - f) / (d * sensorSize * coc);
|
||||
|
||||
float blur = abs(a - b) * c;
|
||||
blur = clamp(blur, 0.0, 1.0);
|
||||
|
||||
vec2 noise = rand2(texCoord) * namount * blur;
|
||||
float w = (texStep.x) * blur * maxblur + noise.x;
|
||||
float h = (texStep.y) * blur * maxblur + noise.y;
|
||||
vec3 col = vec3(0.0);
|
||||
if (blur < 0.05) {
|
||||
col = textureLod(tex, texCoord, 0.0).rgb;
|
||||
}
|
||||
else {
|
||||
col = textureLod(tex, texCoord, 0.0).rgb;
|
||||
vec3 sharpCol = textureLod(tex, texCoord, 0.0).rgb;
|
||||
vec3 col = sharpCol;
|
||||
float blurThreshold = 0.02;
|
||||
float blurRange = 0.06;
|
||||
|
||||
if (blur > blurThreshold) {
|
||||
float blurAmount = smoothstep(blurThreshold, blurThreshold + blurRange, blur);
|
||||
|
||||
vec3 blurredCol = sharpCol;
|
||||
float s = 1.0;
|
||||
int ringsamples;
|
||||
|
||||
@ -81,11 +86,12 @@ vec3 dof(
|
||||
float ph = (sin(float(j) * step) * float(i));
|
||||
float p = 1.0;
|
||||
// if (pentagon) p = penta(vec2(pw, ph));
|
||||
col += color(texCoord + vec2(pw * w, ph * h), blur, tex, texStep) * mix(1.0, (float(i)) / (float(rings)), bias) * p;
|
||||
blurredCol += color(texCoord + vec2(pw * w, ph * h), blur, tex, texStep) * mix(1.0, (float(i)) / (float(rings)), bias) * p;
|
||||
s += 1.0 * mix(1.0, (float(i)) / (float(rings)), bias) * p;
|
||||
}
|
||||
}
|
||||
col /= s;
|
||||
blurredCol /= s;
|
||||
col = mix(sharpCol, blurredCol, blurAmount);
|
||||
}
|
||||
return col;
|
||||
}
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
#ifndef _GBUFFER_GLSL_
|
||||
#define _GBUFFER_GLSL_
|
||||
|
||||
vec2 octahedronWrap(const vec2 v) {
|
||||
vec2 octahedronWrap(vec2 v) {
|
||||
return (1.0 - abs(v.yx)) * (vec2(v.x >= 0.0 ? 1.0 : -1.0, v.y >= 0.0 ? 1.0 : -1.0));
|
||||
}
|
||||
|
||||
vec3 getNor(const vec2 enc) {
|
||||
vec3 getNor(vec2 enc) {
|
||||
vec3 n;
|
||||
n.z = 1.0 - abs(enc.x) - abs(enc.y);
|
||||
n.xy = n.z >= 0.0 ? enc.xy : octahedronWrap(enc.xy);
|
||||
@ -13,13 +13,13 @@ vec3 getNor(const vec2 enc) {
|
||||
return n;
|
||||
}
|
||||
|
||||
vec3 getPosView(const vec3 viewRay, const float depth, const vec2 cameraProj) {
|
||||
vec3 getPosView(vec3 viewRay, float depth, vec2 cameraProj) {
|
||||
float linearDepth = cameraProj.y / (cameraProj.x - depth);
|
||||
//float linearDepth = cameraProj.y / ((depth * 0.5 + 0.5) - cameraProj.x);
|
||||
return viewRay * linearDepth;
|
||||
}
|
||||
|
||||
vec3 getPos(const vec3 eye, const vec3 eyeLook, const vec3 viewRay, const float depth, const vec2 cameraProj) {
|
||||
vec3 getPos(vec3 eye, vec3 eyeLook, vec3 viewRay, float depth, vec2 cameraProj) {
|
||||
// eyeLook, viewRay should be normalized
|
||||
float linearDepth = cameraProj.y / ((depth * 0.5 + 0.5) - cameraProj.x);
|
||||
float viewZDist = dot(eyeLook, viewRay);
|
||||
@ -27,7 +27,7 @@ vec3 getPos(const vec3 eye, const vec3 eyeLook, const vec3 viewRay, const float
|
||||
return wposition;
|
||||
}
|
||||
|
||||
vec3 getPosNoEye(const vec3 eyeLook, const vec3 viewRay, const float depth, const vec2 cameraProj) {
|
||||
vec3 getPosNoEye(vec3 eyeLook, vec3 viewRay, float depth, vec2 cameraProj) {
|
||||
// eyeLook, viewRay should be normalized
|
||||
float linearDepth = cameraProj.y / ((depth * 0.5 + 0.5) - cameraProj.x);
|
||||
float viewZDist = dot(eyeLook, viewRay);
|
||||
@ -36,10 +36,10 @@ vec3 getPosNoEye(const vec3 eyeLook, const vec3 viewRay, const float depth, cons
|
||||
}
|
||||
|
||||
#if defined(HLSL) || defined(METAL)
|
||||
vec3 getPos2(const mat4 invVP, const float depth, vec2 coord) {
|
||||
vec3 getPos2(mat4 invVP, float depth, vec2 coord) {
|
||||
coord.y = 1.0 - coord.y;
|
||||
#else
|
||||
vec3 getPos2(const mat4 invVP, const float depth, const vec2 coord) {
|
||||
vec3 getPos2(mat4 invVP, float depth, vec2 coord) {
|
||||
#endif
|
||||
vec4 pos = vec4(coord * 2.0 - 1.0, depth, 1.0);
|
||||
pos = invVP * pos;
|
||||
@ -48,10 +48,10 @@ vec3 getPos2(const mat4 invVP, const float depth, const vec2 coord) {
|
||||
}
|
||||
|
||||
#if defined(HLSL) || defined(METAL)
|
||||
vec3 getPosView2(const mat4 invP, const float depth, vec2 coord) {
|
||||
vec3 getPosView2(mat4 invP, float depth, vec2 coord) {
|
||||
coord.y = 1.0 - coord.y;
|
||||
#else
|
||||
vec3 getPosView2(const mat4 invP, const float depth, const vec2 coord) {
|
||||
vec3 getPosView2(mat4 invP, float depth, vec2 coord) {
|
||||
#endif
|
||||
vec4 pos = vec4(coord * 2.0 - 1.0, depth, 1.0);
|
||||
pos = invP * pos;
|
||||
@ -60,10 +60,10 @@ vec3 getPosView2(const mat4 invP, const float depth, const vec2 coord) {
|
||||
}
|
||||
|
||||
#if defined(HLSL) || defined(METAL)
|
||||
vec3 getPos2NoEye(const vec3 eye, const mat4 invVP, const float depth, vec2 coord) {
|
||||
vec3 getPos2NoEye(vec3 eye, mat4 invVP, float depth, vec2 coord) {
|
||||
coord.y = 1.0 - coord.y;
|
||||
#else
|
||||
vec3 getPos2NoEye(const vec3 eye, const mat4 invVP, const float depth, const vec2 coord) {
|
||||
vec3 getPos2NoEye(vec3 eye, mat4 invVP, float depth, vec2 coord) {
|
||||
#endif
|
||||
vec4 pos = vec4(coord * 2.0 - 1.0, depth, 1.0);
|
||||
pos = invVP * pos;
|
||||
@ -71,24 +71,24 @@ vec3 getPos2NoEye(const vec3 eye, const mat4 invVP, const float depth, const vec
|
||||
return pos.xyz - eye;
|
||||
}
|
||||
|
||||
float packFloat(const float f1, const float f2) {
|
||||
float packFloat(float f1, float f2) {
|
||||
return floor(f1 * 100.0) + min(f2, 1.0 - 1.0 / 100.0);
|
||||
}
|
||||
|
||||
vec2 unpackFloat(const float f) {
|
||||
vec2 unpackFloat(float f) {
|
||||
return vec2(floor(f) / 100.0, fract(f));
|
||||
}
|
||||
|
||||
float packFloat2(const float f1, const float f2) {
|
||||
float packFloat2(float f1, float f2) {
|
||||
// Higher f1 = less precise f2
|
||||
return floor(f1 * 255.0) + min(f2, 1.0 - 1.0 / 100.0);
|
||||
}
|
||||
|
||||
vec2 unpackFloat2(const float f) {
|
||||
vec2 unpackFloat2(float f) {
|
||||
return vec2(floor(f) / 255.0, fract(f));
|
||||
}
|
||||
|
||||
vec4 encodeRGBM(const vec3 rgb) {
|
||||
vec4 encodeRGBM(vec3 rgb) {
|
||||
const float maxRange = 6.0;
|
||||
float maxRGB = max(rgb.x, max(rgb.g, rgb.b));
|
||||
float m = maxRGB / maxRange;
|
||||
@ -96,7 +96,7 @@ vec4 encodeRGBM(const vec3 rgb) {
|
||||
return vec4(rgb / (m * maxRange), m);
|
||||
}
|
||||
|
||||
vec3 decodeRGBM(const vec4 rgbm) {
|
||||
vec3 decodeRGBM(vec4 rgbm) {
|
||||
const float maxRange = 6.0;
|
||||
return rgbm.rgb * rgbm.a * maxRange;
|
||||
}
|
||||
@ -150,7 +150,7 @@ vec3 decNor(uint val) {
|
||||
/**
|
||||
Packs a float in [0, 1] and an integer in [0..15] into a single 16 bit float value.
|
||||
**/
|
||||
float packFloatInt16(const float f, const uint i) {
|
||||
float packFloatInt16(float f, uint i) {
|
||||
const uint numBitFloat = 12;
|
||||
const float maxValFloat = float((1 << numBitFloat) - 1);
|
||||
|
||||
@ -160,7 +160,7 @@ float packFloatInt16(const float f, const uint i) {
|
||||
return float(bitsInt | bitsFloat);
|
||||
}
|
||||
|
||||
void unpackFloatInt16(const float val, out float f, out uint i) {
|
||||
void unpackFloatInt16(float val, out float f, out uint i) {
|
||||
const uint numBitFloat = 12;
|
||||
const float maxValFloat = float((1 << numBitFloat) - 1);
|
||||
|
||||
|
||||
@ -1,239 +1,680 @@
|
||||
#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 *= min(lightCol, vec3(100.0));
|
||||
|
||||
#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 * 2, 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 * 2, 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 * 2, 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 * 2, 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));
|
||||
// CRITICAL: Clamp light color to prevent extreme HDR values causing white sphere artifacts
|
||||
direct *= min(lightCol, vec3(100.0));
|
||||
|
||||
#ifdef _LTC
|
||||
#ifdef _ShadowMap
|
||||
if (receiveShadow) {
|
||||
#ifdef _SinglePoint
|
||||
vec4 lPos = LWVPSpot[0] * vec4(p + n * bias * 2, 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 * 2, 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 * 2, 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 * 2, 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
|
||||
|
||||
@ -5,6 +5,7 @@ uniform vec2 morphDataDim;
|
||||
uniform vec4 morphWeights[8];
|
||||
|
||||
void getMorphedVertex(vec2 uvCoord, inout vec3 A){
|
||||
vec3 totalDelta = vec3(0.0);
|
||||
for(int i = 0; i<8; i++ )
|
||||
{
|
||||
vec4 tempCoordY = vec4( uvCoord.y - (i * 4) * morphDataDim.y,
|
||||
@ -13,21 +14,28 @@ void getMorphedVertex(vec2 uvCoord, inout vec3 A){
|
||||
uvCoord.y - (i * 4 + 3) * morphDataDim.y);
|
||||
|
||||
vec3 morph = texture(morphDataPos, vec2(uvCoord.x, tempCoordY.x)).rgb * morphScaleOffset.x + morphScaleOffset.y;
|
||||
A += morphWeights[i].x * morph;
|
||||
totalDelta += morphWeights[i].x * morph;
|
||||
|
||||
morph = texture(morphDataPos, vec2(uvCoord.x, tempCoordY.y)).rgb * morphScaleOffset.x + morphScaleOffset.y;
|
||||
A += morphWeights[i].y * morph;
|
||||
totalDelta += morphWeights[i].y * morph;
|
||||
|
||||
morph = texture(morphDataPos, vec2(uvCoord.x, tempCoordY.z)).rgb * morphScaleOffset.x + morphScaleOffset.y;
|
||||
A += morphWeights[i].z * morph;
|
||||
totalDelta += morphWeights[i].z * morph;
|
||||
|
||||
morph = texture(morphDataPos, vec2(uvCoord.x, tempCoordY.w)).rgb * morphScaleOffset.x + morphScaleOffset.y;
|
||||
A += morphWeights[i].w * morph;
|
||||
totalDelta += morphWeights[i].w * morph;
|
||||
}
|
||||
//float deltaLength = length(totalDelta);
|
||||
//if (deltaLength > 5.0) {
|
||||
// clamp corrupted data
|
||||
//totalDelta = normalize(totalDelta) * 5.0;
|
||||
//}
|
||||
A += totalDelta;
|
||||
}
|
||||
|
||||
void getMorphedNormal(vec2 uvCoord, vec3 oldNor, inout vec3 morphNor){
|
||||
|
||||
|
||||
vec3 normalDelta = vec3(0.0);
|
||||
for(int i = 0; i<8; i++ )
|
||||
{
|
||||
vec4 tempCoordY = vec4( uvCoord.y - (i * 4) * morphDataDim.y,
|
||||
@ -35,19 +43,11 @@ void getMorphedNormal(vec2 uvCoord, vec3 oldNor, inout vec3 morphNor){
|
||||
uvCoord.y - (i * 4 + 2) * morphDataDim.y,
|
||||
uvCoord.y - (i * 4 + 3) * morphDataDim.y);
|
||||
|
||||
vec3 norm = oldNor + morphWeights[i].x * (texture(morphDataNor, vec2(uvCoord.x, tempCoordY.x)).rgb * 2.0 - 1.0);
|
||||
morphNor += norm;
|
||||
|
||||
norm = oldNor + morphWeights[i].y * (texture(morphDataNor, vec2(uvCoord.x, tempCoordY.y)).rgb * 2.0 - 1.0);
|
||||
morphNor += norm;
|
||||
|
||||
norm = oldNor + morphWeights[i].z * (texture(morphDataNor, vec2(uvCoord.x, tempCoordY.z)).rgb * 2.0 - 1.0);
|
||||
morphNor += norm;
|
||||
|
||||
norm = oldNor + morphWeights[i].w * (texture(morphDataNor, vec2(uvCoord.x, tempCoordY.w)).rgb * 2.0 - 1.0);
|
||||
morphNor += norm;
|
||||
|
||||
normalDelta += morphWeights[i].x * (texture(morphDataNor, vec2(uvCoord.x, tempCoordY.x)).rgb * 2.0 - 1.0);
|
||||
normalDelta += morphWeights[i].y * (texture(morphDataNor, vec2(uvCoord.x, tempCoordY.y)).rgb * 2.0 - 1.0);
|
||||
normalDelta += morphWeights[i].z * (texture(morphDataNor, vec2(uvCoord.x, tempCoordY.z)).rgb * 2.0 - 1.0);
|
||||
normalDelta += morphWeights[i].w * (texture(morphDataNor, vec2(uvCoord.x, tempCoordY.w)).rgb * 2.0 - 1.0);
|
||||
}
|
||||
|
||||
morphNor = normalize(morphNor);
|
||||
|
||||
morphNor = normalize(oldNor + normalDelta);
|
||||
}
|
||||
1
leenkx/Shaders/std/shader_datas.lnx
Normal file
@ -0,0 +1 @@
|
||||
<EFBFBD><EFBFBD>shader_datas<EFBFBD><EFBFBD><EFBFBD>name<EFBFBD>copy_pass<EFBFBD>contexts<EFBFBD><EFBFBD><EFBFBD>name<EFBFBD>copy_pass<EFBFBD>constants<EFBFBD><EFBFBD>texture_units<EFBFBD><EFBFBD><EFBFBD>name<EFBFBD>tex<EFBFBD>vertex_elements<EFBFBD><EFBFBD><EFBFBD>data<EFBFBD>float2<EFBFBD>name<EFBFBD>pos<EFBFBD>vertex_shader<EFBFBD>pass.vert<72>fragment_shader<65>pass_copy.frag<61>depth_write¬compare_mode<64>always<79>cull_mode<64>none<6E><65>name<6D>compositor_pass<73>contexts<74><73><EFBFBD>name<6D>compositor_pass<73>constants<74><73>texture_units<74><73><EFBFBD>name<6D>tex<65>vertex_elements<74><73><EFBFBD>data<74>float2<74>name<6D>pos<6F>vertex_shader<65>compositor_pass.vert<72>fragment_shader<65>compositor_pass.frag<61>depth_write¬compare_mode<64>always<79>cull_mode<64>none<6E><65>name<6D>deferred_light<68>contexts<74><73><EFBFBD>name<6D>deferred_light<68>constants<74><73><EFBFBD>type<70>mat4<74>name<6D>invVP<56>link<6E>_inverseViewProjectionMatrix<69><78>type<70>vec3<63>name<6D>eye<79>link<6E>_cameraPosition<6F><6E>type<70>float<61>name<6D>envmapStrength<74>link<6E>_envmapStrength<74><68>type<70>floats<74>name<6D>shirr<72>link<6E>_envmapIrradiance<63><65>type<70>int<6E>name<6D>envmapNumMipmaps<70>link<6E>_envmapNumMipmaps<70><73>type<70>vec2<63>name<6D>cameraProj<6F>link<6E>_cameraPlaneProj<6F><6A>type<70>vec3<63>name<6D>eyeLook<6F>link<6E>_cameraLook<6F><6B>type<70>vec2<63>name<6D>lightProj<6F>link<6E>_lightPlaneProj<6F><6A>type<70>vec3<63>name<6D>pointPos<6F>link<6E>_pointPosition<6F><6E>type<70>vec3<63>name<6D>pointCol<6F>link<6E>_pointColor<6F><72>type<70>float<61>name<6D>pointBias<61>link<6E>_pointShadowsBias<61>texture_units<74><73><EFBFBD>name<6D>gbufferD<72><44>name<6D>gbuffer0<72><30>name<6D>gbuffer1<72><31>name<6D>senvmapBrdf<64>link<6E>$brdf.png<6E><67>name<6D>senvmapRadiance<63>link<6E>_envmapRadiance<63><65>name<6D>shadowMapPoint[0]<5D>vertex_elements<74><73><EFBFBD>data<74>float2<74>name<6D>pos<6F>vertex_shader<65>pass_viewray.vert<72>fragment_shader<65>deferred_light.frag<61>color_attachments<74><73>RGBA64<36>depth_write¬compare_mode<64>always<79>cull_mode<64>none<6E><65>name<6D>water_pass<73>contexts<74><73><EFBFBD>name<6D>water_pass<73>constants<74><73><EFBFBD>type<70>mat4<74>name<6D>invVP<56><50>type<70>vec3<63>name<6D>eye<79>link<6E>_cameraPosition<6F><6E>type<70>float<61>name<6D>time<6D>link<6E>_time<6D><65>type<70>float<61>name<6D>holoOverallStrength<74><68>type<70>vec2<63>name<6D>cameraProj<6F>link<6E>_cameraPlaneProj<6F><6A>type<70>vec3<63>name<6D>eyeLook<6F>link<6E>_cameraLook<6F><6B>type<70>vec3<63>name<6D>ld<6C>link<6E>_lightDirection<6F>texture_units<74><73><EFBFBD>name<6D>tex<65><78>name<6D>gbufferD<72><44>name<6D>gbuffer0<72>vertex_elements<74><73><EFBFBD>data<74>float2<74>name<6D>pos<6F>vertex_shader<65>pass_viewray.vert<72>fragment_shader<65>water_pass.frag<61>depth_write¬compare_mode<64>always<79>cull_mode<64>none<6E>blend_source<63>source_alpha<68>blend_destination<6F>inverse_source_alpha<68>blend_operation<6F>add<64>alpha_blend_source<63>blend_one<6E>alpha_blend_destination<6F>blend_one<6E>alpha_blend_operation<6F>add<64><64>contexts<74><73><EFBFBD>name<6D>World_World<6C>depth_write¬compare_mode<64>less<73>cull_mode<64>clockwise<73>vertex_elements<74><73><EFBFBD>name<6D>pos<6F>data<74>float3<74><33>name<6D>nor<6F>data<74>float3<74>color_attachments<74><73>_HDR<44>texture_units<74><73>constants<74><73><EFBFBD>name<6D>SMVP<56>type<70>mat4<74>link<6E>_skydomeMatrix<69>vertex_shader<65>World_World.vert<72>fragment_shader<65>World_World.frag<61>name<6D>World_World
|
||||
@ -23,6 +23,59 @@ uniform vec2 smSizeUniform;
|
||||
#endif
|
||||
|
||||
#ifdef _ShadowMapAtlas
|
||||
// PCF that clamps samples to tile boundaries to prevent bleeding
|
||||
vec3 PCFTileAware(sampler2DShadow shadowMap,
|
||||
#ifdef _ShadowMapTransparent
|
||||
sampler2D shadowMapTransparent,
|
||||
#endif
|
||||
const vec2 uv, const float compare, const vec2 smSize,
|
||||
const vec2 tileMin, const vec2 tileMax
|
||||
#ifdef _ShadowMapTransparent
|
||||
, const bool transparent
|
||||
#endif
|
||||
) {
|
||||
vec3 result = vec3(0.0);
|
||||
vec2 offset;
|
||||
|
||||
offset = vec2(-1.0, -1.0) / smSize;
|
||||
result.x = texture(shadowMap, vec3(clamp(uv + offset, tileMin, tileMax), compare));
|
||||
|
||||
offset = vec2(-1.0, 0.0) / smSize;
|
||||
result.x += texture(shadowMap, vec3(clamp(uv + offset, tileMin, tileMax), compare));
|
||||
|
||||
offset = vec2(-1.0, 1.0) / smSize;
|
||||
result.x += texture(shadowMap, vec3(clamp(uv + offset, tileMin, tileMax), compare));
|
||||
|
||||
offset = vec2(0.0, -1.0) / smSize;
|
||||
result.x += texture(shadowMap, vec3(clamp(uv + offset, tileMin, tileMax), compare));
|
||||
|
||||
result.x += texture(shadowMap, vec3(uv, compare));
|
||||
|
||||
offset = vec2(0.0, 1.0) / smSize;
|
||||
result.x += texture(shadowMap, vec3(clamp(uv + offset, tileMin, tileMax), compare));
|
||||
|
||||
offset = vec2(1.0, -1.0) / smSize;
|
||||
result.x += texture(shadowMap, vec3(clamp(uv + offset, tileMin, tileMax), compare));
|
||||
|
||||
offset = vec2(1.0, 0.0) / smSize;
|
||||
result.x += texture(shadowMap, vec3(clamp(uv + offset, tileMin, tileMax), compare));
|
||||
|
||||
offset = vec2(1.0, 1.0) / smSize;
|
||||
result.x += texture(shadowMap, vec3(clamp(uv + offset, tileMin, tileMax), 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;
|
||||
}
|
||||
|
||||
// https://www.khronos.org/registry/OpenGL/specs/gl/glspec20.pdf // p:168
|
||||
// https://www.gamedev.net/forums/topic/687535-implementing-a-cube-map-lookup-function/5337472/
|
||||
vec2 sampleCube(vec3 dir, out int faceIndex) {
|
||||
@ -58,7 +111,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 +132,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 +150,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 +177,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 +282,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);
|
||||
}
|
||||
|
||||
vec3 result = vec3(0.0);
|
||||
result.x += texture(shadowMap, vec3(uvtiled, compare));
|
||||
// soft shadowing
|
||||
@ -236,14 +319,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 +375,72 @@ 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) {
|
||||
#ifdef _ShadowMapAtlas
|
||||
uniform vec4 tileBounds;
|
||||
#endif
|
||||
|
||||
vec3 shadowTest(sampler2DShadow shadowMap,
|
||||
#ifdef _ShadowMapTransparent
|
||||
sampler2D shadowMapTransparent,
|
||||
#endif
|
||||
const vec3 lPos, const float shadowsBias
|
||||
#ifdef _ShadowMapTransparent
|
||||
, const bool transparent
|
||||
#endif
|
||||
) {
|
||||
if (lPos.x < 0.0 || lPos.y < 0.0 || lPos.x > 1.0 || lPos.y > 1.0) return vec3(1.0);
|
||||
|
||||
#ifdef _ShadowMapAtlas
|
||||
// use tile PCF
|
||||
#ifdef _SMSizeUniform
|
||||
vec2 smSizeAtlas = smSizeUniform;
|
||||
#else
|
||||
const vec2 smSizeAtlas = shadowmapSize;
|
||||
#endif
|
||||
return PCFTileAware(shadowMap,
|
||||
#ifdef _ShadowMapTransparent
|
||||
shadowMapTransparent,
|
||||
#endif
|
||||
lPos.xy, lPos.z - shadowsBias, smSizeAtlas,
|
||||
tileBounds.xy, tileBounds.zw
|
||||
#ifdef _ShadowMapTransparent
|
||||
, transparent
|
||||
#endif
|
||||
);
|
||||
#else
|
||||
// use PCF for non-atlas shadows
|
||||
#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
|
||||
);
|
||||
#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 +456,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 +483,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 +517,21 @@ 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);
|
||||
// use lPos2 coordinates for second cascade, not lPos
|
||||
if (lPos2.w > 0.0) visibility2 = PCF(shadowMap,
|
||||
#ifdef _ShadowMapTransparent
|
||||
shadowMapTransparent,
|
||||
#endif
|
||||
lPos2.xy, lPos2.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 +539,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);
|
||||
//}
|
||||
|
||||
@ -13,32 +13,80 @@ out vec4 fragColor;
|
||||
|
||||
const float SMAA_REPROJECTION_WEIGHT_SCALE = 30.0;
|
||||
|
||||
// TODO: Move to a utility
|
||||
bool isInvalidValue(float v) {
|
||||
return (v != v) || (v > 65000.0) || (v < -65000.0);
|
||||
}
|
||||
|
||||
bool hasInvalidValues(vec3 v) {
|
||||
return isInvalidValue(v.x) || isInvalidValue(v.y) || isInvalidValue(v.z);
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec4 current = textureLod(tex, texCoord, 0.0);
|
||||
|
||||
current.rgb = clamp(current.rgb, vec3(0.0), vec3(10.0));
|
||||
current.a = clamp(current.a, 0.0, 1.0);
|
||||
if (hasInvalidValues(current.rgb)) {
|
||||
current = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
|
||||
#ifdef _Veloc
|
||||
// Velocity is assumed to be calculated for motion blur, so we need to inverse it for reprojection
|
||||
vec2 velocity = -textureLod(sveloc, texCoord, 0.0).rg;
|
||||
|
||||
velocity = clamp(velocity, vec2(-1.0), vec2(1.0));
|
||||
if (isInvalidValue(velocity.x) || isInvalidValue(velocity.y)) {
|
||||
velocity = vec2(0.0);
|
||||
}
|
||||
|
||||
#ifdef _InvY
|
||||
velocity.y = -velocity.y;
|
||||
#endif
|
||||
|
||||
// Reproject current coordinates and fetch previous pixel
|
||||
vec4 previous = textureLod(tex2, texCoord + velocity, 0.0);
|
||||
vec2 prevCoord = texCoord + velocity;
|
||||
prevCoord = clamp(prevCoord, vec2(0.0), vec2(1.0));
|
||||
vec4 previous = textureLod(tex2, prevCoord, 0.0);
|
||||
|
||||
previous.rgb = clamp(previous.rgb, vec3(0.0), vec3(10.0));
|
||||
previous.a = clamp(previous.a, 0.0, 1.0);
|
||||
if (hasInvalidValues(previous.rgb)) {
|
||||
previous = current; // Fallback to current frame if previous is corrupted
|
||||
}
|
||||
|
||||
// Attenuate the previous pixel if the velocity is different
|
||||
#ifdef _SMAA
|
||||
float delta = abs(current.a * current.a - previous.a * previous.a) / 5.0;
|
||||
float currentAlpha = clamp(current.a, 0.0, 1.0);
|
||||
float previousAlpha = clamp(previous.a, 0.0, 1.0);
|
||||
float delta = abs(currentAlpha * currentAlpha - previousAlpha * previousAlpha) / 5.0;
|
||||
delta = clamp(delta, 0.0, 1.0); // Ensure delta is in valid range
|
||||
#else
|
||||
const float delta = 0.0;
|
||||
#endif
|
||||
float weight = 0.5 * clamp(1.0 - sqrt(delta) * SMAA_REPROJECTION_WEIGHT_SCALE, 0.0, 1.0);
|
||||
|
||||
float weight = 0.5 * clamp(1.0 - sqrt(max(delta, 0.0)) * SMAA_REPROJECTION_WEIGHT_SCALE, 0.0, 1.0);
|
||||
|
||||
// Blend the pixels according to the calculated weight:
|
||||
fragColor = vec4(mix(current.rgb, previous.rgb, weight), 1.0);
|
||||
vec3 blended = mix(current.rgb, previous.rgb, weight);
|
||||
blended = clamp(blended, vec3(0.0), vec3(10.0));
|
||||
if (hasInvalidValues(blended)) {
|
||||
blended = current.rgb;
|
||||
}
|
||||
|
||||
fragColor = vec4(blended, 1.0);
|
||||
#else
|
||||
vec4 previous = textureLod(tex2, texCoord, 0.0);
|
||||
fragColor = vec4(mix(current.rgb, previous.rgb, 0.5), 1.0);
|
||||
|
||||
previous.rgb = clamp(previous.rgb, vec3(0.0), vec3(10.0));
|
||||
if (hasInvalidValues(previous.rgb)) {
|
||||
previous.rgb = current.rgb;
|
||||
}
|
||||
|
||||
vec3 blended = mix(current.rgb, previous.rgb, 0.5);
|
||||
blended = clamp(blended, vec3(0.0), vec3(10.0));
|
||||
if (hasInvalidValues(blended)) {
|
||||
blended = current.rgb;
|
||||
}
|
||||
|
||||
fragColor = vec4(blended, 1.0);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -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));
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -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,39 @@ class App {
|
||||
|
||||
static function update() {
|
||||
if (Scene.active == null || !Scene.active.ready) return;
|
||||
|
||||
// VR is handling it so we prevent double updates
|
||||
// TODO: avoid js.Syntax
|
||||
#if (kha_webgl && lnx_vr)
|
||||
var vrActive = false;
|
||||
js.Syntax.code("
|
||||
if (typeof kha !== 'undefined' && kha.vr && kha.vr.VrInterface) {
|
||||
const vr = kha.vr.VrInterface.instance;
|
||||
if (vr && vr.IsPresenting && vr.IsPresenting()) {
|
||||
{0} = true;
|
||||
}
|
||||
}
|
||||
", vrActive);
|
||||
if (vrActive) return;
|
||||
#end
|
||||
|
||||
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 +93,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 +129,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);
|
||||
@ -124,6 +153,21 @@ class App {
|
||||
traitInits.splice(0, traitInits.length);
|
||||
}
|
||||
|
||||
// skip for XR callback to handle rendering
|
||||
// TODO: avoid js Syntax
|
||||
#if (kha_webgl && lnx_vr)
|
||||
var vrActive = false;
|
||||
js.Syntax.code("
|
||||
if (typeof kha !== 'undefined' && kha.vr && kha.vr.VrInterface) {
|
||||
const vr = kha.vr.VrInterface.instance;
|
||||
if (vr && vr.IsPresenting && vr.IsPresenting()) {
|
||||
{0} = true;
|
||||
}
|
||||
}
|
||||
", vrActive);
|
||||
|
||||
if (!vrActive) {
|
||||
#end
|
||||
Scene.active.renderFrame(frame.g4);
|
||||
|
||||
for (f in traitRenders) {
|
||||
@ -132,6 +176,10 @@ class App {
|
||||
|
||||
render2D(frame);
|
||||
|
||||
#if (kha_webgl && lnx_vr)
|
||||
}
|
||||
#end
|
||||
|
||||
#if lnx_debug
|
||||
renderPathTime = kha.Scheduler.realTime() - startTime;
|
||||
#end
|
||||
@ -172,6 +220,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);
|
||||
}
|
||||
|
||||
@ -18,10 +18,44 @@ import iron.object.LightObject;
|
||||
import iron.object.MeshObject;
|
||||
import iron.object.Uniforms;
|
||||
import iron.object.Clipmap;
|
||||
#if lnx_vr
|
||||
import iron.math.Vec4;
|
||||
import iron.math.Mat4;
|
||||
import iron.math.Quat;
|
||||
#end
|
||||
|
||||
class RenderPath {
|
||||
|
||||
public static var active: RenderPath;
|
||||
#if lnx_vr
|
||||
static var vrSimulateMode: Bool = false;
|
||||
static var vrCameraOffsetSet:Bool = false;
|
||||
static var vrCameraOffset:Vec4 = new Vec4();
|
||||
static var wasVRPresenting:Bool = false;
|
||||
public static var vrCalibrationPosition:Vec4 = null;
|
||||
public static var vrCalibrationRotation:iron.math.Quat = null;
|
||||
public static var vrCalibrationSaved:Bool = false;
|
||||
|
||||
public static var vrCenterCameraWorld:Mat4 = null;
|
||||
|
||||
static var vrOriginalSuperSample:Float = -1.0;
|
||||
public static inline function isVRPresenting(): Bool {
|
||||
#if (kha_webgl && lnx_vr)
|
||||
return kha.vr.VrInterface.instance != null && kha.vr.VrInterface.instance.IsPresenting();
|
||||
#else
|
||||
return false;
|
||||
#end
|
||||
}
|
||||
|
||||
public static inline function isVRSimulateMode(): Bool {
|
||||
return vrSimulateMode;
|
||||
}
|
||||
|
||||
// TODO: done remove safely
|
||||
public static inline function debugLog(msg: String, once: Bool = true): Void {
|
||||
return;
|
||||
}
|
||||
#end
|
||||
|
||||
public var frameScissor = false;
|
||||
public var frameScissorX = 0;
|
||||
@ -43,9 +77,15 @@ class RenderPath {
|
||||
public var isProbe = false;
|
||||
public var currentG: Graphics = null;
|
||||
public var frameG: Graphics;
|
||||
#if lnx_vr
|
||||
var beginCalled = false;
|
||||
var scissorSet = false;
|
||||
var viewportScaled = false;
|
||||
var renderToXRFramebuffer = false;
|
||||
#end
|
||||
public var drawOrder = DrawOrder.Distance;
|
||||
public var paused = false;
|
||||
public var ready(get, null): Bool;
|
||||
public var ready(get, never): Bool;
|
||||
function get_ready(): Bool { return loading == 0; }
|
||||
public var commands: Void->Void = null;
|
||||
public var setupDepthTexture: Void->Void = null;
|
||||
@ -123,9 +163,93 @@ class RenderPath {
|
||||
public function renderFrame(g: Graphics) {
|
||||
if (!ready || paused || iron.App.w() == 0 || iron.App.h() == 0) return;
|
||||
|
||||
if (lastW > 0 && (lastW != iron.App.w() || lastH != iron.App.h())) resize();
|
||||
lastW = iron.App.w();
|
||||
lastH = iron.App.h();
|
||||
var appW = iron.App.w();
|
||||
var appH = iron.App.h();
|
||||
|
||||
// use native XR framebuffer dimensions
|
||||
#if (kha_webgl && lnx_vr)
|
||||
if (kha.vr.VrInterface.instance != null) {
|
||||
var vr = kha.vr.VrInterface.instance;
|
||||
var isPresenting = vr != null && vr.IsPresenting();
|
||||
|
||||
// save/restore camera position between modes
|
||||
if (!wasVRPresenting && isPresenting) {
|
||||
if (Scene.active != null && Scene.active.camera != null) {
|
||||
if (vrCalibrationPosition == null) vrCalibrationPosition = new Vec4();
|
||||
if (vrCalibrationRotation == null) vrCalibrationRotation = new Quat();
|
||||
|
||||
vrCalibrationPosition.setFrom(Scene.active.camera.transform.loc);
|
||||
vrCalibrationRotation.setFrom(Scene.active.camera.transform.rot);
|
||||
vrCalibrationSaved = true;
|
||||
}
|
||||
|
||||
// save original super sampling for later
|
||||
vrOriginalSuperSample = leenkx.renderpath.Inc.superSample;
|
||||
|
||||
// compositeToXR function handles blitting to VR framebuffer
|
||||
|
||||
var xrVr: kha.js.vr.VrInterface = cast vr;
|
||||
if (xrVr.xrGLLayer != null) {
|
||||
var vrWidth = untyped xrVr.xrGLLayer.framebufferWidth;
|
||||
var vrHeight = untyped xrVr.xrGLLayer.framebufferHeight;
|
||||
}
|
||||
}
|
||||
else if (wasVRPresenting && !isPresenting) {
|
||||
// reset VR frame time before anything else
|
||||
#if (kha_webgl && lnx_vr)
|
||||
iron.system.Time.vrFrameTime = -1.0;
|
||||
#end
|
||||
|
||||
if (vrCalibrationSaved && Scene.active != null && Scene.active.camera != null) {
|
||||
Scene.active.camera.transform.loc.setFrom(vrCalibrationPosition);
|
||||
Scene.active.camera.transform.rot.setFrom(vrCalibrationRotation);
|
||||
Scene.active.camera.buildMatrix();
|
||||
Scene.active.camera.buildProjection();
|
||||
}
|
||||
|
||||
// restore original super sampling from simulate mode
|
||||
if (vrOriginalSuperSample >= 0.0) {
|
||||
leenkx.renderpath.Inc.superSample = vrOriginalSuperSample;
|
||||
|
||||
for (rt in renderTargets) {
|
||||
if (rt.raw.width == 0 && rt.raw.scale != null) {
|
||||
rt.raw.scale = vrOriginalSuperSample;
|
||||
}
|
||||
}
|
||||
resize();
|
||||
vrOriginalSuperSample = -1.0;
|
||||
}
|
||||
|
||||
// reset offset for next session
|
||||
vrCameraOffsetSet = false;
|
||||
vrCameraOffset = null;
|
||||
}
|
||||
wasVRPresenting = isPresenting;
|
||||
|
||||
if (isPresenting) {
|
||||
// TODO: re-investigate using super sampling to avoid pixelation in simulate mode while giving max quality in headset
|
||||
if (vrOriginalSuperSample >= 0.0 && leenkx.renderpath.Inc.superSample != 4.0) {
|
||||
leenkx.renderpath.Inc.superSample = 4.0;
|
||||
for (rt in renderTargets) {
|
||||
if (rt.raw.width == 0 && rt.raw.scale != null) {
|
||||
rt.raw.scale = 4.0;
|
||||
}
|
||||
}
|
||||
resize();
|
||||
}
|
||||
|
||||
var xrVr: kha.js.vr.VrInterface = cast vr;
|
||||
if (xrVr.xrGLLayer != null) {
|
||||
appW = xrVr.xrGLLayer.framebufferWidth;
|
||||
appH = xrVr.xrGLLayer.framebufferHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
#end
|
||||
|
||||
if (lastW > 0 && (lastW != appW || lastH != appH)) resize();
|
||||
lastW = appW;
|
||||
lastH = appH;
|
||||
|
||||
frameTime = Time.time() - lastFrameTime;
|
||||
lastFrameTime = Time.time();
|
||||
@ -191,7 +315,9 @@ class RenderPath {
|
||||
}
|
||||
light = Scene.active.lights[0];
|
||||
|
||||
commands();
|
||||
if (commands != null) {
|
||||
commands();
|
||||
}
|
||||
|
||||
if (!isProbe) frame++;
|
||||
}
|
||||
@ -207,13 +333,13 @@ class RenderPath {
|
||||
begin(frameG, Scene.active.camera.currentFace);
|
||||
}
|
||||
else { // Screen, planar probe
|
||||
currentW = iron.App.w();
|
||||
currentH = iron.App.h();
|
||||
currentW = kha.System.windowWidth();
|
||||
currentH = kha.System.windowHeight();
|
||||
if (frameScissor) setFrameScissor();
|
||||
begin(frameG);
|
||||
if (!isProbe) {
|
||||
setCurrentViewport(iron.App.w(), iron.App.h());
|
||||
setCurrentScissor(iron.App.w(), iron.App.h());
|
||||
setCurrentViewport(kha.System.windowWidth(), kha.System.windowHeight());
|
||||
setCurrentScissor(kha.System.windowWidth(), kha.System.windowHeight());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -258,16 +384,42 @@ class RenderPath {
|
||||
if (currentG != null) end();
|
||||
currentG = g;
|
||||
additionalTargets = additionalRenderTargets;
|
||||
face >= 0 ? g.beginFace(face) : g.begin(additionalRenderTargets);
|
||||
|
||||
// we still bind but skip begin() when explicitly rendering to XR framebuffer (renderToXRFramebuffer flag)
|
||||
#if lnx_vr
|
||||
if (!renderToXRFramebuffer) {
|
||||
face >= 0 ? g.beginFace(face) : g.begin(additionalRenderTargets);
|
||||
beginCalled = true;
|
||||
} else {
|
||||
// XR framebuffer is already bound by VrInterface so we dont rebind
|
||||
beginCalled = false;
|
||||
}
|
||||
#else
|
||||
face >= 0 ? g.beginFace(face) : g.begin(additionalRenderTargets);
|
||||
#end
|
||||
}
|
||||
|
||||
inline function end() {
|
||||
if (currentG == null) return;
|
||||
if (scissorSet) {
|
||||
currentG.disableScissor();
|
||||
scissorSet = false;
|
||||
}
|
||||
|
||||
#if lnx_vr
|
||||
if (beginCalled) {
|
||||
currentG.end();
|
||||
beginCalled = false;
|
||||
}
|
||||
// persist for rendering both eyes
|
||||
if (!isVRPresenting()) {
|
||||
currentG = null;
|
||||
additionalTargets = null;
|
||||
}
|
||||
#else
|
||||
currentG.end();
|
||||
currentG = null;
|
||||
#end
|
||||
bindParams = null;
|
||||
}
|
||||
|
||||
@ -331,14 +483,17 @@ 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;
|
||||
});
|
||||
}
|
||||
|
||||
@ -399,7 +554,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 +673,208 @@ 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
|
||||
// blits to each eyes viewport in the XR framebuffer.
|
||||
public function compositeToXR(sourceTarget: String) {
|
||||
#if (kha_webgl && lnx_vr)
|
||||
|
||||
var vr: kha.js.vr.VrInterface = cast kha.vr.VrInterface.instance;
|
||||
if (vr == null || vr._glContext == null || vr.xrGLLayer == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var gl: js.html.webgl.WebGL2RenderingContext = cast vr._glContext;
|
||||
var source = renderTargets.get(sourceTarget);
|
||||
if (source == null) {
|
||||
return;
|
||||
}
|
||||
var sourceFB: js.html.webgl.Framebuffer = untyped source.image.g4.renderTargetFrameBuffer;
|
||||
if (sourceFB == null) {
|
||||
return;
|
||||
}
|
||||
// trace('Framebuffer OK');
|
||||
|
||||
renderToXRFramebuffer = true;
|
||||
gl.bindFramebuffer(js.html.webgl.WebGL2RenderingContext.DRAW_FRAMEBUFFER, vr.xrGLLayer.framebuffer);
|
||||
gl.bindFramebuffer(js.html.webgl.WebGL2RenderingContext.READ_FRAMEBUFFER, sourceFB);
|
||||
|
||||
var readStatus = gl.checkFramebufferStatus(js.html.webgl.WebGL2RenderingContext.READ_FRAMEBUFFER);
|
||||
var drawStatus = gl.checkFramebufferStatus(js.html.webgl.WebGL2RenderingContext.DRAW_FRAMEBUFFER);
|
||||
if (readStatus != js.html.webgl.WebGL2RenderingContext.FRAMEBUFFER_COMPLETE ||
|
||||
drawStatus != js.html.webgl.WebGL2RenderingContext.FRAMEBUFFER_COMPLETE) {
|
||||
return;
|
||||
}
|
||||
|
||||
var halfWidth = Std.int(source.image.width / 2);
|
||||
var fullHeight = source.image.height;
|
||||
|
||||
if (vr._leftViewport != null) {
|
||||
var vp = vr._leftViewport;
|
||||
gl.blitFramebuffer(
|
||||
0, 0, halfWidth, fullHeight,
|
||||
vp.x, vp.y, vp.x + vp.width, vp.y + vp.height,
|
||||
js.html.webgl.WebGL2RenderingContext.COLOR_BUFFER_BIT,
|
||||
js.html.webgl.WebGL2RenderingContext.LINEAR
|
||||
);
|
||||
}
|
||||
if (vr._rightViewport != null) {
|
||||
var vp = vr._rightViewport;
|
||||
gl.blitFramebuffer(
|
||||
halfWidth, 0, source.image.width, fullHeight,
|
||||
vp.x, vp.y, vp.x + vp.width, vp.y + vp.height,
|
||||
js.html.webgl.WebGL2RenderingContext.COLOR_BUFFER_BIT,
|
||||
js.html.webgl.WebGL2RenderingContext.LINEAR
|
||||
);
|
||||
}
|
||||
|
||||
gl.bindFramebuffer(js.html.webgl.WebGL2RenderingContext.FRAMEBUFFER, null);
|
||||
renderToXRFramebuffer = false;
|
||||
#end
|
||||
}
|
||||
#end
|
||||
#if lnx_vr
|
||||
public function drawStereo(drawMeshes: Void->Void) {
|
||||
vrSimulateMode = false;
|
||||
|
||||
if (currentG == null && frameG != null) {
|
||||
currentG = frameG;
|
||||
}
|
||||
|
||||
var appw = iron.App.w();
|
||||
var apph = iron.App.h();
|
||||
var g = currentG;
|
||||
|
||||
// get render target dimensions not App.w/h gbuffer is scaled in simulate mode with supersampling
|
||||
|
||||
var gbuffer0 = renderTargets.get("gbuffer0");
|
||||
var actualWidth = (gbuffer0 != null && gbuffer0.image != null) ? gbuffer0.image.width : appw;
|
||||
var actualHeight = (gbuffer0 != null && gbuffer0.image != null) ? gbuffer0.image.height : apph;
|
||||
var actualHalfWidth = Std.int(actualWidth / 2);
|
||||
|
||||
var vrFBWidth = actualWidth;
|
||||
var vrFBHeight = actualHeight;
|
||||
var vrHalfWidth = actualHalfWidth;
|
||||
var isVRPresenting = false;
|
||||
vrSimulateMode = false;
|
||||
|
||||
var vr:Dynamic = null;
|
||||
var vrExists = false;
|
||||
#if (kha_webgl && lnx_vr)
|
||||
if (kha.vr.VrInterface.instance != null) {
|
||||
vr = kha.vr.VrInterface.instance;
|
||||
vrExists = true;
|
||||
}
|
||||
#end
|
||||
|
||||
if (vrExists && vr != null && vr.IsPresenting()) {
|
||||
vrSimulateMode = false;
|
||||
isVRPresenting = true;
|
||||
|
||||
// get framebuffer dimensions from XR layer
|
||||
#if (kha_webgl && lnx_vr)
|
||||
var xrVr: kha.js.vr.VrInterface = cast vr;
|
||||
if (xrVr.xrGLLayer != null) {
|
||||
vrFBWidth = untyped xrVr.xrGLLayer.framebufferWidth;
|
||||
vrFBHeight = untyped xrVr.xrGLLayer.framebufferHeight;
|
||||
vrHalfWidth = Std.int(vrFBWidth / 2);
|
||||
}
|
||||
#end
|
||||
|
||||
if (Scene.active == null || Scene.active.camera == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if (kha_webgl && lnx_vr)
|
||||
if (vrCenterCameraWorld == null) vrCenterCameraWorld = Mat4.identity();
|
||||
vrCenterCameraWorld.setFrom(Scene.active.camera.transform.world);
|
||||
#end
|
||||
|
||||
// LEFT EYE
|
||||
// HMD center for room scale position tracking
|
||||
#if (kha_webgl && lnx_vr)
|
||||
var xrVr: kha.js.vr.VrInterface = cast vr;
|
||||
if (xrVr.currentViewerPose != null) {
|
||||
var viewerTransform = untyped xrVr.currentViewerPose.transform;
|
||||
if (viewerTransform != null && viewerTransform.position != null) {
|
||||
// VR present calibration is used to position objects in world space not the camera
|
||||
var pos = viewerTransform.position;
|
||||
|
||||
// camera follows headset directly in local floor space
|
||||
Scene.active.camera.transform.loc.set(pos.x, pos.y, pos.z);
|
||||
|
||||
if (viewerTransform.orientation != null) {
|
||||
Scene.active.camera.transform.rot.set(
|
||||
viewerTransform.orientation.x,
|
||||
viewerTransform.orientation.y,
|
||||
viewerTransform.orientation.z,
|
||||
viewerTransform.orientation.w
|
||||
);
|
||||
}
|
||||
Scene.active.camera.transform.buildMatrix();
|
||||
}
|
||||
}
|
||||
iron.system.VRController.updatePoses();
|
||||
#end
|
||||
|
||||
Scene.active.camera.V.self = vr.GetViewMatrix(0);
|
||||
Scene.active.camera.P.self = vr.GetProjectionMatrix(0);
|
||||
Scene.active.camera.VP.setFrom(Scene.active.camera.P);
|
||||
Scene.active.camera.VP.multmat(Scene.active.camera.V);
|
||||
Scene.active.camera.buildMatrix(); // update frustum for culling
|
||||
|
||||
var renderWidth = actualWidth;
|
||||
var renderHeight = actualHeight;
|
||||
var renderHalfWidth = actualHalfWidth;
|
||||
|
||||
// left half of render target
|
||||
g.viewport(0, 0, renderHalfWidth, renderHeight);
|
||||
g.scissor(0, 0, renderHalfWidth, renderHeight);
|
||||
drawMeshes();
|
||||
|
||||
// RIGHT EYE
|
||||
Scene.active.camera.V.self = vr.GetViewMatrix(1);
|
||||
Scene.active.camera.P.self = vr.GetProjectionMatrix(1);
|
||||
Scene.active.camera.VP.setFrom(Scene.active.camera.P);
|
||||
Scene.active.camera.VP.multmat(Scene.active.camera.V);
|
||||
Scene.active.camera.buildMatrix();
|
||||
|
||||
// right half of render target
|
||||
g.viewport(renderHalfWidth, 0, renderHalfWidth, renderHeight);
|
||||
g.scissor(renderHalfWidth, 0, renderHalfWidth, renderHeight);
|
||||
drawMeshes();
|
||||
|
||||
// restore for post-processing
|
||||
g.disableScissor();
|
||||
g.viewport(0, 0, renderWidth, renderHeight);
|
||||
}
|
||||
else { // Simulate
|
||||
vrSimulateMode = true;
|
||||
var ipd_offset = 0.032 * 35.0;
|
||||
|
||||
#if (kha_webgl && lnx_vr)
|
||||
if (vrCenterCameraWorld == null) vrCenterCameraWorld = Mat4.identity();
|
||||
vrCenterCameraWorld.setFrom(Scene.active.camera.transform.world);
|
||||
#end
|
||||
|
||||
Scene.active.camera.buildProjection(actualHalfWidth / actualHeight);
|
||||
|
||||
Scene.active.camera.transform.move(Scene.active.camera.right(), -ipd_offset);
|
||||
Scene.active.camera.buildMatrix();
|
||||
g.viewport(0, 0, actualHalfWidth, actualHeight);
|
||||
g.scissor(0, 0, actualHalfWidth, actualHeight);
|
||||
drawMeshes();
|
||||
|
||||
begin(g, additionalTargets);
|
||||
Scene.active.camera.transform.move(Scene.active.camera.right(), ipd_offset * 2.0);
|
||||
Scene.active.camera.buildMatrix();
|
||||
g.viewport(actualHalfWidth, 0, actualHalfWidth, actualHeight);
|
||||
g.scissor(actualHalfWidth, 0, actualHalfWidth, actualHeight);
|
||||
drawMeshes();
|
||||
|
||||
Scene.active.camera.transform.move(Scene.active.camera.right(), -ipd_offset);
|
||||
Scene.active.camera.buildMatrix();
|
||||
g.disableScissor();
|
||||
g.viewport(0, 0, actualWidth, actualHeight);
|
||||
}
|
||||
}
|
||||
#end
|
||||
@ -882,6 +1233,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) {
|
||||
@ -944,7 +954,14 @@ class Scene {
|
||||
static function createTraitClassInstance(traitName: String, args: Array<Dynamic>): Dynamic {
|
||||
var cname = Type.resolveClass(traitName);
|
||||
if (cname == null) return null;
|
||||
return Type.createInstance(cname, args);
|
||||
var trait:Dynamic;
|
||||
try {
|
||||
trait = Type.createInstance(cname, args);
|
||||
} catch(e) {
|
||||
trace("Error creating trait: " + traitName + " - " + e);
|
||||
trait = null;
|
||||
}
|
||||
return trait;
|
||||
}
|
||||
|
||||
function loadEmbeddedData(datas: Array<String>, done: Void->Void) {
|
||||
|
||||
@ -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.
|
||||
**/
|
||||
|
||||
@ -37,7 +37,9 @@ class Armature {
|
||||
}
|
||||
|
||||
public function getAction(name: String): TAction {
|
||||
for (a in actions) if (a.name == name) return a;
|
||||
for (a in actions) {
|
||||
if (a.name == name) return a;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -141,6 +141,7 @@ class Animation {
|
||||
sampler.cacheSet = false;
|
||||
sampler.trackEnd = false;
|
||||
|
||||
if (anim == null || anim.tracks == null || anim.tracks.length == 0) return;
|
||||
var track = anim.tracks[0];
|
||||
|
||||
if (frameIndex == -1) {
|
||||
@ -159,9 +160,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,19 +420,35 @@ 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.
|
||||
*/
|
||||
public inline function setObjectAction(actionData: TObj) {
|
||||
this.actionData = [actionData];
|
||||
this.totalFrames = actionData.anim.tracks[0].frames.length;
|
||||
if (actionData != null && actionData.anim != null && actionData.anim.tracks != null && actionData.anim.tracks.length > 0) {
|
||||
this.totalFrames = actionData.anim.tracks[0].frames.length;
|
||||
}
|
||||
else {
|
||||
this.totalFrames = 0;
|
||||
}
|
||||
actionDataInit = true;
|
||||
}
|
||||
|
||||
|
||||
@ -108,9 +108,11 @@ class BoneAnimation extends Animation {
|
||||
object.transform.rot.set(0, 0, 0, 1);
|
||||
object.transform.buildMatrix();
|
||||
|
||||
var refs = mo.parent.raw.bone_actions;
|
||||
if (refs != null && refs.length > 0) {
|
||||
Data.getSceneRaw(refs[0], function(action: TSceneFormat) { play(action.name); });
|
||||
if (mo.parent != null && mo.parent.raw != null && mo.parent.raw.bone_actions != null) {
|
||||
var refs = mo.parent.raw.bone_actions;
|
||||
if (refs.length > 0) {
|
||||
Data.getSceneRaw(refs[0], function(action: TSceneFormat) { play(action.name); });
|
||||
}
|
||||
}
|
||||
}
|
||||
if (armatureObject.raw.relative_bone_constraints) relativeBoneConstraints = true;
|
||||
@ -183,8 +185,10 @@ class BoneAnimation extends Animation {
|
||||
}
|
||||
|
||||
function setAction(action: String) {
|
||||
if (armature == null) return;
|
||||
armature.initMats();
|
||||
var a = armature.getAction(action);
|
||||
if (a == null) return;
|
||||
skeletonBones = a.bones;
|
||||
skeletonMats = a.mats;
|
||||
if(! rootMotionCacheInit) skeletonMats.push(Mat4.identity());
|
||||
@ -193,8 +197,11 @@ class BoneAnimation extends Animation {
|
||||
}
|
||||
|
||||
function getAction(action: String): Array<TObj> {
|
||||
if (armature == null) return null;
|
||||
armature.initMats();
|
||||
return armature.getAction(action).bones;
|
||||
var a = armature.getAction(action);
|
||||
if (a == null) return null;
|
||||
return a.bones;
|
||||
}
|
||||
|
||||
function multParent(i: Int, fasts: Array<Mat4>, bones: Array<TObj>, mats: Array<Mat4>) {
|
||||
@ -225,9 +232,9 @@ class BoneAnimation extends Animation {
|
||||
}
|
||||
|
||||
override public function play(action = "", onComplete: Void->Void = null, blendTime = 0.2, speed = 1.0, loop = true) {
|
||||
super.play(action, onComplete, blendTime, speed, loop);
|
||||
if (action != "") {
|
||||
setAction(action);
|
||||
super.play(action, onComplete, blendTime, speed, loop);
|
||||
var tempAnimParam = new ActionSampler(action);
|
||||
registerAction("tempAction", tempAnimParam);
|
||||
updateAnimation = function(mats){
|
||||
@ -239,6 +246,10 @@ class BoneAnimation extends Animation {
|
||||
override public function update(delta: FastFloat) {
|
||||
this.delta = delta;
|
||||
if (!isSkinned && skeletonBones == null) setAction(armature.actions[0].name);
|
||||
|
||||
// TODO: double check skip culling for skinned meshes if they need animation updates for bounds
|
||||
// if (object != null && !object.visible) return;
|
||||
|
||||
if (object != null && (!object.visible || object.culled)) return;
|
||||
if (skeletonBones == null || skeletonBones.length == 0) return;
|
||||
|
||||
@ -248,7 +259,6 @@ class BoneAnimation extends Animation {
|
||||
|
||||
super.update(delta);
|
||||
if(updateAnimation != null) {
|
||||
|
||||
updateAnimation(skeletonMats);
|
||||
}
|
||||
|
||||
@ -401,6 +411,7 @@ class BoneAnimation extends Animation {
|
||||
}
|
||||
|
||||
var bones = sampler.getBoneAction();
|
||||
if (bones == null) return;
|
||||
for(b in bones){
|
||||
if (b.anim != null) {
|
||||
updateTrack(b.anim, sampler);
|
||||
@ -410,13 +421,14 @@ class BoneAnimation extends Animation {
|
||||
}
|
||||
|
||||
public function sampleAction(sampler: ActionSampler, actionMats: Array<Mat4>) {
|
||||
|
||||
if(! sampler.actionDataInit) {
|
||||
var bones = getAction(sampler.action);
|
||||
sampler.setBoneAction(bones);
|
||||
}
|
||||
|
||||
var bones = sampler.getBoneAction();
|
||||
if (bones == null) return;
|
||||
|
||||
actionMats[skeletonBones.length].setIdentity();
|
||||
var rootMotionEnabled = sampler.rootMotionPos || sampler.rootMotionRot;
|
||||
for (i in 0...bones.length) {
|
||||
@ -427,7 +439,6 @@ class BoneAnimation extends Animation {
|
||||
updateAnimSampled(bones[i].anim, actionMats[i], sampler);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function updateAnimSampled(anim: TAnimation, mm: Mat4, sampler: ActionSampler) {
|
||||
@ -588,6 +599,9 @@ class BoneAnimation extends Animation {
|
||||
|
||||
public override function getTotalFrames(sampler: ActionSampler): Int {
|
||||
var bones = getAction(sampler.action);
|
||||
if (bones == null){
|
||||
return 0;
|
||||
}
|
||||
var track = bones[0].anim.tracks[0];
|
||||
return Std.int(track.frames[track.frames.length - 1] - track.frames[0]);
|
||||
}
|
||||
@ -1048,9 +1062,9 @@ class BoneAnimation extends Animation {
|
||||
var rootLen = root.bone_length * rootMat.getScale().x;
|
||||
|
||||
// Get distance form root to goal
|
||||
var goalLen = Math.abs(Vec4.distance(rootMat.getLoc(), goal));
|
||||
var goalLen: FastFloat = Math.abs(Vec4.distance(rootMat.getLoc(), goal));
|
||||
|
||||
var totalLength = effectorLen + rootLen;
|
||||
var totalLength: FastFloat = effectorLen + rootLen;
|
||||
|
||||
// Get tip location of effector bone
|
||||
var effectorTipPos = new Vec4().setFrom(effectorMat.look()).normalize();
|
||||
@ -1070,7 +1084,7 @@ class BoneAnimation extends Animation {
|
||||
|
||||
// Get unit vector of effector bone
|
||||
var vectorEffector = new Vec4().setFrom(effectorMat.look()).normalize();
|
||||
|
||||
|
||||
// Get dot product of vectors
|
||||
var dot = new Vec4().setFrom(vectorRootEffector).dot(vectorRoot);
|
||||
// Calmp between -1 and 1
|
||||
|
||||
@ -30,12 +30,23 @@ 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;
|
||||
|
||||
// dont just auto initialize VR button - headset trait controls VR
|
||||
// #if lnx_vr
|
||||
// iron.system.VR.initButton();
|
||||
// #end
|
||||
|
||||
buildProjection();
|
||||
|
||||
V = Mat4.identity();
|
||||
@ -75,7 +86,14 @@ class CameraObject extends Object {
|
||||
projectionJitter();
|
||||
#end
|
||||
|
||||
// matrices are set by VR system so avoid rebuilding transforms unless its in preview/not presenting
|
||||
#if (kha_webgl && lnx_vr)
|
||||
if (@:privateAccess !RenderPath.isVRPresenting()) {
|
||||
buildMatrix();
|
||||
}
|
||||
#else
|
||||
buildMatrix();
|
||||
#end
|
||||
|
||||
RenderPath.active.renderFrame(g);
|
||||
|
||||
@ -117,6 +135,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);
|
||||
}
|
||||
|
||||
@ -59,6 +59,9 @@ class LightObject extends Object {
|
||||
public static var clustersData: kha.Image = null;
|
||||
static var lpos = new Vec4();
|
||||
public static var LWVPMatrixArray: Float32Array = null;
|
||||
#if lnx_vr
|
||||
static var originalLightPositions: Float32Array = null;
|
||||
#end
|
||||
#end // lnx_clusters
|
||||
|
||||
public var V: Mat4 = Mat4.identity();
|
||||
@ -155,8 +158,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 = [];
|
||||
@ -514,7 +522,7 @@ class LightObject extends Object {
|
||||
updateLightsArray(); // TODO: only update on light change
|
||||
}
|
||||
|
||||
static function updateLightsArray() {
|
||||
public static function updateLightsArray() {
|
||||
if (lightsArray == null) { // vec4x3 - 1: pos, a, color, b, 2: dir, c
|
||||
lightsArray = new Float32Array(maxLights * 4 * 3);
|
||||
#if lnx_spot
|
||||
@ -573,6 +581,49 @@ class LightObject extends Object {
|
||||
}
|
||||
}
|
||||
|
||||
// VR deferred stereo we save original light positions before adjusting for per-eye rendering
|
||||
#if lnx_vr
|
||||
public static function saveOriginalLightPositions() {
|
||||
if (lightsArray == null) return;
|
||||
|
||||
if (originalLightPositions == null) {
|
||||
originalLightPositions = new Float32Array(lightsArray.length);
|
||||
}
|
||||
|
||||
for (i in 0...lightsArray.length) {
|
||||
originalLightPositions[i] = lightsArray[i];
|
||||
}
|
||||
}
|
||||
|
||||
// negative for left eye, positive for right eye
|
||||
public static function adjustLightPositionsForVREye(offsetX: Float, rightVec: Vec4) {
|
||||
if (lightsArray == null) return;
|
||||
|
||||
var lights = Scene.active.lights;
|
||||
var n = lights.length > maxLights ? maxLights : lights.length;
|
||||
var i = 0;
|
||||
|
||||
for (l in lights) {
|
||||
if (discardLightCulled(l)) continue;
|
||||
if (i >= n) break;
|
||||
|
||||
lightsArray[i * 12 ] = originalLightPositions[i * 12 ] + rightVec.x * offsetX;
|
||||
lightsArray[i * 12 + 1] = originalLightPositions[i * 12 + 1] + rightVec.y * offsetX;
|
||||
lightsArray[i * 12 + 2] = originalLightPositions[i * 12 + 2] + rightVec.z * offsetX;
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
public static function restoreOriginalLightPositions() {
|
||||
if (lightsArray == null || originalLightPositions == null) return;
|
||||
|
||||
for (i in 0...lightsArray.length) {
|
||||
lightsArray[i] = originalLightPositions[i];
|
||||
}
|
||||
}
|
||||
#end
|
||||
|
||||
public static function updateLWVPMatrixArray(object: Object, type: String) {
|
||||
if (LWVPMatrixArray == null) {
|
||||
LWVPMatrixArray = new Float32Array(maxLightsCluster * 16);
|
||||
@ -624,8 +675,8 @@ class LightObject extends Object {
|
||||
LWVPMatrixArray[i * 16 + 13] = m._31;
|
||||
LWVPMatrixArray[i * 16 + 14] = m._32;
|
||||
LWVPMatrixArray[i * 16 + 15] = m._33;
|
||||
i++; // only increment in light type
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return LWVPMatrixArray;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,6 +20,13 @@ class MorphTarget {
|
||||
public var morphDataPos: Image;
|
||||
public var morphDataNor: Image;
|
||||
public var morphMap: Map<String, Int> = null;
|
||||
|
||||
public var isDirty: Bool = true;
|
||||
var previousWeights: Float32Array;
|
||||
var changeThreshold: FastFloat = 0.001; // skip smaller
|
||||
var pendingUpdates: Map<Int, Float> = null;
|
||||
var batchUpdateEnabled: Bool = true;
|
||||
var lastFlushFrame: Int = 0;
|
||||
|
||||
public function new(data: TMorphTarget) {
|
||||
initWeights(data.morph_target_defaults);
|
||||
@ -42,6 +49,14 @@ class MorphTarget {
|
||||
morphMap.set(name, i);
|
||||
i++;
|
||||
}
|
||||
|
||||
previousWeights = new Float32Array(morphWeights.length);
|
||||
for (i in 0...morphWeights.length) {
|
||||
previousWeights.set(i, morphWeights.get(i));
|
||||
}
|
||||
|
||||
// batch system
|
||||
pendingUpdates = new Map<Int, Float>();
|
||||
}
|
||||
|
||||
inline function initWeights(defaults: Float32Array) {
|
||||
@ -54,9 +69,96 @@ class MorphTarget {
|
||||
public function setMorphValue(name: String, value: Float) {
|
||||
var i = morphMap.get(name);
|
||||
if (i != null) {
|
||||
morphWeights.set(i, value);
|
||||
if (batchUpdateEnabled) {
|
||||
pendingUpdates.set(i, value);
|
||||
} else {
|
||||
setMorphValueDirect(i, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// faster indexed access
|
||||
public inline function setMorphValueDirect(index: Int, value: Float) {
|
||||
var current = morphWeights.get(index);
|
||||
|
||||
// allow explicit zero values to reset
|
||||
if (value == 0.0 && current != 0.0) {
|
||||
morphWeights.set(index, value);
|
||||
isDirty = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var delta = value - current;
|
||||
|
||||
if (delta < -changeThreshold || delta > changeThreshold) {
|
||||
morphWeights.set(index, value);
|
||||
isDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
// flush pending batch
|
||||
public function flushBatchedUpdates() {
|
||||
if (pendingUpdates.keys().hasNext()) {
|
||||
var anyChanged = false;
|
||||
var hasZeros = false;
|
||||
|
||||
for (index in pendingUpdates.keys()) {
|
||||
var value = pendingUpdates.get(index);
|
||||
if (value == null) continue;
|
||||
|
||||
if (value == 0.0) hasZeros = true;
|
||||
|
||||
var current = morphWeights.get(index);
|
||||
var delta = value - current;
|
||||
|
||||
if (value == 0.0 && current != 0.0) {
|
||||
try{
|
||||
morphWeights.set(index, cast value);
|
||||
}catch(e){
|
||||
trace("ERROR: " + e);
|
||||
}
|
||||
anyChanged = true;
|
||||
}
|
||||
else if (delta < -changeThreshold || delta > changeThreshold) {
|
||||
morphWeights.set(index, cast value);
|
||||
anyChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
pendingUpdates.clear();
|
||||
|
||||
if (anyChanged || hasZeros) {
|
||||
isDirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public inline function markClean() {
|
||||
isDirty = false;
|
||||
for (i in 0...morphWeights.length) {
|
||||
previousWeights.set(i, morphWeights.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
public inline function markDirty() {
|
||||
isDirty = true;
|
||||
}
|
||||
|
||||
// toggle batch mode
|
||||
public inline function setBatchMode(enabled: Bool) {
|
||||
if (!enabled && batchUpdateEnabled) {
|
||||
flushBatchedUpdates();
|
||||
}
|
||||
batchUpdateEnabled = enabled;
|
||||
}
|
||||
|
||||
public function resetAllWeights() {
|
||||
for (i in 0...morphWeights.length) {
|
||||
morphWeights.set(i, 0.0);
|
||||
}
|
||||
pendingUpdates.clear();
|
||||
isDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
#end
|
||||
|
||||
@ -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;
|
||||
@ -206,8 +210,12 @@ class Object {
|
||||
}
|
||||
|
||||
#if lnx_skin
|
||||
public function getBoneAnimation(armatureUid): BoneAnimation {
|
||||
for (a in Scene.active.animations) if (a.armature != null && a.armature.uid == armatureUid) return cast a;
|
||||
public function getBoneAnimation(armatureUid: Int): BoneAnimation {
|
||||
for (a in Scene.active.animations) {
|
||||
if (a.armature != null && a.armature.uid == armatureUid) {
|
||||
return cast a;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
#else
|
||||
|
||||
@ -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
|
||||
@ -75,7 +97,9 @@ class ObjectAnimation extends Animation {
|
||||
}
|
||||
|
||||
public override function getTotalFrames(sampler: ActionSampler): Int {
|
||||
var track = getAction(sampler.action).anim.tracks[0];
|
||||
var action = getAction(sampler.action);
|
||||
if (action == null || action.anim == null || action.anim.tracks == null || action.anim.tracks.length == 0) return 0;
|
||||
var track = action.anim.tracks[0];
|
||||
return Std.int(track.frames[track.frames.length - 1] - track.frames[0]);
|
||||
}
|
||||
|
||||
|
||||