This commit is contained in:
Julien Valverdé
2026-09-09 01:04:07 +02:00
parent f9d589cf68
commit 7b1c459cf9
408 changed files with 24 additions and 19273 deletions
+4 -4
View File
@@ -104,10 +104,10 @@ subscriptions after a scene transition.
## Proposed package shape
Start in this workspace as `packages/effect-platform-godot` under the internal
scope `@codename-painless/effect-platform-godot`. Keep it independently
publishable; an unscoped `effect-platform-godot` package name or the
`@effect/*` namespace should not be assumed available.
Start in this workspace as `packages/effect-platform-godot` under the
`@effect-godot/effect-platform-godot` scope. Keep it independently
publishable; an unscoped `effect-platform-godot` package name should not be
assumed available.
```text
packages/effect-platform-godot/
+8 -118
View File
@@ -3,40 +3,24 @@
"configVersion": 1,
"workspaces": {
"": {
"name": "effect-godot",
"name": "@effect-godot/monorepo",
"devDependencies": {
"typescript": "^7.0.2",
},
},
"packages/common": {
"name": "@codename-painless/common",
"version": "0.0.0",
"dependencies": {
"effect": "^4.0.0-rc.112",
},
},
"packages/effect-godot": {
"name": "@codename-painless/effect-godot",
"name": "effect-godot",
"version": "0.0.0",
},
"packages/game": {
"name": "@codename-painless/game",
"name": "@effect-godot/game",
"version": "0.0.0",
"dependencies": {
"@codename-painless/common": "workspace:*",
"effect": "^4.0.0-rc.112",
"mitt": "^3.0.1",
},
"devDependencies": {
"@codename-painless/godot-bin": "workspace:*",
"@effect/platform-bun": "^4.0.0-rc.112",
"@types/node": "^26.4.1",
"esbuild": "^0.28.2",
"rolldown": "^1.2.7",
"@effect-godot/godot-bin": "workspace:*",
},
},
"packages/godot-bin": {
"name": "@codename-painless/godot-bin",
"name": "@effect-godot/godot-bin",
"version": "0.0.0",
"bin": {
"godot-bin": "./src/cli.ts",
@@ -48,70 +32,14 @@
},
},
"packages": {
"@codename-painless/common": ["@codename-painless/common@workspace:packages/common"],
"@effect-godot/game": ["@effect-godot/game@workspace:packages/game"],
"@codename-painless/effect-godot": ["@codename-painless/effect-godot@workspace:packages/effect-godot"],
"@codename-painless/game": ["@codename-painless/game@workspace:packages/game"],
"@codename-painless/godot-bin": ["@codename-painless/godot-bin@workspace:packages/godot-bin"],
"@effect-godot/godot-bin": ["@effect-godot/godot-bin@workspace:packages/godot-bin"],
"@effect/platform-bun": ["@effect/platform-bun@4.0.0-rc.112", "", { "dependencies": { "@effect/platform-node-shared": "^4.0.0-rc.112" }, "peerDependencies": { "effect": "^4.0.0-rc.112" } }, "sha512-Y5n2HhV/vsbrJls9ukX42RL7zqXQxISHegWFsP9njsCyDmGTnq7QYSO82rglwrLPwtTrv5dkSRTuGw4+oXxgMg=="],
"@effect/platform-node-shared": ["@effect/platform-node-shared@4.0.0-rc.112", "", { "dependencies": { "@types/ws": "^8.18.1", "ws": "^8.21.3" }, "peerDependencies": { "effect": "^4.0.0-rc.112" } }, "sha512-ttjz0xKamFN7vL8pNDYVwddJLjZvqKePc05djlz2VcdaKbLsnYbtMnL1rbOfHgEnIUSHGh7FkjaN4DM1Ov81sQ=="],
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.28.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ=="],
"@esbuild/android-arm": ["@esbuild/android-arm@0.28.2", "", { "os": "android", "cpu": "arm" }, "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg=="],
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.28.2", "", { "os": "android", "cpu": "arm64" }, "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A=="],
"@esbuild/android-x64": ["@esbuild/android-x64@0.28.2", "", { "os": "android", "cpu": "x64" }, "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q=="],
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.28.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw=="],
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.28.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw=="],
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.28.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw=="],
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.28.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg=="],
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.28.2", "", { "os": "linux", "cpu": "arm" }, "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w=="],
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.28.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug=="],
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.28.2", "", { "os": "linux", "cpu": "ia32" }, "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ=="],
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.28.2", "", { "os": "linux", "cpu": "none" }, "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ=="],
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.28.2", "", { "os": "linux", "cpu": "none" }, "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA=="],
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.28.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ=="],
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.28.2", "", { "os": "linux", "cpu": "none" }, "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA=="],
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.28.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg=="],
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.28.2", "", { "os": "linux", "cpu": "x64" }, "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ=="],
"@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.28.2", "", { "os": "none", "cpu": "arm64" }, "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw=="],
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.28.2", "", { "os": "none", "cpu": "x64" }, "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw=="],
"@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.28.2", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ=="],
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.28.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw=="],
"@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.28.2", "", { "os": "none", "cpu": "arm64" }, "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q=="],
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.28.2", "", { "os": "sunos", "cpu": "x64" }, "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g=="],
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.28.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ=="],
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.28.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA=="],
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.28.2", "", { "os": "win32", "cpu": "x64" }, "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g=="],
"@msgpackr-extract/msgpackr-extract-darwin-arm64": ["@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-LCkGo6JDfaBhgST7UpPWgNgLINpcpabaHfyz5OBx75nUYxBsaEPxjnyNjWpeb/xBup/682QnBfRBy2/LvPutZQ=="],
"@msgpackr-extract/msgpackr-extract-darwin-x64": ["@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-zExlW9zUJKZH/tOtVMttwjKa4Xm/3KcNjnE3dPN92uCktwavMxpgCA3MoJK/DOnTWsQgo224OaST27/mPNAf+w=="],
@@ -124,40 +52,6 @@
"@msgpackr-extract/msgpackr-extract-win32-x64": ["@msgpackr-extract/msgpackr-extract-win32-x64@3.0.4", "", { "os": "win32", "cpu": "x64" }, "sha512-CmCXPQrkbwExx3j946/PtHWHbYJiCRBRDl4BlkRQcJB/YOwQxJRTpoo7aTsortjgoJ1x7opzTSxn7C+ASSLVjQ=="],
"@oxc-project/types": ["@oxc-project/types@0.148.0", "", {}, "sha512-Nm4s/jB+4FpFsPhWGEC4h7rzksesmtnMXomo6rCMcg/b8zLQuOziRgkCS1fxDCXOlJB/6Q8oABOZ/OP6RIPj9A=="],
"@rolldown/binding-android-arm-eabi": ["@rolldown/binding-android-arm-eabi@1.2.7", "", { "os": "android", "cpu": "arm" }, "sha512-EypzgnYCwyVY4NDHKzGmNJT5b+XaQEBniHxsMdeIQLB/tcCzZnhqrzHpZFbX9iaxx+5RiB8caATBtfvZP7zVxQ=="],
"@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.2.7", "", { "os": "android", "cpu": "arm64" }, "sha512-l17HE9EweWaqJZhuUuNBN/FzM62xw+DECVnJyvMsxn8vJFAGLy5QfLDoYAcronkAN8VxKZHezDpulHDPx95vFw=="],
"@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.2.7", "", { "os": "darwin", "cpu": "arm64" }, "sha512-8ED8ELFvHXc6OCETIn4gXObPiaR6bckM/ipXtbzlPVDRMBfEGjCKgO90F9YtfdpDatVx/ZQw7aZ1vUMf/+T3Mw=="],
"@rolldown/binding-darwin-x64": ["@rolldown/binding-darwin-x64@1.2.7", "", { "os": "darwin", "cpu": "x64" }, "sha512-/WPripjtiAIZ2tWY7ddijORT0Ujg87wxWW/qcoFVCKAWVDPhtY0xr7Dj0M3GyNGz60jGwTElhro/mkF9dT7dDQ=="],
"@rolldown/binding-freebsd-x64": ["@rolldown/binding-freebsd-x64@1.2.7", "", { "os": "freebsd", "cpu": "x64" }, "sha512-14DI4NcqpvbICxSnGLx3PmtDaWqRP/KGSGb6C+JLLVPeZRl6dKdHba3pGsqT3vpdTqhEYIPG0MMQ8c0xYqoJxA=="],
"@rolldown/binding-linux-arm-gnueabihf": ["@rolldown/binding-linux-arm-gnueabihf@1.2.7", "", { "os": "linux", "cpu": "arm" }, "sha512-bxrWIRvHWQvbJwi+VIie/kDJmQxcNE6xxWwZdqF/ExVAigtHkv54WTLQPb+QsZdnFy18fg7JPfWGL0RH6vwIlQ=="],
"@rolldown/binding-linux-arm64-gnu": ["@rolldown/binding-linux-arm64-gnu@1.2.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-toOY2BChBZyuxU7OYX6Tn389di4IzAqPTycVcci0O7FSfBqzRB3RZn+K5Is6ANf4tmgRd/K1yZTsNTXbkXsnLg=="],
"@rolldown/binding-linux-arm64-musl": ["@rolldown/binding-linux-arm64-musl@1.2.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-lAIXTH/aiLRLxsTgQvfhjo4K1ydWIp00+V0voOr9beb/9ZmkUFrSIb03dXNFRgMNvkE6oGsF10ioQ6UsI+vS5Q=="],
"@rolldown/binding-linux-ppc64-gnu": ["@rolldown/binding-linux-ppc64-gnu@1.2.7", "", { "os": "linux", "cpu": "ppc64" }, "sha512-kdnwS28Pkenp/mZMRwjXXXwxQ7pIsm+bF919LUK93BOyhcLsrVKdP2p9fxpiPNPAbNuch8ypQt0pm2P2LYCAGg=="],
"@rolldown/binding-linux-s390x-gnu": ["@rolldown/binding-linux-s390x-gnu@1.2.7", "", { "os": "linux", "cpu": "s390x" }, "sha512-516OdsyLdr5E65paF3yBF55t8mfm9+gmtCsK3xI7XKXIT7EfRlHhxL8K/NR6Hu8BWSgF5+1w74lTL0+nxcc8Qw=="],
"@rolldown/binding-linux-x64-gnu": ["@rolldown/binding-linux-x64-gnu@1.2.7", "", { "os": "linux", "cpu": "x64" }, "sha512-r8/z8n7GFaYRln3xmP1Cxy0HH/HLM0uBUPkEuSVEfKGDA89M0FsZRZJRSwe/tJjRx+fpH/gjorfhB8tmEbSFLA=="],
"@rolldown/binding-linux-x64-musl": ["@rolldown/binding-linux-x64-musl@1.2.7", "", { "os": "linux", "cpu": "x64" }, "sha512-pAsE8iiDxUg1xBqdhrTfg45AVDVpirjz00sblEYClGNNcMnDb+e8beQgqIAw6LvauX/APvgxUnwrgun/YYGBhw=="],
"@rolldown/binding-openharmony-arm64": ["@rolldown/binding-openharmony-arm64@1.2.7", "", { "os": "none", "cpu": "arm64" }, "sha512-lTcIYmmnQQA8Or/2DatS6oSqcdLHvendjS+zLu+FwgToynWMRSmQdpM65fTANJgIS4mjbMOo5KT2lnT9SAb96w=="],
"@rolldown/binding-win32-arm64-msvc": ["@rolldown/binding-win32-arm64-msvc@1.2.7", "", { "os": "win32", "cpu": "arm64" }, "sha512-e3Gu3WxbNk/UqQhxqU7YIYO+9ZBvWNz3U+h/qRFosscMFzdRPbXYSaSWgSnklv2fz1TgzBTcti2z35c/7irsHw=="],
"@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.2.7", "", { "os": "win32", "cpu": "x64" }, "sha512-W/jg5qoRSqjsEv0+dZi4e687mcHqmVuU0P4fK6qS/xjetW2Gmc1W8j//z5nAeNcC8Ttm0hV46IjcYeuVwYhuiw=="],
"@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.1", "", {}, "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw=="],
"@types/node": ["@types/node@26.4.1", "", { "dependencies": { "undici-types": "~8.3.0" } }, "sha512-k97ENvZWtvA6yqz5/FS6a7duDgOPEeOQOc2iKS/nY6mX6qJUKtLnWzQS+Xj6tXweyj6ZcTAK2Qecetnvi9nCLA=="],
"@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="],
@@ -206,12 +100,10 @@
"effect": ["effect@4.0.0-rc.112", "", { "dependencies": { "fast-check": "^4.9.0", "msgpackr": "^2.0.5" } }, "sha512-wXxwuh1Ywnv4cPRM3Wfa0vDwuOHnZ1TsTgHJkG9XgzND6inhBH9n1vBxhg3iIXOia/OrpmvVmd3lrD4vq6bF3A=="],
"esbuild": ["esbuild@0.28.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.28.2", "@esbuild/android-arm": "0.28.2", "@esbuild/android-arm64": "0.28.2", "@esbuild/android-x64": "0.28.2", "@esbuild/darwin-arm64": "0.28.2", "@esbuild/darwin-x64": "0.28.2", "@esbuild/freebsd-arm64": "0.28.2", "@esbuild/freebsd-x64": "0.28.2", "@esbuild/linux-arm": "0.28.2", "@esbuild/linux-arm64": "0.28.2", "@esbuild/linux-ia32": "0.28.2", "@esbuild/linux-loong64": "0.28.2", "@esbuild/linux-mips64el": "0.28.2", "@esbuild/linux-ppc64": "0.28.2", "@esbuild/linux-riscv64": "0.28.2", "@esbuild/linux-s390x": "0.28.2", "@esbuild/linux-x64": "0.28.2", "@esbuild/netbsd-arm64": "0.28.2", "@esbuild/netbsd-x64": "0.28.2", "@esbuild/openbsd-arm64": "0.28.2", "@esbuild/openbsd-x64": "0.28.2", "@esbuild/openharmony-arm64": "0.28.2", "@esbuild/sunos-x64": "0.28.2", "@esbuild/win32-arm64": "0.28.2", "@esbuild/win32-ia32": "0.28.2", "@esbuild/win32-x64": "0.28.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA=="],
"effect-godot": ["effect-godot@workspace:packages/effect-godot"],
"fast-check": ["fast-check@4.9.0", "", { "dependencies": { "pure-rand": "^8.0.0" } }, "sha512-7ms6T7SybUev/PQITciI0yLM2pOSFy5zpG8Ty7tQofcVaQUvrMXp6CBwqF6fThLCLOrfBtuHAtwq6Yu4XPCllg=="],
"mitt": ["mitt@3.0.1", "", {}, "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw=="],
"msgpackr": ["msgpackr@2.1.0", "", { "optionalDependencies": { "msgpackr-extract": "^3.0.4" } }, "sha512-p/pBCVO63CsvvpkomUnNNag6+n38rULuDA6HHe70o2gtC8ODI52foF/4ko2qQcp6OiErJXTmrZeXmsGGHsIQNQ=="],
"msgpackr-extract": ["msgpackr-extract@3.0.4", "", { "dependencies": { "node-gyp-build-optional-packages": "5.2.2" }, "optionalDependencies": { "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.4", "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.4", "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.4" }, "bin": { "download-msgpackr-prebuilds": "bin/download-prebuilds.js" } }, "sha512-4kmO/MdyUIkLIvTPr8VHLil4AtoKIoniWPIEk5+CDy0xnWC84azhSFmuJ7PxZdsYtiP5kEeQsORAVIeMgxT+Hw=="],
@@ -220,8 +112,6 @@
"pure-rand": ["pure-rand@8.4.2", "", {}, "sha512-vvuOGgcuPJAirlHvuQw1TrOiw7ptaIXXmIbNuiNOY6lNGJJH49PQ1Kj4nd783nPdQhQdicgOjVI2yI/9BD6/Ng=="],
"rolldown": ["rolldown@1.2.7", "", { "dependencies": { "@oxc-project/types": "=0.148.0", "@rolldown/pluginutils": "^1.0.0" }, "optionalDependencies": { "@rolldown/binding-android-arm-eabi": "1.2.7", "@rolldown/binding-android-arm64": "1.2.7", "@rolldown/binding-darwin-arm64": "1.2.7", "@rolldown/binding-darwin-x64": "1.2.7", "@rolldown/binding-freebsd-x64": "1.2.7", "@rolldown/binding-linux-arm-gnueabihf": "1.2.7", "@rolldown/binding-linux-arm64-gnu": "1.2.7", "@rolldown/binding-linux-arm64-musl": "1.2.7", "@rolldown/binding-linux-ppc64-gnu": "1.2.7", "@rolldown/binding-linux-s390x-gnu": "1.2.7", "@rolldown/binding-linux-x64-gnu": "1.2.7", "@rolldown/binding-linux-x64-musl": "1.2.7", "@rolldown/binding-openharmony-arm64": "1.2.7", "@rolldown/binding-win32-arm64-msvc": "1.2.7", "@rolldown/binding-win32-x64-msvc": "1.2.7" }, "bin": { "rolldown": "./bin/cli.mjs" } }, "sha512-g0EtLvBjTUB7jhyV0S/TCup3v/XSVl45vUIGbOGU4QPiyjTenCe4mKuFvW9fEgYmS2Fo42AUssRmNuMziXdrig=="],
"typescript": ["typescript@7.0.2", "", { "optionalDependencies": { "@typescript/typescript-aix-ppc64": "7.0.2", "@typescript/typescript-darwin-arm64": "7.0.2", "@typescript/typescript-darwin-x64": "7.0.2", "@typescript/typescript-freebsd-arm64": "7.0.2", "@typescript/typescript-freebsd-x64": "7.0.2", "@typescript/typescript-linux-arm": "7.0.2", "@typescript/typescript-linux-arm64": "7.0.2", "@typescript/typescript-linux-loong64": "7.0.2", "@typescript/typescript-linux-mips64el": "7.0.2", "@typescript/typescript-linux-ppc64": "7.0.2", "@typescript/typescript-linux-riscv64": "7.0.2", "@typescript/typescript-linux-s390x": "7.0.2", "@typescript/typescript-linux-x64": "7.0.2", "@typescript/typescript-netbsd-arm64": "7.0.2", "@typescript/typescript-netbsd-x64": "7.0.2", "@typescript/typescript-openbsd-arm64": "7.0.2", "@typescript/typescript-openbsd-x64": "7.0.2", "@typescript/typescript-sunos-x64": "7.0.2", "@typescript/typescript-win32-arm64": "7.0.2", "@typescript/typescript-win32-x64": "7.0.2" }, "bin": { "tsc": "bin/tsc" } }, "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA=="],
"undici-types": ["undici-types@8.3.0", "", {}, "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ=="],
+2 -6
View File
@@ -1,14 +1,10 @@
{
"name": "effect-godot",
"name": "@effect-godot/monorepo",
"private": true,
"workspaces": ["packages/*"],
"scripts": {
"build": "bun run --cwd packages/game build",
"dev": "bun run --cwd packages/game dev",
"typegen": "bun run --cwd packages/game typegen",
"edit": "bun run --cwd packages/game edit",
"run": "bun run --cwd packages/game run",
"cef:fetch": "bun run --cwd packages/game cef:fetch"
"run": "bun run --cwd packages/game run"
},
"devDependencies": {
"typescript": "^7.0.2"
-12
View File
@@ -1,12 +0,0 @@
{
"name": "@codename-painless/common",
"version": "0.0.0",
"private": true,
"type": "module",
"exports": {
".": "./src/index.ts"
},
"dependencies": {
"effect": "^4.0.0-rc.112"
}
}
-10
View File
@@ -1,10 +0,0 @@
// The events the game can push to the UI, over RpcClient/RpcServer's
// pseudo-RPC engine. Unlike procedures these are unsolicited broadcasts:
// nothing correlates them to a request.
//
// Empty for now — no events defined yet.
import { Schema } from "effect"
export const Event = Schema.TaggedUnion({})
export type Event = typeof Event.Type
-14
View File
@@ -1,14 +0,0 @@
// The procedures the UI can trigger on the game, over RpcClient/RpcServer's
// pseudo-RPC engine. Each tag pairs a request shape with the success/error
// schema its response is decoded against.
//
// Empty for now — no procedures defined yet.
import { Schema } from "effect"
export const Request = Schema.TaggedUnion({})
export type Request = typeof Request.Type
export const success = {} satisfies Record<Request["_tag"], Schema.Top>
export const error = {} satisfies Record<Request["_tag"], Schema.Top>
-119
View File
@@ -1,119 +0,0 @@
// The UI side of the pseudo-RPC engine: call the game's procedures and
// subscribe to its events. See RpcMessage.ts for the wire protocol.
import { Effect, PubSub, Schema, Scope, Stream } from "effect"
import * as RpcMessage from "./RpcMessage"
export interface Client<
Req extends RpcMessage.AnyRequestUnion,
Success extends RpcMessage.SchemaByTag<Req>,
Err extends RpcMessage.SchemaByTag<Req>,
Ev extends RpcMessage.AnySchema,
> {
readonly call: <T extends RpcMessage.Tag<Req>>(
request: RpcMessage.RequestOf<Req, T>,
) => Effect.Effect<Success[T]["Type"], Err[T]["Type"]>
readonly events: Stream.Stream<Ev["Type"]>
}
// Scoped: holds a live transport subscription and an event PubSub for as
// long as the returned Client is in use, and tears both down when the scope
// closes.
export function make<
Req extends RpcMessage.AnyRequestUnion,
Success extends RpcMessage.SchemaByTag<Req>,
Err extends RpcMessage.SchemaByTag<Req>,
Ev extends RpcMessage.AnySchema,
>(options: {
readonly transport: RpcMessage.Transport
readonly request: Req
readonly success: Success
readonly error: Err
readonly event: Ev
}): Effect.Effect<Client<Req, Success, Err, Ev>, never, Scope.Scope> {
return Effect.gen(function* () {
const pending = new Map<
string,
(envelope: RpcMessage.ResponseEnvelope) => void
>()
const pubsub = yield* PubSub.unbounded<Ev["Type"]>()
yield* Effect.addFinalizer(() => PubSub.shutdown(pubsub))
const unsubscribe = options.transport.onMessage((raw) => {
const parsed = RpcMessage.parseQuietly(raw)
if (parsed === undefined) return
const envelope = RpcMessage.decodeQuietly(
RpcMessage.GameToUiEnvelope,
parsed,
"game -> ui message",
)
if (!envelope) return
if (envelope._tag === "RpcEvent") {
const event = RpcMessage.decodeQuietly(
options.event,
envelope.event,
"event",
)
if (event === undefined) return
PubSub.publishUnsafe(pubsub, event)
return
}
const resolve = pending.get(envelope.id)
if (!resolve) return
pending.delete(envelope.id)
resolve(envelope)
})
yield* Effect.addFinalizer(() => Effect.sync(unsubscribe))
function call<T extends RpcMessage.Tag<Req>>(
request: RpcMessage.RequestOf<Req, T>,
): Effect.Effect<Success[T]["Type"], Err[T]["Type"]> {
return Effect.callback<unknown, unknown>((resume) => {
const tag = (request as { _tag: string })
._tag as RpcMessage.Tag<Req>
const id = RpcMessage.nextId()
pending.set(id, (envelope) => {
if (envelope._tag === "RpcSuccess") {
const value = RpcMessage.decodeQuietly(
options.success[tag],
envelope.value,
`${tag} result`,
)
resume(
value === undefined
? Effect.die(
`[rpc] malformed result for "${tag}"`,
)
: Effect.succeed(value),
)
} else {
const error = RpcMessage.decodeQuietly(
options.error[tag],
envelope.error,
`${tag} error`,
)
resume(
error === undefined
? Effect.die(
`[rpc] malformed error for "${tag}"`,
)
: Effect.fail(error),
)
}
})
const encoded = Schema.encodeSync(options.request)(request)
options.transport.send(
JSON.stringify({
_tag: "RpcRequest",
id,
request: encoded,
}),
)
}) as Effect.Effect<Success[T]["Type"], Err[T]["Type"]>
}
return { call, events: Stream.fromPubSub(pubsub) }
})
}
-94
View File
@@ -1,94 +0,0 @@
// The wire protocol RpcClient.ts and RpcServer.ts both speak, and the
// transport contract either side plugs into it.
//
// godot-cef only gives two one-way string channels: the UI pushes a string to
// the game (`window.sendIpcMessage` / the `ipc_message` signal) and the game
// pushes a string to the UI (`CefTexture.eval` running JS in the page). There
// is no real request/response transport underneath. RpcClient/RpcServer
// emulate one on top of those two channels: every UI -> game request carries
// an `id`, the matching game -> UI reply is correlated by that same `id`, and
// anything the game pushes without a request (a broadcast) is delivered as
// an event instead. Hence "pseudo": the RPC semantics are real, the
// transport is not.
import { Schema } from "effect"
// Both Godot's JS engine and the browser provide `console`; this package's
// tsconfig otherwise stays deliberately free of DOM/Node lib globals.
declare const console: {
readonly log: (...args: ReadonlyArray<unknown>) => void
}
// The only thing either runtime has to supply — a way to send a string out
// and a way to be notified when one arrives.
export interface Transport {
readonly send: (message: string) => void
readonly onMessage: (listener: (message: string) => void) => () => void
}
// The schemas plugged into RpcClient/RpcServer never need decoding/encoding
// services (they're plain JSON-shaped data), which is what lets a single
// schema value be used for both `decodeUnknownSync` and `encodeSync`.
export type AnySchema = Schema.Codec<unknown, unknown, never, never>
export const RequestEnvelope = Schema.TaggedStruct("RpcRequest", {
id: Schema.String,
request: Schema.Unknown,
})
export const ResponseEnvelope = Schema.TaggedUnion({
RpcSuccess: { id: Schema.String, value: Schema.Unknown },
RpcFailure: { id: Schema.String, error: Schema.Unknown },
})
export type ResponseEnvelope = typeof ResponseEnvelope.Type
export const EventEnvelope = Schema.TaggedStruct("RpcEvent", {
event: Schema.Unknown,
})
export const GameToUiEnvelope = Schema.Union([ResponseEnvelope, EventEnvelope])
export function nextId(): string {
return Math.random().toString(36).slice(2)
}
export function decodeQuietly<S extends AnySchema>(
schema: S,
input: unknown,
what: string,
): S["Type"] | undefined {
try {
return Schema.decodeUnknownSync(schema)(input)
} catch (cause) {
console.log(`[rpc] ignoring malformed ${what}`, cause)
return undefined
}
}
export function parseQuietly(raw: string): unknown {
try {
return JSON.parse(raw)
} catch (cause) {
console.log("[rpc] ignoring malformed message", raw, cause)
return undefined
}
}
// A tagged union of requests, as produced by `Schema.TaggedUnion`. Every
// procedure a group exposes is one member of this union.
export type AnyRequestUnion = AnySchema & {
readonly Type: { readonly _tag: string }
readonly match: (
value: any,
cases: Record<string, (value: any) => unknown>,
) => unknown
}
export type Tag<Req extends AnyRequestUnion> = Req["Type"]["_tag"]
export type RequestOf<
Req extends AnyRequestUnion,
T extends Tag<Req>,
> = Extract<Req["Type"], { readonly _tag: T }>
export type SchemaByTag<Req extends AnyRequestUnion> = {
readonly [T in Tag<Req>]: AnySchema
}
-115
View File
@@ -1,115 +0,0 @@
// The game side of the pseudo-RPC engine: handle the UI's procedure calls
// and push events to it. See RpcMessage.ts for the wire protocol.
import { Effect, Exit, Option, Schema, Scope } from "effect"
import * as RpcMessage from "./RpcMessage"
// Both Godot's JS engine and the browser provide `console`; this package's
// tsconfig otherwise stays deliberately free of DOM/Node lib globals.
declare const console: {
readonly log: (...args: ReadonlyArray<unknown>) => void
}
export interface Server<Ev extends RpcMessage.AnySchema> {
readonly emit: (event: Ev["Type"]) => Effect.Effect<void>
}
// Scoped: holds a live transport subscription for as long as the returned
// Server is in use, and tears it down when the scope closes.
export function make<
Req extends RpcMessage.AnyRequestUnion,
Success extends RpcMessage.SchemaByTag<Req>,
Err extends RpcMessage.SchemaByTag<Req>,
Ev extends RpcMessage.AnySchema,
>(options: {
readonly transport: RpcMessage.Transport
readonly request: Req
readonly success: Success
readonly error: Err
readonly event: Ev
readonly handlers: {
readonly [T in RpcMessage.Tag<Req>]: (
request: RpcMessage.RequestOf<Req, T>,
) => Effect.Effect<Success[T]["Type"], Err[T]["Type"]>
}
}): Effect.Effect<Server<Ev>, never, Scope.Scope> {
return Effect.gen(function* () {
const unsubscribe = options.transport.onMessage((raw) => {
const parsed = RpcMessage.parseQuietly(raw)
if (parsed === undefined) return
const envelope = RpcMessage.decodeQuietly(
RpcMessage.RequestEnvelope,
parsed,
"ui -> game message",
)
if (!envelope) return
const request = RpcMessage.decodeQuietly(
options.request,
envelope.request,
"request",
)
if (!request) return
const tag = (request as { _tag: string })
._tag as RpcMessage.Tag<Req>
const effect = options.request.match(
request,
options.handlers as Record<
string,
(value: unknown) => Effect.Effect<unknown, unknown>
>,
) as Effect.Effect<unknown, unknown>
Effect.runPromiseExit(effect).then((exit) => {
if (Exit.isSuccess(exit)) {
const value = Schema.encodeSync(options.success[tag])(
exit.value,
)
options.transport.send(
JSON.stringify({
_tag: "RpcSuccess",
id: envelope.id,
value,
}),
)
return
}
// A defect here is a genuine bug (the handler threw instead of
// failing with its declared error type) — there's no schema to
// encode it as, so it's logged loudly and the call is left pending
// rather than pretending it succeeded.
const failure = Exit.findErrorOption(exit)
if (Option.isNone(failure)) {
console.log(
`[rpc] unhandled defect in "${tag}" handler`,
exit.cause,
)
return
}
const error = Schema.encodeSync(options.error[tag])(
failure.value,
)
options.transport.send(
JSON.stringify({
_tag: "RpcFailure",
id: envelope.id,
error,
}),
)
})
})
yield* Effect.addFinalizer(() => Effect.sync(unsubscribe))
function emit(event: Ev["Type"]): Effect.Effect<void> {
return Effect.sync(() => {
const encoded = Schema.encodeSync(options.event)(event)
options.transport.send(
JSON.stringify({ _tag: "RpcEvent", event: encoded }),
)
})
}
return { emit }
})
}
-11
View File
@@ -1,11 +0,0 @@
// JSON-safe data and protocol modules shared by the Godot runtime and the
// UI. Runtime-specific behavior stays in packages/game and packages/ui.
//
// Organized the way `effect` organizes itself: one module per file, each
// re-exported here as a namespace.
export * as Events from "./Events"
export * as Procedures from "./Procedures"
export * as RpcClient from "./RpcClient"
export * as RpcMessage from "./RpcMessage"
export * as RpcServer from "./RpcServer"
-14
View File
@@ -1,14 +0,0 @@
{
"compilerOptions": {
"target": "es2022",
"module": "esnext",
"moduleResolution": "bundler",
"lib": ["es2022"],
"strict": true,
"noEmit": true,
"isolatedModules": true,
"verbatimModuleSyntax": true,
"skipLibCheck": true
},
"include": ["src"]
}
+1 -1
View File
@@ -1,5 +1,5 @@
{
"name": "@codename-painless/effect-godot",
"name": "effect-godot",
"version": "0.0.0",
"private": true,
"type": "module",
+1 -1
View File
@@ -2,7 +2,7 @@
"compilerOptions": {
"target": "es2022",
"module": "esnext",
"moduleResolution": "bundler",
"moduleResolution": "nodenext",
"lib": ["es2022"],
"strict": true,
"noEmit": true,
-6
View File
@@ -1,9 +1,3 @@
.godot/
.godot-bin/
node_modules/
# Platform CEF runtime binaries (~1GB), fetched by `godot-bin cef fetch`
addons/godot_cef/bin/
addons/libpainless/bin/
gen/
typings/*.d.ts
*.tsbuildinfo
-21
View File
@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2025 Jakob Gillich
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.
-63
View File
@@ -1,63 +0,0 @@
# Foliage3D
Procedural foliage generation for Terrain3D.
![](./screenshot.png)
**Important**: This addon is in alpha, bugs and breaking changes are to be expected. Always back up your project.
## Getting started
After enabling the plugin, create a *Foliage3D* node below a *Terrain3D* node.
To set bounds, create a *CollisionShape3D* node below *Foliage3D* with either a box or sphere shape
(this will likely be replaced with a custom node in the future).
Once bounds are set, create a graph. Saving to disk is optional but recommended. The graph editor opens in the bottom panel.
Create a *SurfaceSampler* node by right-clicking anywhere and feed its
output into a *MeshSpawner* node. To assign a mesh, click on the *MeshSpawner* and add at least one mesh in the sidebar on the right.
This should spawn meshes in the 3D viewport. Click the save button under *Foliage3D* to save the meshes into your terrain data, or clear to delete them.
## Nodes
#### SurfaceSampler
Sample points from terrain surface within bounds. Point extents sets a bounding box that, for example, can be used to filter overlapping points with the *Difference* and *Prune* nodes.
#### FilterPoint
Filter point position and rotation range. A `0` value equals the respective minimum/maximum value.
#### Transform
Randomize transform offset/rotation/scale.
#### Difference
Remove points in A that overlap with B.
#### Prune
Remove points that overlap with self.
#### MeshSpawner
Spawn meshes. Mesh are imported if they do not exist in the current terrain.
#### TexturePainter
Pain texture. Textures are imported if they do not exist in the current terrain.
This node is slow with many points, use extents modifier and prune to improve performance.
**Note**: Painted textures are not cleared, previously painted textures are overwritten.
## Performance
This plugin uses threads and should perform well up to a certain size, but you do
need a good amount of RAM to generate large environments. When you run into problems,
consider using multiple Foliage3D nodes to split up generation.
## Contributing
UX and performance improvements are welcome. This plugin is inspired by Unreal PCG,
however we do not intend to create an exact clone. Features are welcome as well,
but justifications should be provided if they deviate meaningfully from PCG.
@@ -1,6 +0,0 @@
[plugin]
name="Foliage3D"
description="Procedural foliage generation for Terrain3D"
author="Jakob Gillich"
version="0.1.0"
script="src/plugin.gd"
@@ -1,47 +0,0 @@
class_name Foliage3DBounds
var shapes: Array[CollisionShape3D]
#var exclusions: Array[CollisionShape3D]
var aabb: AABB
func set_shapes(p_shapes: Array[CollisionShape3D]):
aabb = AABB()
shapes = p_shapes
for shape in p_shapes:
if shape.shape == null:
continue
var shape_aabb = get_aabb(shape.global_position, shape.shape)
if aabb.position == Vector3.ZERO:
aabb = shape_aabb
else:
aabb = aabb.merge(shape_aabb)
func contains(position: Vector3) -> bool:
for shape in shapes:
if shape_contains(position, shape):
return true
return false
func shape_contains(position: Vector3, shape: CollisionShape3D) -> bool:
if shape.shape is BoxShape3D:
var min_corner = shape.global_position - shape.shape.extents
var max_corner = shape.global_position + shape.shape.extents
return position.x >= min_corner.x and position.x <= max_corner.x and \
position.y >= min_corner.y and position.y <= max_corner.y and \
position.z >= min_corner.z and position.z <= max_corner.z
elif shape.shape is SphereShape3D:
return position.distance_to(shape.global_position) <= shape.shape.radius
return false
func get_aabb(position: Vector3, shape: Shape3D) -> AABB:
if shape is BoxShape3D:
return AABB(position - shape.extents, shape.size)
elif shape is SphereShape3D:
var radius = Vector3(shape.radius, shape.radius, shape.radius)
return AABB(position - radius, radius * 2)
#elif shape is CapsuleShape3D:
#return AABB(position, Vector3(shape.radius * 2, shape.height + shape.radius * 2, shape.radius * 2))
return AABB(position, Vector3.ZERO)
@@ -1 +0,0 @@
uid://dk4c8vpi21hxp
@@ -1,169 +0,0 @@
class_name Foliage3DExecutor
class Context:
var bounds: Foliage3DBounds
var _data: Dictionary[String, Dictionary]
var _data_mut: Mutex = Mutex.new()
var _terrain: Terrain3D
var _terrain_mut: Mutex = Mutex.new()
var _finalized: Array[String]
var _finalized_mut: Mutex = Mutex.new()
var _main: Array[Callable]
var _main_mut: Mutex = Mutex.new()
func _init(terrain: Terrain3D, bounds: Foliage3DBounds):
_terrain = terrain
self.bounds = bounds
func for_node(key: String) -> NodeContext:
return NodeContext.new(self, key)
func duplicate(key: String) -> Dictionary:
_data_mut.lock()
var data = _data.get(key, {}).duplicate(true)
_data_mut.unlock()
return data
func mutate(key: String, fn: Callable) :
_data_mut.lock()
fn.call(_data.get_or_add(key, {}))
_data_mut.unlock()
func with_terrain(fn: Callable) -> Variant:
_terrain_mut.lock()
var res = fn.call(_terrain)
_terrain_mut.unlock()
return res
func with_terrain_main(fn: Callable) -> void:
push_main(with_terrain.bind(fn))
func finalize(key: String) -> Variant:
_finalized_mut.lock()
if _finalized.has(key):
_finalized_mut.unlock()
return false
_finalized.append(key)
_finalized_mut.unlock()
_data_mut.lock()
var data = _data.get(key, {})
_data_mut.unlock()
return data
func push_main(fn: Callable) -> void:
_main.append(fn)
func pop_main() -> Variant:
return _main.pop_back()
class NodeContext:
var _root: Context
var _key: String
var bounds: Foliage3DBounds:
get:
return _root.bounds
func _init(context: Context, key: String):
_root = context
_key = key
func duplicate() -> Dictionary:
return _root.duplicate(_key)
func mutate(fn: Callable) -> void:
_root.mutate(_key, fn)
func with_terrain(fn: Callable) -> Variant:
return _root.with_terrain(fn)
func with_terrain_main(fn: Callable) -> void:
return _root.with_terrain_main(fn)
func finalize() -> Variant:
return _root.finalize(_key)
func push_main(fn: Callable) -> void:
_root.push_main(fn)
var ctx: Context
var all_nodes: Dictionary[String, Foliage3DNode]
var remaining_nodes: Dictionary[String, Foliage3DNode]
var connections: Array[Dictionary]
var threads: Dictionary[String, Thread]
func _init(p_ctx: Context, p_nodes: Dictionary[String, Foliage3DNode], p_connections: Array[Dictionary]):
ctx = p_ctx
connections = p_connections.duplicate()
all_nodes = p_nodes
func execute():
var total = Time.get_ticks_msec()
var durations: Dictionary[String, int]
for connection in connections:
var from: Foliage3DNode = all_nodes[connection["from_node"]]
var to: Foliage3DNode = all_nodes[connection["to_node"]]
if from == null or to == null:
push_error("bad node connection")
return
to.inputs[connection["to_port"]].append([connection["from_port"], from])
for fname in ["generate", "post_generate"]:
remaining_nodes = all_nodes.duplicate()
while remaining_nodes.size() > 0:
for name in threads.keys():
var thread = threads[name]
if not thread.is_alive():
connections = connections.filter(func(d: Dictionary): return d["from_node"] != name)
remaining_nodes.erase(name)
thread.wait_to_finish()
threads.erase(name)
durations[name] = Time.get_ticks_msec() - durations[name]
# TODO max threads config
for i in range(4 - threads.size()):
var name := get_next()
if name.is_empty():
break
var thread = Thread.new()
var node = remaining_nodes[name]
var fn = node[fname].bind(ctx.for_node(node.type()))
thread.start(fn)
threads[name] = thread
durations[name] = Time.get_ticks_msec()
var fn = ctx.pop_main()
while fn != null:
fn.call()
fn = ctx.pop_main()
OS.delay_msec(10)
threads.clear()
print_stats(Time.get_ticks_msec() - total, durations)
func print_stats(total: int, durations: Dictionary[String, int]):
var by_node: Dictionary[String, int]
for name in durations.keys():
var type = all_nodes[name].type()
by_node[type] = by_node.get(type, 0) + durations[name]
var keys = by_node.keys()
keys.sort_custom(func(a, b): return by_node[a] > by_node[b])
var bottom3 = keys.slice(0, 3).map(func(k): return "%s in %dms" % [k, by_node[k]])
var text = "Foliage3D generation completed in %dms (bottom 3: %s, %s, %s)" % ([total] + bottom3)
print_debug(text)
func get_next() -> String:
for name in remaining_nodes.keys():
if threads.keys().has(name):
continue
if connections.filter(func(d: Dictionary): return d["to_node"] == name).is_empty():
return name
return ""
@@ -1 +0,0 @@
uid://trswuoqp2ob6
@@ -1,48 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2.5"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-leaf-icon lucide-leaf"
version="1.1"
id="svg2"
sodipodi:docname="foliage3d.svg"
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs2" />
<sodipodi:namedview
id="namedview2"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="17.088414"
inkscape:cx="-1.8726138"
inkscape:cy="19.135772"
inkscape:window-width="1720"
inkscape:window-height="1371"
inkscape:window-x="20"
inkscape:window-y="20"
inkscape:window-maximized="0"
inkscape:current-layer="svg2" />
<path
d="M11 20A7 7 0 0 1 9.8 6.1C15.5 5 17 4.48 19 2c1 2 2 4.18 2 8 0 5.5-4.78 10-10 10Z"
id="path1"
style="stroke:#fc7f7f;stroke-opacity:1" />
<path
d="M2 21c0-3 1.85-5.36 5.08-6C9.5 14.52 12 13 13 12"
id="path2"
style="stroke:#fc7f7f;stroke-opacity:1" />
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

@@ -1,43 +0,0 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://wf16dssf81mf"
path="res://.godot/imported/foliage3d.svg-6ac372c3b956f2b6bc796ca56aa78c19.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/foliage_3d/src/foliage3d.svg"
dest_files=["res://.godot/imported/foliage3d.svg-6ac372c3b956f2b6bc796ca56aa78c19.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false
@@ -1,142 +0,0 @@
@tool @icon("foliage3d.svg")
class_name Foliage3D extends Node3D
const Foliage3DGraphEdit := preload("graph_edit.gd")
static var NODES = {
"Difference": Foliage3DDifference,
"Prune": Foliage3DPrune,
"SurfaceSampler": Foliage3DSurfaceSampler,
"MeshSpawner": Foliage3DMeshSpawner,
"Transform": Foliage3DTransform,
"Filter": Foliage3DFilter,
"FilterPoint": Foliage3DFilterPoint,
"Slice": Foliage3DSlice,
"ExtentsModifier": Foliage3DExtentsModifier,
"TexturePainter": Foliage3DTexturePainter,
}
signal graph_changed()
@export_tool_button("Generate", "Callable") var _gen = generate
@export_tool_button("Clear", "Callable") var _clear = clear
@export_tool_button("Save", "Callable") var _save = save
@export var auto_generate: bool = true
@export var auto_save: bool = false
@export var graph: Foliage3DGraph:
set(value):
graph = value
graph_changed.emit()
# region>mesh>transform
@export var generated: Dictionary[Vector2i, Dictionary] = {}
var terrain: Terrain3D
var timer: Timer
var num_timer: int
var bounds := Foliage3DBounds.new()
var edit: Foliage3DGraphEdit
func _ready() -> void:
if not get_parent() is Terrain3D:
return
terrain = get_parent()
timer = Timer.new()
timer.wait_time = 1.0
timer.one_shot = true
timer.timeout.connect(generate)
add_child(timer)
set_notify_transform(true)
update_bounds()
#func _exit_tree() -> void:
#if graph != null:
#graph.changed.disconnect(queue_gen)
func create_edit() -> Foliage3DGraphEdit:
edit = Foliage3DGraphEdit.new(graph, terrain, bounds)
edit.changed.connect(queue_generate)
edit.mesh_xforms_added.connect(func(region: Vector2i, mesh: int, xforms: Array[Transform3D]):
generated.get_or_add(region, {}).get_or_add(mesh, []).append_array(xforms)
)
return edit
func update_bounds():
var shapes: Array[CollisionShape3D]
for child in get_children():
if child is CollisionShape3D:
shapes.append(child)
bounds.set_shapes(shapes)
func _notification(what):
match what:
NOTIFICATION_TRANSFORM_CHANGED:
queue_generate()
func _get_configuration_warnings():
if terrain == null:
return ["Foliage3D must be child of Terrain3D"]
return []
func queue_generate():
if not auto_generate:
return
if timer != null:
timer.start()
func generate():
update_bounds()
clear()
edit.generate()
if auto_save:
save()
func clear():
# https://terrain3d.readthedocs.io/en/latest/api/class_terrain3dregion.html#class-terrain3dregion-property-instances
for region_loc in generated.keys():
var region = terrain.data.get_region(region_loc)
if region == null:
continue
region.modified = true
var region_generated = generated[region_loc]
var instances = region.instances
for mesh in instances.keys():
if not region_generated.has(mesh):
continue
var mesh_generated = region_generated[mesh]
var mesh_cells = instances[mesh]
for cell in mesh_cells.keys():
var arr = mesh_cells[cell]
if arr.is_empty():
continue
var xforms = arr[0]
var filtered = xforms.filter(func(xform: Transform3D) -> bool:
return not mesh_generated.has(xform)
)
if filtered.is_empty():
mesh_cells.erase(cell)
else:
arr[0] = filtered
generated = {}
terrain.instancer.update_mmis(true)
func save():
terrain.data.save_directory(terrain.data_directory)
func _validate_property(property: Dictionary):
if property.name in ["generated"]:
property.usage = PROPERTY_USAGE_NO_EDITOR
@@ -1 +0,0 @@
uid://smqrc7uef45a
@@ -1,6 +0,0 @@
@tool
class_name Foliage3DGraph extends Resource
@export var nodes: Array[Dictionary]
@export var connections: Array[Dictionary]
@@ -1 +0,0 @@
uid://tkade2qgt1mn
@@ -1,121 +0,0 @@
@tool
extends GraphEdit
const Foliage3DGraphEditNode = preload("graph_edit_node.gd")
signal changed()
signal mesh_xforms_added(region: Vector2i, mesh: int, xforms: Array[Vector3])
@onready var node_popup: Window = preload("node_popup.tscn").instantiate()
var resource: Foliage3DGraph
var terrain: Terrain3D
var bounds: Foliage3DBounds
func _init(p_resource: Foliage3DGraph, p_terrain: Terrain3D, p_bounds: Foliage3DBounds):
resource = p_resource
terrain = p_terrain
bounds = p_bounds
size_flags_vertical = Control.SIZE_EXPAND_FILL
size_flags_horizontal = Control.SIZE_EXPAND_FILL
func _ready():
for params in resource.nodes:
var node = create_node(params["resource_name"], params)
add_child(node)
for connection in resource.connections:
connection["from_node"] = connection["from_node"].validate_node_name()
connection["to_node"] = connection["to_node"].validate_node_name()
var err = connect_node(connection["from_node"], connection["from_port"], connection["to_node"], connection["to_port"])
if err != OK:
push_error("foliage: connect_node error %d" % err)
add_child(node_popup)
node_popup.node_created.connect(_on_node_created)
popup_request.connect(_show_add_node_popup)
connection_request.connect(_on_connection_request)
delete_nodes_request.connect(_on_delete_nodes_request)
disconnection_request.connect(_on_disconnection_request)
end_node_move.connect(_on_end_node_move)
node_selected.connect(_on_node_selected)
add_valid_connection_type(TYPE_TRANSFORM3D, TYPE_TRANSFORM3D)
right_disconnects = true
func create_node(type: String, params: Dictionary = {}) -> Foliage3DGraphEditNode:
var node = Foliage3DGraphEditNode.new(type, params)
node.changed.connect(func():
save()
changed.emit()
)
node.mesh_xforms_added.connect(mesh_xforms_added.emit)
return node
func generate():
var nodes: Dictionary[String, Foliage3DNode]
for child in get_children():
if child is Foliage3DGraphEditNode:
nodes[str(child.name)] = child.node
var ctx = Foliage3DExecutor.Context.new(terrain, bounds)
var executor = Foliage3DExecutor.new(ctx, nodes, connections)
# TODO display "generating..." window with option to cancel
executor.execute()
func save():
resource.nodes = []
resource.connections = connections
for node in get_children():
if node is Foliage3DGraphEditNode:
var dict = {
"name": node.get_name().validate_node_name(),
"position_offset": node.position_offset
}
for prop in node.node.get_property_list():
if (prop.usage & PROPERTY_USAGE_STORAGE) == 0:
continue
if ["terrain", "slots", "script"].has(prop["name"]):
continue
dict[prop["name"]] = node.node.get(prop["name"])
resource.nodes.append(dict)
if not resource.resource_path.is_empty():
ResourceSaver.save(resource, resource.resource_path)
func _on_node_selected(node):
EditorInterface.edit_resource(node.node)
func _on_node_created(type: String, node_offset: Vector2):
var node = create_node(type)
node.position_offset = node_offset
add_child(node)
save()
func _on_connection_request(from: StringName, fport: int, to: StringName, tport: int):
if from == to:
return
connect_node(from, fport, to, tport)
save()
changed.emit()
func _on_delete_nodes_request(nodes: Array[StringName]) -> void:
for node in nodes:
get_node(NodePath(node)).free()
save()
changed.emit()
func _on_disconnection_request(from_node: StringName, from_port: int, to_node: StringName, to_port: int) -> void:
disconnect_node(from_node, from_port, to_node, to_port)
save()
changed.emit()
func _on_end_node_move():
save()
func _show_add_node_popup(click_position: Vector2i) -> void:
node_popup.node_position = (get_local_mouse_position() + scroll_offset) / zoom
node_popup.popup(Rect2i(Vector2i(DisplayServer.mouse_get_position()), node_popup.size))
@@ -1 +0,0 @@
uid://rxhkt40jgqcs
@@ -1,48 +0,0 @@
@tool
extends GraphNode
signal changed()
signal mesh_xforms_added(region: Vector2i, mesh: int, xforms: Array[Vector3])
var node: Foliage3DNode
func _init(type: String, props: Dictionary = {}):
node = Foliage3D.NODES[type].new()
node.changed.connect(changed.emit)
node.mesh_xforms_added.connect(mesh_xforms_added.emit)
title = type
if not props.is_empty():
name = props["name"]
position_offset = props["position_offset"]
for i in range(max(node.get_inputs().size(), node.get_outputs().size())):
var hbox := HBoxContainer.new()
var has_input: bool
var input_type = TYPE_VECTOR3
if node.get_inputs().size() > i:
has_input = true
input_type = node.get_inputs()[i]
var label = Label.new()
label.text = "in"
hbox.add_child(label)
var has_output: bool
var output_type = TYPE_VECTOR3
if node.get_outputs().size() > i:
has_output = true
output_type = node.get_outputs()[i]
var label = Label.new()
label.text = "out"
label.size_flags_horizontal = Control.SIZE_SHRINK_END | Control.SIZE_EXPAND
hbox.add_child(label)
set_slot(i, has_input, input_type, Color.BLUE, has_output, output_type, Color.BLUE)
add_child(hbox)
for prop in node.get_property_list():
if (prop.usage & PROPERTY_USAGE_STORAGE) == 0:
continue
# TODO not sure why all C++ props are included
if ["terrain", "slots", "script", "resource_name"].has(prop["name"]):
continue
if props.has(prop["name"]):
node.set(prop["name"], props[prop["name"]])
@@ -1 +0,0 @@
uid://i5tdnb5mu44q
@@ -1,7 +0,0 @@
class_name Foliage3DEditorInspectorPlugin extends EditorInspectorPlugin
func _can_handle(object):
return true
func _parse_property(object, type, name, hint_type, hint_string, usage_flags, wide):
return false
@@ -1 +0,0 @@
uid://cw48v08km172g
@@ -1,7 +0,0 @@
@tool
class_name Foliage3DMeshAsset extends Resource
@export var scene: PackedScene
# TODO
# var weight: float
@@ -1 +0,0 @@
uid://gvg7dvp2ie3g
@@ -1,47 +0,0 @@
@tool
extends Window
signal node_created(String, Vector2i)
@onready var tree: Tree = %Tree
var node_position: Vector2
func _ready() -> void:
refresh()
about_to_popup.connect(refresh)
close_requested.connect(hide)
focus_exited.connect(hide)
tree.item_activated.connect(_on_item_activated)
tree.item_selected.connect(_on_item_selected)
tree.nothing_selected.connect(_on_nothing_selected)
%CreateButton.pressed.connect(_on_item_activated)
%CancelButton.pressed.connect(hide)
func refresh():
tree.clear()
var root = tree.create_item()
for type in Foliage3D.NODES.keys():
var item = tree.create_item(root)
item.set_text(0, type)
#item.set_tooltip_text(0, "description")
item.set_metadata(0, type)
func _on_item_selected() -> void:
var item = tree.get_selected()
if item == null:
_on_nothing_selected()
return
%CreateButton.disabled = false
func _on_nothing_selected() -> void:
%CreateButton.disabled = true
func _on_item_activated() -> void:
var selected = tree.get_selected()
if selected == null:
return
node_created.emit(selected.get_metadata(0), node_position)
hide()
@@ -1 +0,0 @@
uid://besoxm36sku3c
@@ -1,67 +0,0 @@
[gd_scene load_steps=2 format=3 uid="uid://bd3iulla58u3y"]
[ext_resource type="Script" uid="uid://besoxm36sku3c" path="res://addons/foliage_3d/src/node_popup.gd" id="1_kwkgp"]
[node name="NodePopup" type="Window"]
title = "Create node"
size = Vector2i(300, 400)
visible = false
transient = true
popup_window = true
script = ExtResource("1_kwkgp")
[node name="PanelContainer" type="PanelContainer" parent="."]
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="MarginContainer" type="MarginContainer" parent="PanelContainer"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
theme_override_constants/margin_left = 14
theme_override_constants/margin_top = 14
theme_override_constants/margin_right = 14
theme_override_constants/margin_bottom = 14
[node name="VBoxContainer" type="VBoxContainer" parent="PanelContainer/MarginContainer"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="Search" type="LineEdit" parent="PanelContainer/MarginContainer/VBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
placeholder_text = "Search"
clear_button_enabled = true
caret_blink = true
caret_blink_interval = 0.5
[node name="Tree" type="Tree" parent="PanelContainer/MarginContainer/VBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
hide_root = true
[node name="ActionContainer" type="HBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
[node name="CancelButton" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer/ActionContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
text = "Cancel"
[node name="CreateButton" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer/ActionContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
disabled = true
text = "Create"
@@ -1,60 +0,0 @@
#include "difference.hpp"
#include <godot_cpp/core/class_db.hpp>
using namespace godot;
Foliage3DDifference::Foliage3DDifference()
{
// Foliage3DSlot* inout = memnew(Foliage3DSlot);
// inout->left->type = Foliage3DPort::Type::POINT;
// inout->right->type = Foliage3DPort::Type::POINT;
// _slots.append(inout);
}
Foliage3DDifference::~Foliage3DDifference()
{
}
Array Foliage3DDifference::_execute(TypedArray<Foliage3DPoint> p_input, TypedArray<Foliage3DPoint> p_diff)
{
TypedArray<Foliage3DPoint> points = p_input.duplicate();
for (int i = p_input.size() - 1; i >= 0; i--) {
Foliage3DPoint* p1 = cast_to<Foliage3DPoint>(p_input[i]);
for (int j = 0; j < p_diff.size(); j++) {
Foliage3DPoint* p2 = cast_to<Foliage3DPoint>(p_diff[j]);
if (p1->intersects(p2))
{
points.remove_at(i);
break;
}
}
}
Array result;
result.append(points);
return result;
}
TypedArray<int> Foliage3DDifference::get_inputs()
{
TypedArray<int> inputs;
inputs.append(Variant::Type::TRANSFORM3D);
inputs.append(Variant::Type::TRANSFORM3D);
return inputs;
}
TypedArray<int> Foliage3DDifference::get_outputs()
{
TypedArray<int> outputs;
outputs.append(Variant::Type::TRANSFORM3D);
return outputs;
}
void Foliage3DDifference::_bind_methods()
{
ClassDB::bind_method(D_METHOD("_execute"), &Foliage3DDifference::_execute);
ClassDB::bind_method(D_METHOD("get_inputs"), &Foliage3DDifference::get_inputs);
ClassDB::bind_method(D_METHOD("get_outputs"), &Foliage3DDifference::get_outputs);
}
@@ -1,13 +0,0 @@
@tool
class_name Foliage3DDifference extends Foliage3DNode
func get_inputs() -> Array[int]:
return [TYPE_POINT, TYPE_POINT]
func get_outputs() -> Array[int]:
return [TYPE_POINT]
# removes all points within the extents of diff
func _generate(ctx: Foliage3DExecutor.NodeContext, input: Array[Foliage3DPoint] = [], diff: Array[Foliage3DPoint] = []) -> Array:
var result = Foliage3DPoint.Grid.new(diff).difference(input)
return [result]
@@ -1 +0,0 @@
uid://dljr6ntao15cj
@@ -1,23 +0,0 @@
#pragma once
#include "point.hpp"
#include "node.hpp"
using namespace godot;
class Foliage3DDifference : public Foliage3DNode
{
GDCLASS(Foliage3DDifference, Foliage3DNode);
protected:
static void _bind_methods();
Array _execute(TypedArray<Foliage3DPoint> p_input, TypedArray<Foliage3DPoint> p_diff);
public:
Foliage3DDifference();
~Foliage3DDifference();
TypedArray<int> get_inputs();
TypedArray<int> get_outputs();
};
@@ -1,33 +0,0 @@
class_name Foliage3DExtentsModifier extends Foliage3DNode
enum Mode {
SET,
MULTIPLY,
ADD
}
@export var point_extents: Vector3 = Vector3(1, 1, 1):
set(value):
point_extents = value
changed.emit()
@export var mode: Mode
func get_inputs() -> Array[int]:
return [TYPE_POINT]
func get_outputs() -> Array[int]:
return [TYPE_POINT]
func _generate(ctx: Foliage3DExecutor.NodeContext, input: Array[Foliage3DPoint]) -> Array:
var points: Array[Foliage3DPoint]
points.assign(input.map(func(p): return p.duplicate()))
for point in points:
match mode:
Mode.SET:
point.extents = point_extents
Mode.MULTIPLY:
point.extents *= point_extents
Mode.ADD:
point.extents += point_extents
return [points]
@@ -1 +0,0 @@
uid://cp1twl3xj43pw
@@ -1,37 +0,0 @@
@tool
class_name Foliage3DFilter extends Foliage3DNode
@export var expression: String = "true":
set(value):
expression = value
changed.emit()
# TODO accept any object type
func get_inputs() -> Array[int]:
return [TYPE_POINT]
func get_outputs() -> Array[int]:
return [TYPE_POINT, TYPE_POINT]
func _generate(ctx: Foliage3DExecutor.NodeContext, input: Array[Foliage3DPoint]) -> Array:
var out: Array[Foliage3DPoint]
var rest: Array[Foliage3DPoint]
var exp = Expression.new()
var err = exp.parse(expression, ["p"])
if err != OK:
push_warning("foliage: bad expression '%s'" % expression)
return [out, rest]
for point in input:
var res = exp.execute([point])
if res is bool:
if res:
out.append(point)
else:
rest.append(point)
else:
push_warning("foliage: bad expression '%s'" % expression)
break
return [out, rest]
@@ -1 +0,0 @@
uid://b0giscjsnwugo
@@ -1,64 +0,0 @@
@tool
class_name Foliage3DFilterPoint extends Foliage3DNode
@export var position_min: Vector3:
set(value):
position_min = value
changed.emit()
@export var position_max: Vector3:
set(value):
position_max = value
changed.emit()
@export var rotation_min: Vector3:
set(value):
rotation_min = value
changed.emit()
@export var rotation_max: Vector3:
set(value):
rotation_max = value
changed.emit()
func get_inputs() -> Array[int]:
return [TYPE_POINT]
func get_outputs() -> Array[int]:
return [TYPE_POINT, TYPE_POINT]
func _generate(ctx: Foliage3DExecutor.NodeContext, input: Array[Foliage3DPoint]) -> Array:
var result: Array[Foliage3DPoint]
var rest: Array[Foliage3DPoint]
for point in input:
if position_min != Vector3.ZERO or position_max != Vector3.ZERO:
if point.transform.origin.clamp(vec_defaults(position_min, -INF), vec_defaults(position_max)) != point.transform.origin:
rest.append(point)
continue
if rotation_min != Vector3.ZERO or rotation_max != Vector3.ZERO:
var rad_min = vec_defaults(rotation_min, 0.0) * deg_to_rad(1)
var rad_max = vec_defaults(rotation_max, 360.0) * deg_to_rad(1)
var rad = point.transform.basis.get_euler()
if not filter_rotation_vector(rad, rad_min, rad_max):
rest.append(point)
continue
result.append(point)
return [result, rest]
func filter_rotation_vector(value: Vector3, min: Vector3, max: Vector3):
for axis in ["x", "y", "z"]:
if value[axis] < 0:
value[axis] *= -1
if value[axis] > max[axis] or value[axis] < min[axis]:
return false
return true
func vec_defaults(vec: Vector3, default = INF) -> Vector3:
return Vector3(
vec.x if vec.x != 0.0 else default,
vec.y if vec.y != 0.0 else default,
vec.z if vec.z != 0.0 else default
)
@@ -1 +0,0 @@
uid://ca55qfd76hqul
@@ -1,42 +0,0 @@
#include "graph.hpp"
#include <godot_cpp/core/class_db.hpp>
// using namespace godot;
// Foliage3DGraph::Foliage3DGraph()
// {
// }
// Foliage3DGraph::~Foliage3DGraph()
// {
// }
// void Foliage3DGraph::load(Array nodes, Array connections)
// {
// _nodes = TypedArray<Foliage3DNode>();
// for (int i = 0; i < nodes.size(); i++) {
// Dictionary dict = nodes[i];
// String str = dict["node"];
// std::string node(str.utf8().get_data());
// switch(node) {
// case "foo":
// // code block
// break;
// case y:
// // code block
// break;
// default:
// // code block
// }
// }
// }
// void Foliage3DGraph::_bind_methods()
// {
// // ClassDB::bind_method(D_METHOD("gen", "input", "diff"), &Foliage3DGraph::gen);
// }
@@ -1,22 +0,0 @@
#pragma once
#include "point.hpp"
#include "node.hpp"
using namespace godot;
// class Foliage3DGraph : public Object
// {
// GDCLASS(Foliage3DGraph, Object);
// protected:
// static void _bind_methods();
// TypedArray<Foliage3DNode> _nodes;
// public:
// Foliage3DGraph();
// ~Foliage3DGraph();
// void load(Array nodes, Array connections);
// Dictionary gen(Terrain3D terrain);
// };
@@ -1,86 +0,0 @@
@tool
class_name Foliage3DMeshSpawner extends Foliage3DNode
@export var assets: Array[Foliage3DMeshAsset]:
set(value):
assets = value
changed.emit()
func get_inputs() -> Array[int]:
return [TYPE_POINT]
func get_outputs() -> Array[int]:
return []
func _generate(ctx: Foliage3DExecutor.NodeContext, points: Array[Foliage3DPoint]) -> Array:
var ids: Array[int]
for i in range(assets.size()):
if assets[i].scene == null:
continue
var id = ctx.with_terrain(get_or_create_mesh.bind(assets[i].scene))
ids.append(id)
if ids.is_empty():
return []
var xforms: Array[Array]
for i in range(ids.size()):
xforms.append([] as Array[Transform3D])
for i in range(0, points.size(), ids.size()):
for j in range(min(ids.size(), points.size()-i)):
xforms[j].append(points[i+j].transform)
for i in range(ids.size()):
ctx.with_terrain(add_mesh_xforms.bind(ctx, ids[i], xforms[i]))
return []
func get_or_create_mesh(terrain: Terrain3D, mesh: PackedScene) -> int:
var mesh_count = terrain.assets.get_mesh_count()
for i in range(mesh_count):
var asset = terrain.assets.get_mesh_asset(i)
if asset == null or asset.scene_file == null:
continue
if mesh.resource_path == asset.scene_file.resource_path:
return i
var asset := Terrain3DMeshAsset.new()
asset.scene_file = mesh
terrain.assets.set_mesh_asset(mesh_count, asset)
return mesh_count
func add_mesh_xforms(terrain: Terrain3D, ctx: Foliage3DExecutor.NodeContext, mesh: int, xforms: Array[Transform3D]) -> void:
if mesh >= terrain.assets.get_mesh_count():
push_warning("foliage: mesh %d out of range" % mesh)
return
var dict: Dictionary = {}
var asset := terrain.assets.get_mesh_asset(mesh)
for i in range(xforms.size()):
var xform = xforms[i]
xform.origin += xform.basis.y * asset.height_offset
var loc = terrain.data.get_region_location(xform.origin)
if not terrain.data.has_region(loc):
terrain.data.add_region_blank(loc)
var region: Array[Transform3D] = dict.get_or_add(loc, [] as Array[Transform3D])
region.append(xform)
for loc in dict.keys():
var colors: PackedColorArray = []
colors.resize(dict[loc].size())
colors.fill(Color.WHITE)
var region = terrain.data.get_region(loc)
region.modified = true
var global_local_offset = Vector3(loc.x, 0, loc.y) * region.region_size * terrain.vertex_spacing
for i in range(dict[loc].size()):
dict[loc][i].origin -= global_local_offset
ctx.with_terrain_main(func(terrain: Terrain3D):
terrain.instancer.append_region(region, mesh, dict[loc], colors)
)
mesh_xforms_added.emit(loc, mesh, dict[loc])
@@ -1 +0,0 @@
uid://b3ldpkr2ml5lo
@@ -1,126 +0,0 @@
#include "node.hpp"
#include <godot_cpp/core/class_db.hpp>
using namespace godot;
Foliage3DNode::Foliage3DNode()
{
_terrain = memnew(Foliage3DTerrain);
// promise<Variant> promise;
// _promise = &promise;
// future<Variant> future;
// _result = &future.share();
// int num_inputs;
// for (int i = 0; i < _slots.size(); i++)
// {
// Foliage3DSlot* slot = cast_to<Foliage3DSlot>(_inputs[i]);
// if (slot->left) {
// num_inputs++;
// }
// }
// _inputs.resize(num_inputs);
}
Foliage3DNode::~Foliage3DNode()
{
}
void Foliage3DNode::execute()
{
if (_inputs.size() != get_inputs().size())
{
// TODO optional inputs
ERR_PRINT("input count mismatch");
return;
}
Array inputs;
for (int i = _inputs.size() - 1; i >= 0; i--)
{
Foliage3DNode* node = cast_to<Foliage3DNode>(_inputs[i]);
Variant result = node->get_result();
if (result.get_type() != Variant::Type::ARRAY)
{
ERR_PRINT("bad result type");
return;
}
Array arr = result;
// TODO support multiple out ports
inputs.append(arr[0]);
}
//_result = callv("_execute", inputs);
// _promise->set_value()
// _promise->set_value(result);
}
void Foliage3DNode::set_params(Dictionary p_dict)
{
Array keys = p_dict.keys();
for (int i = 0; i < keys.size(); i++) {
String key = keys[i];
if (key == "node")
{
continue;
}
set(keys[i], p_dict[keys[i]]);
}
}
void Foliage3DNode::set_input(Variant p_node, int slot)
{
// ASSERT(slot > _inputs.size(), void());
Foliage3DNode* node = cast_to<Foliage3DNode>(p_node);
_inputs[slot] = node;
}
// void Foliage3DNode::set_slots(TypedArray<Foliage3DSlot> p_slots)
// {
// _slots = p_slots;
// }
// TypedArray<Foliage3DSlot> Foliage3DNode::get_slots()
// {
// return _slots;
// }
TypedArray<int> Foliage3DNode::get_inputs()
{
TypedArray<int> inputs;
return inputs;
}
TypedArray<int> Foliage3DNode::get_outputs()
{
TypedArray<int> outputs;
return outputs;
}
void Foliage3DNode::_bind_methods()
{
ClassDB::bind_method(D_METHOD("get_terrain"), &Foliage3DNode::get_terrain);
ClassDB::bind_method(D_METHOD("set_terrain", "terrain"), &Foliage3DNode::set_terrain);
// ClassDB::bind_method(D_METHOD("get_slots"), &Foliage3DNode::get_slots);
// ClassDB::bind_method(D_METHOD("set_slots", "slots"), &Foliage3DNode::set_slots);
// ClassDB::bind_method(D_METHOD("get_params"), &Foliage3DNode::get_params);
ClassDB::bind_method(D_METHOD("set_params", "params"), &Foliage3DNode::set_params);
ClassDB::bind_method(D_METHOD("set_input", "node", "slot"), &Foliage3DNode::set_input);
ClassDB::bind_method(D_METHOD("execute"), &Foliage3DNode::execute);
GDVIRTUAL_BIND(get_inputs);
GDVIRTUAL_BIND(get_outputs);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "terrain"), "set_terrain", "get_terrain");
// ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "slots"), "set_slots", "get_slots");
}
@@ -1,56 +0,0 @@
@tool
class_name Foliage3DNode extends Resource
enum {
TYPE_POINT = 100
}
signal mesh_xforms_added(region: Vector2i, mesh: int, xforms: Array[Vector3])
var inputs: Array[Array]
var result: Array
func _init():
inputs.resize(get_inputs().size())
resource_name = type()
for i in range(inputs.size()):
inputs[i] = []
func get_inputs() -> Array[int]:
return []
func get_outputs() -> Array[int]:
return []
func generate(ctx: Foliage3DExecutor.NodeContext):
if OS.get_thread_caller_id() != OS.get_main_thread_id():
Thread.set_thread_safety_checks_enabled(false)
var args = []
for i in range(inputs.size()):
for j in inputs[i]:
var port = j[0]
var node = j[1]
if args.size() <= i:
args.append(node.result[port].duplicate())
else:
args[i].append_array(node.result[port])
if args.size() != get_inputs().size():
return
args.push_front(ctx)
result = callv("_generate", args)
for i in range(inputs.size()):
inputs[i] = []
func post_generate(ctx: Foliage3DExecutor.NodeContext):
if not has_method("_post_generate"):
return
call("_post_generate", ctx)
func type() -> String:
return get_script().get_global_name().trim_prefix("Foliage3D")
@@ -1 +0,0 @@
uid://d1nqgvgqr3qao
@@ -1,51 +0,0 @@
#pragma once
#include "slot.hpp"
#include "terrain.hpp"
// #include <future>
#include <godot_cpp/classes/object.hpp>
#include <godot_cpp/variant/builtin_types.hpp>
#include <godot_cpp/core/gdvirtual.gen.inc>
using namespace std;
using namespace godot;
class Foliage3DNode : public Object
{
GDCLASS(Foliage3DNode, Object);
protected:
static void _bind_methods();
// TypedArray<Foliage3DSlot> _slots;
TypedArray<Foliage3DNode> _inputs;
Foliage3DTerrain* _terrain;
// promise<Variant>* _promise;
// shared_future<Variant>* _result;
Variant _result;
public:
Foliage3DNode();
~Foliage3DNode();
void execute();
virtual TypedArray<int> get_inputs();
GDVIRTUAL0R(TypedArray<int>, get_inputs);
virtual TypedArray<int> get_outputs();
GDVIRTUAL0R(TypedArray<int>, get_outputs);
void set_params(Dictionary p_dict);
// Dictionary get_params();
void set_input(Variant node, int slot);
Foliage3DTerrain* get_terrain() { return _terrain; };
void set_terrain(Foliage3DTerrain* p_terrain) { _terrain = p_terrain; };
Variant get_result() { return _result; };
};
@@ -1,57 +0,0 @@
#include "point.hpp"
#include <godot_cpp/core/class_db.hpp>
using namespace godot;
Foliage3DPoint::Foliage3DPoint()
{
}
// Foliage3DPoint::Foliage3DPoint(Transform3D p_transform, Vector3 p_size)
// {
// _transform = p_transform;
// _size = p_size;
// _update_aabb();
// }
Foliage3DPoint::~Foliage3DPoint()
{
}
void Foliage3DPoint::set_transform(Transform3D p_transform)
{
_transform = p_transform;
_update_aabb();
}
void Foliage3DPoint::set_size(Vector3 p_size)
{
_size = p_size;
_update_aabb();
}
bool Foliage3DPoint::intersects(Foliage3DPoint* p_point)
{
return _aabb.intersects(p_point->_aabb);
}
void Foliage3DPoint::_update_aabb()
{
Vector3 scaled_size = _size.operator*(_transform.basis.get_scale());
_aabb = AABB(_transform.origin.operator-(scaled_size.operator/(2)), scaled_size);
}
void Foliage3DPoint::_bind_methods()
{
ClassDB::bind_method(D_METHOD("get_transform"), &Foliage3DPoint::get_transform);
ClassDB::bind_method(D_METHOD("set_transform", "transform"), &Foliage3DPoint::set_transform);
ClassDB::bind_method(D_METHOD("get_size"), &Foliage3DPoint::get_size);
ClassDB::bind_method(D_METHOD("set_size", "size"), &Foliage3DPoint::set_size);
ClassDB::bind_method(D_METHOD("get_aabb"), &Foliage3DPoint::get_aabb);
ClassDB::bind_method(D_METHOD("intersects", "point"), &Foliage3DPoint::intersects);
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "transform"), "set_transform", "get_transform");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size"), "set_size", "get_size");
}
@@ -1,29 +0,0 @@
#pragma once
#include <godot_cpp/classes/object.hpp>
using namespace godot;
class Foliage3DPoint : public Object
{
GDCLASS(Foliage3DPoint, Object);
protected:
static void _bind_methods();
Transform3D _transform;
Vector3 _size;
AABB _aabb;
void _update_aabb();
public:
Foliage3DPoint();
// Foliage3DPoint(Transform3D p_transform, Vector3 p_size);
~Foliage3DPoint();
Transform3D get_transform() const { return _transform; }
void set_transform(Transform3D p_transform);
Vector3 get_size() const { return _size; }
void set_size(Vector3 p_size);
AABB get_aabb() const { return _aabb; }
bool intersects(Foliage3DPoint* p_input);
};
@@ -1,39 +0,0 @@
#include "port.hpp"
#include <godot_cpp/core/class_db.hpp>
using namespace godot;
Foliage3DPort::Foliage3DPort()
{
}
Foliage3DPort::~Foliage3DPort()
{
}
void Foliage3DPort::_bind_methods()
{
BIND_ENUM_CONSTANT(POINT);
BIND_ENUM_CONSTANT(VECTOR3);
BIND_ENUM_CONSTANT(FLOAT);
BIND_ENUM_CONSTANT(INT);
BIND_ENUM_CONSTANT(BOOL);
BIND_ENUM_CONSTANT(STRING);
BIND_ENUM_CONSTANT(NONE);
BIND_ENUM_CONSTANT(POSITION);
BIND_ENUM_CONSTANT(ROTATION);
ClassDB::bind_method(D_METHOD("get_type"), &Foliage3DPort::get_type);
ClassDB::bind_method(D_METHOD("set_type", "type"), &Foliage3DPort::set_type);
ClassDB::bind_method(D_METHOD("get_name"), &Foliage3DPort::get_name);
ClassDB::bind_method(D_METHOD("set_name", "name"), &Foliage3DPort::set_name);
ClassDB::bind_method(D_METHOD("get_hint"), &Foliage3DPort::get_hint);
ClassDB::bind_method(D_METHOD("set_hint", "hint"), &Foliage3DPort::set_hint);
ADD_PROPERTY(PropertyInfo(Variant::INT, "type"), "set_type", "get_type");
ADD_PROPERTY(PropertyInfo(Variant::INT, "hint"), "set_hint", "get_hint");
}
@@ -1,53 +0,0 @@
#pragma once
#include <godot_cpp/classes/object.hpp>
#include <godot_cpp/classes/global_constants.hpp>
#include <godot_cpp/core/binder_common.hpp>
using namespace godot;
class Foliage3DPort : public Object
{
GDCLASS(Foliage3DPort, Object);
public:
enum Type {
POINT,
VECTOR3,
FLOAT,
INT,
BOOL,
STRING,
};
enum TypeHint {
NONE,
POSITION,
ROTATION
};
protected:
static void _bind_methods();
public:
Foliage3DPort();
~Foliage3DPort();
Type type;
String name;
TypeHint hint;
Type get_type() const { return type; }
void set_type(Type p_type) { type = p_type; };
String get_name() const { return name; }
void set_name(String p_name) { name = p_name; };
TypeHint get_hint() const { return hint; }
void set_hint(TypeHint p_hint) { hint = p_hint; };
};
VARIANT_ENUM_CAST(Foliage3DPort::Type);
VARIANT_ENUM_CAST(Foliage3DPort::TypeHint);
@@ -1,58 +0,0 @@
#include "prune.hpp"
#include <godot_cpp/core/class_db.hpp>
using namespace godot;
Foliage3DPrune::Foliage3DPrune()
{
// Foliage3DSlot* inout = memnew(Foliage3DSlot);
// inout->left->type = Foliage3DPort::Type::POINT;
// inout->right->type = Foliage3DPort::Type::POINT;
// _slots.append(inout);
}
Foliage3DPrune::~Foliage3DPrune()
{
}
TypedArray<int> Foliage3DPrune::get_inputs()
{
TypedArray<int> inputs;
inputs.append(Variant::Type::TRANSFORM3D);
return inputs;
}
TypedArray<int> Foliage3DPrune::get_outputs()
{
TypedArray<int> outputs;
outputs.append(Variant::Type::TRANSFORM3D);
return outputs;
}
Array Foliage3DPrune::_execute(TypedArray<Foliage3DPoint> p_input)
{
TypedArray<Foliage3DPoint> points = p_input.duplicate();
for (int i = p_input.size() - 1; i >= 0; i--) {
Foliage3DPoint* p1 = cast_to<Foliage3DPoint>(p_input[i]);
for (int j = i - 1; j >= 0; j--) {
Foliage3DPoint* p2 = cast_to<Foliage3DPoint>(p_input[j]);
if (p1->intersects(p2))
{
points.remove_at(i);
break;
}
}
}
Array result;
result.append(points);
return result;
}
void Foliage3DPrune::_bind_methods()
{
ClassDB::bind_method(D_METHOD("_execute"), &Foliage3DPrune::_execute);
ClassDB::bind_method(D_METHOD("get_inputs"), &Foliage3DPrune::get_inputs);
ClassDB::bind_method(D_METHOD("get_outputs"), &Foliage3DPrune::get_outputs);
}
@@ -1,13 +0,0 @@
@tool
class_name Foliage3DPrune extends Foliage3DNode
func get_inputs() -> Array[int]:
return [TYPE_POINT]
func get_outputs() -> Array[int]:
return [TYPE_POINT]
# removes all points within the extents of self
func _generate(ctx: Foliage3DExecutor.NodeContext, input: Array[Foliage3DPoint]) -> Array:
var result = Foliage3DPoint.Grid.new(input).prune()
return [result]
@@ -1 +0,0 @@
uid://t37le0xtvd6r
@@ -1,23 +0,0 @@
#pragma once
#include "point.hpp"
#include "node.hpp"
using namespace godot;
class Foliage3DPrune : public Foliage3DNode
{
GDCLASS(Foliage3DPrune, Foliage3DNode);
protected:
static void _bind_methods();
Array _execute(TypedArray<Foliage3DPoint> p_input);
public:
Foliage3DPrune();
~Foliage3DPrune();
TypedArray<int> get_inputs();
TypedArray<int> get_outputs();
};
@@ -1,46 +0,0 @@
#include "register_types.h"
#include <gdextension_interface.h>
#include <godot_cpp/classes/engine.hpp>
#include "point.hpp"
#include "prune.hpp"
#include "difference.hpp"
#include "terrain.hpp"
void gdextension_initialize(ModuleInitializationLevel p_level)
{
if (p_level == MODULE_INITIALIZATION_LEVEL_SCENE)
{
ClassDB::register_class<Foliage3DTerrain>();
ClassDB::register_class<Foliage3DPort>();
ClassDB::register_class<Foliage3DSlot>();
ClassDB::register_class<Foliage3DNode>();
ClassDB::register_class<Foliage3DPoint>();
ClassDB::register_class<Foliage3DPrune>();
ClassDB::register_class<Foliage3DDifference>();
}
}
void gdextension_terminate(ModuleInitializationLevel p_level)
{
if (p_level == MODULE_INITIALIZATION_LEVEL_SCENE)
{
}
}
extern "C"
{
GDExtensionBool GDE_EXPORT gdextension_init(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization)
{
godot::GDExtensionBinding::InitObject init_obj(p_get_proc_address, p_library, r_initialization);
init_obj.register_initializer(gdextension_initialize);
init_obj.register_terminator(gdextension_terminate);
init_obj.set_minimum_library_initialization_level(MODULE_INITIALIZATION_LEVEL_SCENE);
return init_obj.init();
}
}
@@ -1,6 +0,0 @@
#pragma once
#include <godot_cpp/core/class_db.hpp>
void gdextension_initialize(godot::ModuleInitializationLevel p_level);
void gdextension_terminate(godot::ModuleInitializationLevel p_level);
@@ -1,40 +0,0 @@
@tool
class_name Foliage3DSlice extends Foliage3DNode
@export_range(0.0, 1.0) var weight: float = 0.5:
set(value):
weight = value
changed.emit()
@export var randomize: bool = true:
set(value):
randomize = value
changed.emit()
@export var seed: int:
set(value):
seed = value
changed.emit()
func get_inputs() -> Array[int]:
return [TYPE_POINT]
func get_outputs() -> Array[int]:
return [TYPE_POINT, TYPE_POINT]
func _generate(ctx: Foliage3DExecutor.NodeContext, input: Array[Foliage3DPoint]) -> Array:
var result = input.duplicate()
if randomize:
var rng = RandomNumberGenerator.new()
rng.seed = seed
array_shuffle(result, rng)
var index = roundi(remap(weight, 0.0, 1.0, 0, input.size()))
return [result.slice(0, index), result.slice(index, result.size())]
func array_shuffle(array: Array, rng: RandomNumberGenerator) -> void:
for i in range(array.size() - 2):
var j := rng.randi_range(i, array.size() - 1)
var tmp = array[i]
array[i] = array[j]
array[j] = tmp
@@ -1 +0,0 @@
uid://bqn17g3wl2nee
@@ -1,38 +0,0 @@
#include "slot.hpp"
#include <godot_cpp/core/class_db.hpp>
using namespace godot;
Foliage3DSlot::Foliage3DSlot()
{
left = memnew(Foliage3DPort);
right = memnew(Foliage3DPort);
}
Foliage3DSlot::~Foliage3DSlot()
{
}
void Foliage3DSlot::_bind_methods()
{
ClassDB::bind_method(D_METHOD("get_prop"), &Foliage3DSlot::get_prop);
ClassDB::bind_method(D_METHOD("set_prop", "prop"), &Foliage3DSlot::set_prop);
ClassDB::bind_method(D_METHOD("get_name"), &Foliage3DSlot::get_name);
ClassDB::bind_method(D_METHOD("set_name", "name"), &Foliage3DSlot::set_name);
ClassDB::bind_method(D_METHOD("get_left"), &Foliage3DSlot::get_left);
ClassDB::bind_method(D_METHOD("set_left", "slot"), &Foliage3DSlot::set_left);
ClassDB::bind_method(D_METHOD("get_right"), &Foliage3DSlot::get_right);
ClassDB::bind_method(D_METHOD("set_right", "slot"), &Foliage3DSlot::set_right);
ADD_PROPERTY(PropertyInfo(Variant::STRING, "prop"), "set_prop", "get_prop");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "name"), "set_name", "get_name");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "left"), "set_left", "get_left");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "right"), "set_right", "get_right");
}
@@ -1,39 +0,0 @@
#pragma once
#include "port.hpp"
#include <godot_cpp/classes/object.hpp>
using namespace godot;
class Foliage3DSlot : public Object
{
GDCLASS(Foliage3DSlot, Object);
protected:
static void _bind_methods();
public:
Foliage3DSlot();
~Foliage3DSlot();
String prop;
String name;
Foliage3DPort *left;
Foliage3DPort *right;
String get_prop() const { return prop; }
void set_prop(String p_prop) { prop = p_prop; };
String get_name() const { return name; }
void set_name(String p_name) { name = p_name; };
Foliage3DPort* get_left() const { return left; }
void set_left(Foliage3DPort *p_left) { left = p_left; };
Foliage3DPort* get_right() const { return right; }
void set_right(Foliage3DPort *p_right) { right = p_right; };
};
@@ -1,60 +0,0 @@
@tool
class_name Foliage3DSurfaceSampler extends Foliage3DNode
@export var spacing: float = 10.0:
set(value):
spacing = value
changed.emit()
@export var point_extents: Vector3 = Vector3(1, 1, 1):
set(value):
point_extents = value
changed.emit()
@export var seed: int:
set(value):
seed = value
changed.emit()
func get_inputs() -> Array[int]:
return []
func get_outputs() -> Array[int]:
return [TYPE_POINT]
func _generate(ctx: Foliage3DExecutor.NodeContext) -> Array:
var rng = RandomNumberGenerator.new()
rng.seed = seed
var points: Array[Foliage3DPoint]
var size = ctx.bounds.aabb.size
var x = 0.0
while x < size.x:
x += spacing
var z = 0.0
while z < size.z:
z += spacing
var offset = Vector3(rng.randf_range(-spacing/2, spacing/2), 0, rng.randf_range(-spacing/2, spacing/2))
var position = Vector3(x, 0, z) + ctx.bounds.aabb.position + offset
position.y = ctx.with_terrain(func(t: Terrain3D): return t.data.get_height(position))
if is_nan(position.y):
position.y = 0
if not ctx.bounds.contains(position):
continue
var normal = ctx.with_terrain(func(t: Terrain3D): return t.data.get_normal(position))
if is_nan(normal.x):
normal = Vector3.UP
var basis: Basis
if normal != Vector3.UP:
var tangent = normal.cross(Vector3.UP).normalized()
var bitangent = tangent.cross(normal).normalized()
basis = Basis(tangent, normal, bitangent)
var transform = Transform3D(basis, position)
points.append(Foliage3DPoint.new(transform, point_extents))
return [points]
@@ -1 +0,0 @@
uid://cc4n4ipq4i7jk
@@ -1,40 +0,0 @@
#include "terrain.hpp"
#include <godot_cpp/core/class_db.hpp>
using namespace godot;
Foliage3DTerrain::Foliage3DTerrain()
{
}
Foliage3DTerrain::~Foliage3DTerrain()
{
}
double Foliage3DTerrain::get_height(Vector3 p_position)
{
return 0.0;
}
Vector3 Foliage3DTerrain::get_normal(Vector3 p_position)
{
return Vector3();
}
void Foliage3DTerrain::add_mesh_xforms(int id, TypedArray<Transform3D> xforms)
{
}
void Foliage3DTerrain::_bind_methods()
{
ClassDB::bind_method(D_METHOD("get_height", "position"), &Foliage3DTerrain::get_height);
ClassDB::bind_method(D_METHOD("get_normal", "position"), &Foliage3DTerrain::get_normal);
GDVIRTUAL_BIND(get_height, "position");
GDVIRTUAL_BIND(get_normal, "position");
GDVIRTUAL_BIND(add_mesh_xforms, "id", "xforms");
}
@@ -1,28 +0,0 @@
#pragma once
#include <godot_cpp/classes/object.hpp>
#include <godot_cpp/core/gdvirtual.gen.inc>
#include <godot_cpp/core/binder_common.hpp>
using namespace godot;
class Foliage3DTerrain : public Object
{
GDCLASS(Foliage3DTerrain, Object);
protected:
static void _bind_methods();
public:
Foliage3DTerrain();
~Foliage3DTerrain();
double get_height(Vector3 p_position);
GDVIRTUAL1R(double, get_height, Vector3);
Vector3 get_normal(Vector3 p_position);
GDVIRTUAL1R(Vector3, get_normal, Vector3);
void add_mesh_xforms(int id, TypedArray<Transform3D> xforms);
GDVIRTUAL2(add_mesh_xforms, int, TypedArray<Transform3D>);
};
@@ -1,118 +0,0 @@
class_name Foliage3DTexturePainter extends Foliage3DNode
const BRUSH_PATH: String = "res://addons/terrain_3d/brushes"
enum Brush {
CIRCLE0,
CIRCLE1,
CIRCLE2,
CIRCLE3,
CIRCLE4,
SQUARE1,
SQUARE2,
SQUARE3,
SQUARE4,
SQUARE5,
}
@export var albedo_texture: Texture2D:
set(value):
albedo_texture = value
changed.emit()
@export var brush: Brush:
set(value):
brush = value
changed.emit()
@export_range(0.1, 1000.0) var strength: float = 1000.0:
set(value):
strength = value
changed.emit()
# textures are painted in order of priority, lowest first, highest last
@export_range(0, 1024) var priority: int:
set(value):
priority = value
changed.emit()
func get_inputs() -> Array[int]:
return [TYPE_POINT]
func _generate(ctx: Foliage3DExecutor.NodeContext, input: Array[Foliage3DPoint]) -> Array:
if input.is_empty() or albedo_texture == null:
return []
if priority > 0:
ctx.mutate(func(data: Dictionary):
data[self] = input
)
else:
ctx.with_terrain_main(paint.bind(input))
return []
func _post_generate(ctx: Foliage3DExecutor.NodeContext):
var data = ctx.finalize()
if data is not Dictionary:
return
var keys: Array = data.keys()
keys.sort_custom(func(a, b): return a.priority < b.priority)
ctx.with_terrain_main(func(terrain: Terrain3D):
for node: Foliage3DTexturePainter in keys:
node.paint(terrain, data[node])
)
func paint(terrain: Terrain3D, input: Array[Foliage3DPoint]):
var editor = Terrain3DEditor.new()
editor.set_terrain(terrain)
editor.set_tool(Terrain3DEditor.TEXTURE)
editor.set_operation(Terrain3DEditor.REPLACE)
var brush = load_brush(get_or_create_texture(terrain))
editor.set_brush_data(brush)
editor.start_operation(Vector3.ZERO)
for point: Foliage3DPoint in input:
var size = point.size.x + point.size.z
if brush["size"] != size:
brush["size"] = size
editor.set_brush_data(brush)
editor.operate(point.transform.origin, 0.0)
editor.stop_operation()
func get_or_create_texture(terrain: Terrain3D) -> int:
var texture_count = terrain.assets.get_texture_count()
for i in range(texture_count):
var texture = terrain.assets.get_texture(i)
if texture.albedo_texture.resource_path == albedo_texture.resource_path:
return i
var texture = Terrain3DTextureAsset.new()
texture.id = texture_count
texture.albedo_texture = albedo_texture
texture.name = albedo_texture.resource_path.get_file()
terrain.assets.set_texture(texture_count, texture)
return texture_count
func load_brush(texture_id: int) -> Dictionary:
var img: Image = Image.load_from_file("%s/%s.exr" % [BRUSH_PATH, Brush.keys()[brush].to_lower()])
var thumbimg: Image = img.duplicate()
img.convert(Image.FORMAT_RF)
var tex_img = img
if tex_img.get_width() < 1024 and tex_img.get_height() < 1024:
tex_img = tex_img.duplicate()
tex_img.resize(1024, 1024, Image.INTERPOLATE_CUBIC)
var tex: ImageTexture = ImageTexture.create_from_image(tex_img)
return {
"brush": [img, tex],
"strength": strength,
"enable_texture": true,
"asset_id": texture_id,
"size": 0.0,
}
@@ -1 +0,0 @@
uid://ouxsf8xl5t6t
@@ -1,85 +0,0 @@
class_name Foliage3DTransform extends Foliage3DNode
@export var offset_min: Vector3:
set(value):
offset_min = value
changed.emit()
@export var offset_max: Vector3:
set(value):
offset_max = value
changed.emit()
@export var rotation_min: Vector3:
set(value):
rotation_min = value
changed.emit()
@export var rotation_max: Vector3:
set(value):
rotation_max = value
changed.emit()
@export var rotation_absolute: bool:
set(value):
rotation_absolute = value
changed.emit()
@export var scale_min: Vector3 = Vector3(1, 1, 1):
set(value):
scale_min = value
changed.emit()
@export var scale_max: Vector3 = Vector3(1, 1, 1):
set(value):
scale_max = value
changed.emit()
@export var scale_uniform: bool = true:
set(value):
scale_uniform = value
changed.emit()
@export var seed: int:
set(value):
seed = value
changed.emit()
func get_inputs() -> Array[int]:
return [TYPE_POINT]
func get_outputs() -> Array[int]:
return [TYPE_POINT]
func _generate(ctx: Foliage3DExecutor.NodeContext, input: Array[Foliage3DPoint]) -> Array:
var rng = RandomNumberGenerator.new()
rng.seed = seed
var result: Array[Foliage3DPoint]
result.assign(input.map(func(p): return p.duplicate()))
if offset_min != Vector3.ZERO or offset_max != Vector3.ZERO:
for i in range(result.size()):
var transform = result[i].transform
transform.origin.x += rng.randf_range(offset_min.x, offset_max.x)
transform.origin.y += rng.randf_range(offset_min.y, offset_max.y)
transform.origin.z += rng.randf_range(offset_min.z, offset_max.z)
result[i].transform = transform
if rotation_min != Vector3.ZERO or rotation_max != Vector3.ZERO or rotation_absolute:
for i in range(result.size()):
var transform = result[i].transform
if rotation_absolute:
transform.basis = Basis()
transform.basis = transform.basis * Basis.from_euler(Vector3(
deg_to_rad(rng.randf_range(rotation_min.x, rotation_max.x)),
deg_to_rad(rng.randf_range(rotation_min.y, rotation_max.y)),
deg_to_rad(rng.randf_range(rotation_min.z, rotation_max.z))
))
result[i].transform = transform
if not scale_min.is_equal_approx(scale_max):
for i in range(result.size()):
var transform = result[i].transform
var scale : Vector3
if scale_uniform:
var val = rng.randf_range(scale_min.x, scale_max.x)
scale = Vector3(val, val, val)
else:
scale = Vector3(rng.randf_range(scale_min.x, scale_max.x), rng.randf_range(scale_min.y, scale_max.y), rng.randf_range(scale_min.z, scale_max.z))
transform.basis = transform.basis.scaled(scale)
result[i].transform = transform
return [result]
@@ -1 +0,0 @@
uid://sf4o83hyhd1p
@@ -1,46 +0,0 @@
@tool
extends EditorPlugin
#var inspector_plugin = Foliage3DEditorInspectorPlugin.new()
var container: BoxContainer = BoxContainer.new()
var button: Button
@onready var selection = EditorInterface.get_selection()
var current: Foliage3D
func _ready():
#add_inspector_plugin(inspector_plugin)
selection.selection_changed.connect(_selection_changed)
_selection_changed()
container.grow_horizontal = Control.GROW_DIRECTION_BOTH
container.grow_vertical = Control.GROW_DIRECTION_BOTH
button = add_control_to_bottom_panel(container, "Foliage3D")
add_custom_type("Foliage3D", "Node3D", Foliage3D, null)
func _exit_tree():
#remove_inspector_plugin(inspector_plugin)
remove_control_from_bottom_panel(container)
remove_custom_type("Foliage3D")
selection.selection_changed.disconnect(_selection_changed)
button.queue_free()
func _selection_changed():
var nodes = selection.get_selected_nodes()
if nodes.is_empty():
return
var foliage = nodes[0]
if foliage is Foliage3D:
if not foliage.graph_changed.is_connected(add_graph_edit):
foliage.graph_changed.connect(add_graph_edit.bind(foliage))
add_graph_edit(foliage)
func add_graph_edit(foliage: Foliage3D):
for child in container.get_children():
container.remove_child(child)
child.queue_free()
if is_instance_valid(foliage.graph) and is_instance_valid(foliage.terrain):
container.add_child(foliage.create_edit())
@@ -1 +0,0 @@
uid://bbkd83wq3l2pe
@@ -1,109 +0,0 @@
class_name Foliage3DPoint
var transform: Transform3D:
set(value):
transform = value
update_aabb()
var extents: Vector3:
set(value):
extents = value
size = extents * 2
update_aabb()
var size: Vector3
var density: float
var aabb: AABB
func _init(p_transform: Transform3D, p_extents: Vector3, p_density = 0.0):
transform = p_transform
extents = p_extents
density = p_density
func update_aabb():
var scaled_size = size * transform.basis.get_scale()
aabb = AABB(transform.origin - scaled_size/2, scaled_size)
func intersects(point: Foliage3DPoint) -> bool:
return aabb.intersects(point.aabb)
func duplicate() -> Foliage3DPoint:
return Foliage3DPoint.new(transform, extents)
class Grid:
var points: Array[Foliage3DPoint]
var grid: Dictionary[Vector3i, Array]
var cell_size: float = INF
func _init(p_points: Array[Foliage3DPoint]):
points = p_points
for point in points:
cell_size = min(cell_size, min(point.aabb.size.x, point.aabb.size.y, point.aabb.size.z))
cell_size = max(cell_size, 0.001) # Prevent division by zero
func get_grid_keys(point: Foliage3DPoint) -> Array:
var min_cell := Vector3i(point.aabb.position / cell_size)
var max_cell := Vector3i((point.aabb.position + point.aabb.size) / cell_size)
var keys = []
for x in range(min_cell.x, max_cell.x + 1):
for y in range(min_cell.y, max_cell.y + 1):
for z in range(min_cell.z, max_cell.z + 1):
keys.append(Vector3i(x, y, z))
return keys
func difference(input: Array[Foliage3DPoint]) -> Array[Foliage3DPoint]:
for point in points:
for key in get_grid_keys(point):
if key not in grid:
grid[key] = []
grid[key].append(point)
var result: Array[Foliage3DPoint]
for point in input:
var overlaps := false
for key in get_grid_keys(point):
if key in grid:
for diff_point in grid[key]:
if point.intersects(diff_point):
overlaps = true
break
if overlaps:
break
if not overlaps:
result.append(point)
return result
func prune() -> Array[Foliage3DPoint]:
var result: Array[Foliage3DPoint]
var to_remove := {}
for point in points:
var keys = get_grid_keys(point)
var overlapping = false
# Check if the box overlaps with any existing boxes in the same grid cell
for key in keys:
if key in grid:
for other in grid[key]:
if point.intersects(other):
overlapping = true
to_remove[other] = true
break
if overlapping:
break
if not overlapping:
for key in keys:
if key not in grid:
grid[key] = []
grid[key].append(point)
# Filter out overlapping boxes
for point in points:
if point not in to_remove:
result.append(point)
return result
@@ -1 +0,0 @@
uid://c8d1f38wya20c
@@ -1,98 +0,0 @@
[configuration]
entry_symbol = "gdext_rust_init"
compatibility_minimum = 4.5
reloadable = true
[libraries]
linux.x86_64 = "bin/x86_64-unknown-linux-gnu/libgdcef.so"
linux.arm64 = "bin/aarch64-unknown-linux-gnu/libgdcef.so"
macos = "bin/universal-apple-darwin/Godot CEF.framework"
windows.x86_64 = "bin/x86_64-pc-windows-msvc/gdcef.dll"
windows.arm64 = "bin/aarch64-pc-windows-msvc/gdcef.dll"
[icons]
CefTexture = "icons/webview.png"
CefIpcInspector = "icons/webview.png"
[dependencies]
windows.x86_64 = {
"bin/x86_64-pc-windows-msvc/gdcef.dll" : "",
"bin/x86_64-pc-windows-msvc/gdcef_helper.exe" : "",
"bin/x86_64-pc-windows-msvc/locales" : "",
"bin/x86_64-pc-windows-msvc/bootstrap.exe" : "",
"bin/x86_64-pc-windows-msvc/bootstrapc.exe" : "",
"bin/x86_64-pc-windows-msvc/chrome_100_percent.pak" : "",
"bin/x86_64-pc-windows-msvc/chrome_200_percent.pak" : "",
"bin/x86_64-pc-windows-msvc/chrome_elf.dll" : "",
"bin/x86_64-pc-windows-msvc/d3dcompiler_47.dll" : "",
"bin/x86_64-pc-windows-msvc/dxcompiler.dll" : "",
"bin/x86_64-pc-windows-msvc/dxil.dll" : "",
"bin/x86_64-pc-windows-msvc/icudtl.dat" : "",
"bin/x86_64-pc-windows-msvc/libcef.dll" : "",
"bin/x86_64-pc-windows-msvc/libEGL.dll" : "",
"bin/x86_64-pc-windows-msvc/libGLESv2.dll" : "",
"bin/x86_64-pc-windows-msvc/resources.pak" : "",
"bin/x86_64-pc-windows-msvc/v8_context_snapshot.bin" : "",
"bin/x86_64-pc-windows-msvc/vk_swiftshader.dll" : "",
"bin/x86_64-pc-windows-msvc/vk_swiftshader_icd.json" : "",
"bin/x86_64-pc-windows-msvc/vulkan-1.dll" : ""
}
windows.arm64 = {
"bin/aarch64-pc-windows-msvc/gdcef.dll" : "",
"bin/aarch64-pc-windows-msvc/gdcef_helper.exe" : "",
"bin/aarch64-pc-windows-msvc/locales" : "",
"bin/aarch64-pc-windows-msvc/bootstrap.exe" : "",
"bin/aarch64-pc-windows-msvc/bootstrapc.exe" : "",
"bin/aarch64-pc-windows-msvc/chrome_100_percent.pak" : "",
"bin/aarch64-pc-windows-msvc/chrome_200_percent.pak" : "",
"bin/aarch64-pc-windows-msvc/chrome_elf.dll" : "",
"bin/aarch64-pc-windows-msvc/d3dcompiler_47.dll" : "",
"bin/aarch64-pc-windows-msvc/dxcompiler.dll" : "",
"bin/aarch64-pc-windows-msvc/dxil.dll" : "",
"bin/aarch64-pc-windows-msvc/icudtl.dat" : "",
"bin/aarch64-pc-windows-msvc/libcef.dll" : "",
"bin/aarch64-pc-windows-msvc/libEGL.dll" : "",
"bin/aarch64-pc-windows-msvc/libGLESv2.dll" : "",
"bin/aarch64-pc-windows-msvc/resources.pak" : "",
"bin/aarch64-pc-windows-msvc/v8_context_snapshot.bin" : "",
"bin/aarch64-pc-windows-msvc/vk_swiftshader.dll" : "",
"bin/aarch64-pc-windows-msvc/vk_swiftshader_icd.json" : "",
"bin/aarch64-pc-windows-msvc/vulkan-1.dll" : ""
}
macos = {
"bin/universal-apple-darwin/Godot CEF.framework" : "Contents/Frameworks",
"bin/universal-apple-darwin/Godot CEF.app" : "Contents/Frameworks"
}
linux.x86_64 = {
"bin/x86_64-unknown-linux-gnu/libgdcef.so" : "",
"bin/x86_64-unknown-linux-gnu/gdcef_helper" : "",
"bin/x86_64-unknown-linux-gnu/chrome-sandbox" : "",
"bin/x86_64-unknown-linux-gnu/libcef.so" : "",
"bin/x86_64-unknown-linux-gnu/libEGL.so" : "",
"bin/x86_64-unknown-linux-gnu/libGLESv2.so" : "",
"bin/x86_64-unknown-linux-gnu/libvk_swiftshader.so" : "",
"bin/x86_64-unknown-linux-gnu/libvulkan.so.1" : "",
"bin/x86_64-unknown-linux-gnu/v8_context_snapshot.bin" : "",
"bin/x86_64-unknown-linux-gnu/vk_swiftshader_icd.json" : ""
}
linux.arm64 = {
"bin/aarch64-unknown-linux-gnu/libgdcef.so" : "",
"bin/aarch64-unknown-linux-gnu/gdcef_helper" : "",
"bin/aarch64-unknown-linux-gnu/chrome-sandbox" : "",
"bin/aarch64-unknown-linux-gnu/libcef.so" : "",
"bin/aarch64-unknown-linux-gnu/libEGL.so" : "",
"bin/aarch64-unknown-linux-gnu/libGLESv2.so" : "",
"bin/aarch64-unknown-linux-gnu/libvk_swiftshader.so" : "",
"bin/aarch64-unknown-linux-gnu/libvulkan.so.1" : "",
"bin/aarch64-unknown-linux-gnu/v8_context_snapshot.bin" : "",
"bin/aarch64-unknown-linux-gnu/vk_swiftshader_icd.json" : ""
}
@@ -1 +0,0 @@
uid://cs3wfn3u42rgo
Binary file not shown.

Before

Width:  |  Height:  |  Size: 826 KiB

@@ -1,40 +0,0 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://1axq0kdirfs5"
path="res://.godot/imported/webview.png-257894f448b3347f6b7b31ad54724fa2.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/godot_cef/icons/webview.png"
dest_files=["res://.godot/imported/webview.png-257894f448b3347f6b7b31ad54724fa2.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
@@ -1,14 +0,0 @@
[configuration]
entry_symbol = "gdext_rust_init"
compatibility_minimum = 4.6
reloadable = true
[libraries]
linux.debug.x86_64 = "res://../libpainless/target/debug/libpainless.so"
linux.release.x86_64 = "res://../libpainless/target/release/libpainless.so"
windows.debug.x86_64 = "res://../libpainless/target/debug/painless.dll"
windows.release.x86_64 = "res://../libpainless/target/release/painless.dll"
macos.debug = "res://../libpainless/target/debug/libpainless.dylib"
macos.release = "res://../libpainless/target/release/libpainless.dylib"
@@ -1 +0,0 @@
uid://bu8a1sxlivkaf
-26
View File
@@ -1,26 +0,0 @@
MIT License
Copyright (c) 2023-2025 Cory Petkovsek and Contributors
Copyright (c) 2021 J. Cuéllar
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.
----
Third party assets have their own licenses found under assets/thirdparty.
-3
View File
@@ -1,3 +0,0 @@
# Sky3D
See the README in the code repository at https://github.com/TokisanGames/Sky3D.
@@ -1,8 +0,0 @@
## Attribution for Third Party Assets
`Milkyway.jpg` "[The Milky Way panorama](https://www.eso.org/public/images/eso0932a/)" by ESO/S. Brunier, licensed under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/
).
[Read more](/addons/sky_3d/assets/thirdparty/textures/milkyway/LICENSE.md)
`MoonMap.png` Copyright (c) 2019 GPoSM, MIT License
[Read more](/addons/sky_3d/assets/thirdparty/textures/moon/LICENSE.md)
@@ -1,7 +0,0 @@
[gd_resource type="NoiseTexture2D" load_steps=2 format=3 uid="uid://cfqk60lpl5ljv"]
[sub_resource type="FastNoiseLite" id="1"]
[resource]
seamless = true
noise = SubResource("1")
@@ -1,5 +0,0 @@
[gd_resource type="Curve" format=3 uid="uid://70482fhm3qg7"]
[resource]
_data = [Vector2(0, 0), 0.0, 0.0, 0, 0, Vector2(0.617886, 0), 0.0, 0.0467088, 1, 0, Vector2(0.699187, 1), 0.0, 0.0, 0, 0, Vector2(1, 1), 0.0, 0.0, 0, 0]
point_count = 4
Binary file not shown.

Before

Width:  |  Height:  |  Size: 860 B

@@ -1,40 +0,0 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bwooawylkf7f2"
path="res://.godot/imported/SkyIcon.png-7b3cbfa68354965cdbfdba8b95dacf67.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/sky_3d/assets/textures/SkyIcon.png"
dest_files=["res://.godot/imported/SkyIcon.png-7b3cbfa68354965cdbfdba8b95dacf67.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

@@ -1,41 +0,0 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://djpfuyxkryegn"
path.s3tc="res://.godot/imported/noise.jpg-b47d5d36d9abfdaec2a09c140a78ba24.s3tc.ctex"
metadata={
"imported_formats": ["s3tc_bptc"],
"vram_texture": true
}
[deps]
source_file="res://addons/sky_3d/assets/textures/noise.jpg"
dest_files=["res://.godot/imported/noise.jpg-b47d5d36d9abfdaec2a09c140a78ba24.s3tc.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0
Binary file not shown.

Before

Width:  |  Height:  |  Size: 142 KiB

@@ -1,41 +0,0 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bd7u40ws8s57f"
path.s3tc="res://.godot/imported/noise2.png-37a5cbd5451b4b9c2c18ab32099e6965.s3tc.ctex"
metadata={
"imported_formats": ["s3tc_bptc"],
"vram_texture": true
}
[deps]
source_file="res://addons/sky_3d/assets/textures/noise2.png"
dest_files=["res://.godot/imported/noise2.png-37a5cbd5451b4b9c2c18ab32099e6965.s3tc.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
Binary file not shown.

Before

Width:  |  Height:  |  Size: 123 KiB

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