Compare commits
475 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| de33cbce2b | |||
| 2b5f621ff8 | |||
| 1681adc10b | |||
| f606f2b7c2 | |||
| e3f9b66994 | |||
| ec3ff260fe | |||
| fafab30a09 | |||
| 707352ce51 | |||
| a9f5dafefe | |||
| 291ffd311b | |||
| 0e8c0b459b | |||
| c575a2968b | |||
| 0b297b4cd7 | |||
| b8c90985ce | |||
| b924576983 | |||
| a8b62b31a1 | |||
| 95b2d5a908 | |||
| 7d2ccc302d | |||
| 1ba1bff859 | |||
| 9409841c89 | |||
| 6c4e8021d6 | |||
| 4b1623e8c0 | |||
| a1e88bff70 | |||
| f3c20cde30 | |||
| eb601d9276 | |||
| 17a13993cc | |||
| 16e7254179 | |||
| ab055f1a0e | |||
| 0cb3716dc7 | |||
| 71e9877808 | |||
| f05e424c49 | |||
| 646882e1a9 | |||
| 482311fe48 | |||
| 97a80ed887 | |||
| 0e547c80a9 | |||
| b792487b60 | |||
| 7920415d18 | |||
| ada7668c28 | |||
| e7a34f9498 | |||
| 2a5c465923 | |||
| a14a558f0d | |||
| 66db5f0df1 | |||
| 2dc4ba20fb | |||
| 2f14d7ac27 | |||
| 6cc659bda5 | |||
| 206e492e7c | |||
| 09289e72a1 | |||
| 7861b63c99 | |||
| 965b9c948e | |||
| ae4ca8cd6b | |||
| 2dec862c3b | |||
| f9d8073e80 | |||
| 2ca99c29d2 | |||
| 2e4477b533 | |||
| b0c7919dda | |||
| 398c14ee96 | |||
| 422e54b488 | |||
| 36f1c49f49 | |||
| 271f4e8b21 | |||
| b164e4646d | |||
| 14fd5729e2 | |||
| 7c3e279237 | |||
| 2884094dee | |||
| 817c268491 | |||
| 071a306f14 | |||
| c97fea6d0a | |||
| d94faf828d | |||
| 0d6d4b133e | |||
| 5ab6bfb663 | |||
| e087dbc878 | |||
| 391e96ad3d | |||
| fbf812091d | |||
| 7448483f84 | |||
| e3d6e1bcc6 | |||
| fbbcd1b95b | |||
| d8e7325044 | |||
| f17aeca79c | |||
| ac3a223114 | |||
| e4312c2f8b | |||
| 17bde631ac | |||
| 64d8f7ee2d | |||
| d8b3aee9dc | |||
| fce94fa4bf | |||
| 254d671629 | |||
| e66e7e627a | |||
| 578efbf15f | |||
| 8b6bb228e3 | |||
| 611c4606d7 | |||
| 05bdaf0390 | |||
| eb8fcaee36 | |||
| 32a71933d6 | |||
| a4baf9ca0a | |||
| 72bfd0a2bb | |||
| 7ae4a9f460 | |||
| 9bd6fb0105 | |||
| 1f1024251b | |||
| fc516a20d5 | |||
| 791c2c3426 | |||
| b00079897a | |||
| 37b73e1d5c | |||
| 4bd1136713 | |||
| ef98dbd5fd | |||
| 5df0a60b06 | |||
| 9feb20eff8 | |||
| c9267d61a8 | |||
| a29e225a80 | |||
| ae0f3c2b3b | |||
| 852ea75449 | |||
| ab6a5dad2b | |||
| 1a1eaca280 | |||
| 0272f8c57f | |||
| cf09358710 | |||
| b5d833fa3d | |||
| 329dbe9585 | |||
| c7ae7f155e | |||
| 5f7dbb8662 | |||
| ee21548151 | |||
| ca00125960 | |||
| 4067264e72 | |||
| 9c2d243ad4 | |||
| de9d8b0d2e | |||
| 67f4615b34 | |||
| cd7a130ee4 | |||
| 4d17f7aecf | |||
| a59e7500ab | |||
| 40040294e7 | |||
| 783e61ec3d | |||
| e09db5d7df | |||
| 91f9ef3f4b | |||
| d52a3abb14 | |||
| 16370b0b6e | |||
| bfa60b48cf | |||
| 50518bfe21 | |||
| 80e4467829 | |||
| 396315bd05 | |||
| 7a0fec2c2f | |||
| 4afaaa7b12 | |||
| b057041467 | |||
| 33e6ce6376 | |||
| 118ef39c30 | |||
| 1013e1c824 | |||
| b0e924c7fe | |||
| 1777acd1d4 | |||
| 8276a862f8 | |||
| 4329acf91d | |||
| 72f83b40f7 | |||
| a33eb30a53 | |||
| d3e96f50a8 | |||
| 3aefeb98b4 | |||
| 3553ff8e60 | |||
| 945a2c0c5a | |||
| 8c7974e216 | |||
| 37756cd759 | |||
| c60cc4f013 | |||
| 87cce2e33c | |||
| 40ada9c186 | |||
| 55fb458266 | |||
| 79d2466fa2 | |||
| d750e489df | |||
| a206e49b2b | |||
| 0b691ebcd5 | |||
| 3c35c52803 | |||
| 0ed4964ee5 | |||
| b7cf7b61c8 | |||
| 54b0ccfce6 | |||
| 050d00b628 | |||
| 2733201ac3 | |||
| 26bf03205c | |||
| 628d57d216 | |||
| 58ed8259f2 | |||
| 062ed5bcc8 | |||
| 539d152caa | |||
| a1af4335e0 | |||
| e68b112020 | |||
| fab6d187ca | |||
| 0daa00cec2 | |||
| f3036850ce | |||
| 51c8b47bba | |||
| 89efd53d61 | |||
| 7667f51cf3 | |||
| 61eaa5a734 | |||
| 1d589d1a62 | |||
| 03b1eeb77e | |||
| 8446df72f7 | |||
| c07397e9c0 | |||
| 29a92aeb93 | |||
| 8467782b80 | |||
| c8dbb21ea4 | |||
| 63e1c12564 | |||
| 52f58150da | |||
| d1d642a7bb | |||
| 8e45358aad | |||
| a959c7220b | |||
| e06425c5eb | |||
| 66ce258fe1 | |||
| 181881a661 | |||
| af0d8d1d2f | |||
| 6c68e94b96 | |||
| 93313a5c50 | |||
| 0527baa708 | |||
| ce1fbde937 | |||
| 764abdac45 | |||
| b42d3d8f74 | |||
| cd67a773c5 | |||
| 6d7bade7ca | |||
| dea8d4498a | |||
| 2969916f34 | |||
| 8785224c51 | |||
| 605f02a655 | |||
| 8099d37c14 | |||
| dd4dbefe9a | |||
| 52a15fd349 | |||
| 3b3be6aed4 | |||
| aeb7d6d0f9 | |||
| 5336dbafec | |||
| 6079cb4830 | |||
| 50ff174104 | |||
| b77ef89df6 | |||
| a701dd29a9 | |||
| ab36fdd545 | |||
| f87afb34f4 | |||
| 053917d3d7 | |||
| 063ba01970 | |||
| 72a888f3ff | |||
| 0bd36bff1d | |||
| 2bf125b7ac | |||
| ba3cf8fd56 | |||
| 951f2a4ee7 | |||
| d55b1bb3c2 | |||
| 275ecb78c3 | |||
| 64ac0d6017 | |||
| 3f16d67746 | |||
| 3a34dc8626 | |||
| c1766fb439 | |||
| cfd47adfda | |||
| 9b9e6b9179 | |||
| 49d1587a71 | |||
| b0f5e55744 | |||
| d9191534d5 | |||
| ff459621e6 | |||
| 64fb45d74d | |||
| 1590abb489 | |||
| a3c9b0654a | |||
| a9388321d9 | |||
| 877c824e58 | |||
| 80f30dfd74 | |||
| 9a087025fe | |||
| 29381bce7b | |||
| 21dc0f13c9 | |||
| 7794958804 | |||
| c245ed6598 | |||
| 6270b03005 | |||
| 2674b945bb | |||
| 0647bdbab3 | |||
| 528a12ac83 | |||
| 4ac9de05df | |||
| a0f1b72089 | |||
| 85c07b11c6 | |||
| 215e1d46d0 | |||
| 5f228f0567 | |||
| f597958e1e | |||
| 95921358f8 | |||
| a22d494797 | |||
| 666e917b8f | |||
| a26a97e7fb | |||
| cdbb9de933 | |||
| feccf12580 | |||
| d371d93c9d | |||
| 5f3e8d76b2 | |||
| a7bd72e35b | |||
| 0a5326d2b1 | |||
| dad2014c46 | |||
| 70dd0bda72 | |||
| 8213901229 | |||
| 668ba491e8 | |||
| d85589c41a | |||
| 7f5316108d | |||
| 9c1abbac2b | |||
| 1bb957a866 | |||
| 6ccba17baf | |||
| e4c5d8adab | |||
| 823f204424 | |||
| 505e9a77fd | |||
| 4c580fe4ff | |||
| 9fea29cbb6 | |||
| efc1865f87 | |||
| 7e1e5a56e2 | |||
| 059293ebe0 | |||
| 4f9d4e2a14 | |||
| 6bd3c825c3 | |||
| c75595a5e2 | |||
| 266d463873 | |||
| ae08ad56c4 | |||
| 633544e0b0 | |||
| 2432028aa0 | |||
| eb6aa13815 | |||
| 55155103ec | |||
| 73c718c676 | |||
| 3df5c04759 | |||
| 667dd85aef | |||
| d72c34a926 | |||
| 8991338be1 | |||
| 9bd946a41c | |||
| 241baef7af | |||
| b5890a4783 | |||
| e3b67ef500 | |||
| 5905fe3df2 | |||
| 9d35a70437 | |||
| f121860563 | |||
| 9715db3ac6 | |||
| 03a29fbacb | |||
| e91888934b | |||
| 030f814398 | |||
| 90ef8fd64d | |||
| 0ffefaa8c1 | |||
| 99703d65df | |||
| bd2f5a7836 | |||
| a44556f86a | |||
| 4597b7f647 | |||
| 0de80cfaa7 | |||
| 6b32ab02d3 | |||
| c5adc3f72a | |||
| 034aaddca3 | |||
| a1d493f25d | |||
| 4b5a4dda79 | |||
| ce528f3fd5 | |||
| e4c769e95e | |||
| f13095875f | |||
| 3d1af8f944 | |||
| d73867efd6 | |||
| 045733deb5 | |||
| b552bf2566 | |||
| 33d37b3937 | |||
| 15a044d059 | |||
| 9e5be3ad21 | |||
| ba977a29f0 | |||
| c6c94ef906 | |||
| 7fed4b1ddb | |||
| dfee36f416 | |||
| cf6945b44c | |||
| a01a9ac356 | |||
| 89619696cb | |||
| 88f945bf22 | |||
| 3555133d7f | |||
| 294013eff0 | |||
| 6748ec25ff | |||
| 485c3dedb3 | |||
| 4ceecdfb09 | |||
| 23d3e44002 | |||
| 3a5d6e7370 | |||
| 71237caa81 | |||
| 7e19f9e6eb | |||
| f7b5b9a2f5 | |||
| 77016de6e6 | |||
| e530d0ffda | |||
| b04a308090 | |||
| 385d6919fb | |||
| 458cc9b505 | |||
| afdccfe087 | |||
| 4d7674348b | |||
| a2c96ba7ff | |||
| 5c5de3c744 | |||
| 18acb5d101 | |||
| c86c32b39e | |||
| 3c680b5daf | |||
| 84d1298e18 | |||
| 354b6567d4 | |||
| 3498faed59 | |||
| f8eb1e8a97 | |||
| 19057218d6 | |||
| f745e9c51a | |||
| da922a8c69 | |||
| 3f2d8ea6ae | |||
| 550f36e9fa | |||
| ba0835bf4a | |||
| 766a41ce56 | |||
| 3b5728692d | |||
| 05d573c847 | |||
| 9360e45a39 | |||
| 71aaff32a2 | |||
| 2fbeb43894 | |||
| ae6fa83c50 | |||
| f4171ffca1 | |||
| dedcc875d2 | |||
| 224a5449ed | |||
| b0d325fd14 | |||
| 36ad3f4e43 | |||
| b5eff6aa80 | |||
| f1e93ad547 | |||
| e59c22fb69 | |||
| 183882f9ce | |||
| 5b825f9dbb | |||
| 933d5c957c | |||
| 1bfa93eea3 | |||
| 1d0d67d215 | |||
| 2866aefb90 | |||
| c5bfdbc430 | |||
| 0ae83929b7 | |||
| 1a600e7c53 | |||
| dc92a341d4 | |||
| 31a534f945 | |||
| 2c3345a596 | |||
| d14349383b | |||
| db378d64b0 | |||
| 7963303a48 | |||
| 42d2cc6915 | |||
| 45128fff6b | |||
| 854885db64 | |||
| 963e62c595 | |||
| d2e41792a7 | |||
| fedd4b5cce | |||
| 804412698e | |||
| 09fa469a7d | |||
| 163ee63f9e | |||
| e143fb91a3 | |||
| 5897fc816c | |||
| da1dc04e98 | |||
| 7a05c8cdde | |||
| b219370469 | |||
| 2f7ab04984 | |||
| caf7f64f11 | |||
| 7834213a60 | |||
| 000c6053ed | |||
| 879b117959 | |||
| 272012ed22 | |||
| 3d9b988410 | |||
| 8b850f14d3 | |||
| 76f69b238a | |||
| 0b6e1135ce | |||
| 17b0d2e763 | |||
| a1a92ffd14 | |||
| 52cf6ac9df | |||
| 02a309cd34 | |||
| 0ec9e60396 | |||
| 597b659026 | |||
| 67c6061c7a | |||
| 0843a6f355 | |||
| d8d8d6f9a0 | |||
| c42ce57022 | |||
| db34b455aa | |||
| 59c82f0499 | |||
| f78e771c8b | |||
| 1be141348c | |||
| d9b5195bee | |||
| 4d0472749d | |||
| b8ebc54dee | |||
| 413ee3cdf4 | |||
| dee58dafc9 | |||
| 7b326d63e8 | |||
| 74f80ca2f5 | |||
| 6246f66300 | |||
| 037231c0ac | |||
| b416746ba2 | |||
| 5f7181f6f1 | |||
| 6b23e0de7e | |||
| fe6c4f7507 | |||
| e83d490b0e | |||
| 09bc303583 | |||
| 3fb09fa811 | |||
| 4984d00d36 | |||
| 87222f3b39 | |||
| c58a8d8e69 | |||
| f1deb7e592 | |||
| 00abfb735a | |||
| d2e831885d | |||
| d7358ed7a3 | |||
| bffffbb333 | |||
| 2e7185da5d | |||
| 32775ac3e5 | |||
| cb59d76f09 | |||
| 7512a41ef7 | |||
| 7d083bdad2 | |||
| 9972363846 | |||
| 4f171234c4 | |||
| e5536de44f |
@@ -1,19 +0,0 @@
|
|||||||
**/.git
|
|
||||||
**/.gitlab
|
|
||||||
**/.cache
|
|
||||||
|
|
||||||
buildAllJars
|
|
||||||
|
|
||||||
**/_Misc Files
|
|
||||||
*.bat
|
|
||||||
*.md
|
|
||||||
*.sh
|
|
||||||
*.txt
|
|
||||||
|
|
||||||
coreSubProjects/*.md
|
|
||||||
coreSubProjects/*.txt
|
|
||||||
|
|
||||||
**/.gitignore
|
|
||||||
**/.gitattributes
|
|
||||||
**/.gitlab-cy.yml
|
|
||||||
**/.gitmodules
|
|
||||||
@@ -25,6 +25,8 @@ hs_err_pid*
|
|||||||
Merged/
|
Merged/
|
||||||
# Folder created by the buildAll scripts
|
# Folder created by the buildAll scripts
|
||||||
buildAllJars/
|
buildAllJars/
|
||||||
|
_buildAllJars/
|
||||||
|
_buildWorkers/
|
||||||
|
|
||||||
relocate_natives/.venv/
|
relocate_natives/.venv/
|
||||||
relocate_natives/__pycache__/
|
relocate_natives/__pycache__/
|
||||||
|
|||||||
+23
-5
@@ -1,10 +1,10 @@
|
|||||||
# use Eclipse's JDK
|
# use Eclipse's JDK
|
||||||
# The ci should always use a unix(-like) OS to work
|
# The ci should always use a unix(-like) OS to work
|
||||||
image: eclipse-temurin:21
|
image: eclipse-temurin:25
|
||||||
|
|
||||||
# all stages need to be defined here
|
# all stages need to be defined here
|
||||||
# TODO: Make stages depend on what is in versionProperties
|
|
||||||
stages:
|
stages:
|
||||||
|
- translations
|
||||||
- build
|
- build
|
||||||
- api
|
- api
|
||||||
- pages
|
- pages
|
||||||
@@ -33,22 +33,26 @@ variables:
|
|||||||
|
|
||||||
build:
|
build:
|
||||||
stage: build
|
stage: build
|
||||||
|
needs:
|
||||||
|
- job: translations
|
||||||
|
artifacts: true
|
||||||
parallel:
|
parallel:
|
||||||
matrix:
|
matrix:
|
||||||
- MC_VER: [
|
- MC_VER: [
|
||||||
|
"26.1.2",
|
||||||
"1.21.11", "1.21.10", "1.21.9", "1.21.8", "1.21.6", "1.21.5", "1.21.4", "1.21.3", "1.21.1",
|
"1.21.11", "1.21.10", "1.21.9", "1.21.8", "1.21.6", "1.21.5", "1.21.4", "1.21.3", "1.21.1",
|
||||||
"1.20.6", "1.20.4", "1.20.2", "1.20.1",
|
"1.20.6", "1.20.4", "1.20.2", "1.20.1",
|
||||||
"1.19.4", "1.19.2",
|
"1.19.4", "1.19.2",
|
||||||
"1.18.2",
|
"1.18.2",
|
||||||
"1.17.1",
|
"1.17.1",
|
||||||
"1.16.5"
|
"1.16.5",
|
||||||
|
"1.12.2"
|
||||||
]
|
]
|
||||||
script:
|
script:
|
||||||
# this both runs the unit tests and assembles the code
|
# this both runs the unit tests and assembles the code
|
||||||
- ./gradlew clean -PmcVer="${MC_VER}" -PinfoGitCommit="${CI_COMMIT_SHA}" -PinfoGitBranch="${CI_COMMIT_BRANCH}" -PinfoBuildSource="GitLab CI (${CI_PIPELINE_ID})" --gradle-user-home cache/;
|
- ./gradlew clean -PmcVer="${MC_VER}" -PinfoGitCommit="${CI_COMMIT_SHA}" -PinfoGitBranch="${CI_COMMIT_BRANCH}" -PinfoBuildSource="GitLab CI (${CI_PIPELINE_ID})" --gradle-user-home cache/;
|
||||||
- ./gradlew build -PmcVer="${MC_VER}" -PinfoGitCommit="${CI_COMMIT_SHA}" -PinfoGitBranch="${CI_COMMIT_BRANCH}" -PinfoBuildSource="GitLab CI (${CI_PIPELINE_ID})" --gradle-user-home cache/;
|
- ./gradlew build -PmcVer="${MC_VER}" -PinfoGitCommit="${CI_COMMIT_SHA}" -PinfoGitBranch="${CI_COMMIT_BRANCH}" -PinfoBuildSource="GitLab CI (${CI_PIPELINE_ID})" --gradle-user-home cache/;
|
||||||
- ./gradlew mergeJars -PmcVer="${MC_VER}" -PinfoGitCommit="${CI_COMMIT_SHA}" -PinfoGitBranch="${CI_COMMIT_BRANCH}" -PinfoBuildSource="GitLab CI (${CI_PIPELINE_ID})" --gradle-user-home cache/;
|
- cp ./fabric/build/libs/* ./forge/build/libs/* ./neoforge/build/libs/* ./build/forgix/* . || true
|
||||||
- cp ./fabric/build/libs/* ./forge/build/libs/* ./neoforge/build/libs/* ./build/merged/* . || true
|
|
||||||
artifacts:
|
artifacts:
|
||||||
name: "NightlyBuild_${MC_VER}-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
|
name: "NightlyBuild_${MC_VER}-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
|
||||||
paths:
|
paths:
|
||||||
@@ -102,3 +106,17 @@ pages:
|
|||||||
- public
|
- public
|
||||||
allow_failure: false
|
allow_failure: false
|
||||||
extends: .build_java
|
extends: .build_java
|
||||||
|
|
||||||
|
translations:
|
||||||
|
stage: translations
|
||||||
|
needs: []
|
||||||
|
image: crowdin/cli:latest
|
||||||
|
script:
|
||||||
|
- if [ "$CI_COMMIT_BEFORE_SHA" = "0000000000000000000000000000000000000000" ] || git diff --name-only "$CI_COMMIT_BEFORE_SHA" "$CI_COMMIT_SHA" -- coreSubProjects/core/src/main/resources/assets/distanthorizons/lang | grep -q .; then crowdin upload sources; fi
|
||||||
|
- crowdin download --export-only-approved --skip-untranslated-files
|
||||||
|
- for f in coreSubProjects/core/src/main/resources/assets/distanthorizons/lang/*.json; do [ -e "$f" ] || continue; sed -i 's/\\\\n/\\n/g' "$f"; n="$(basename "$f" | tr '[:upper:]' '[:lower:]')"; [ "$(basename "$f")" = "$n" ] || mv "$f" "$(dirname "$f")/$n"; done
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- coreSubProjects/core/src/main/resources/assets/distanthorizons/lang/**
|
||||||
|
expire_in: 1 day
|
||||||
|
when: always
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
# See mailmap docs: https://git-scm.com/docs/gitmailmap
|
||||||
|
# Test with git shortlog --summary --email
|
||||||
|
# Keep sorted for easier editing and smaller diffs
|
||||||
|
|
||||||
|
Ada Aster <an.ada.poirier@gmail.com>
|
||||||
|
CodeF53 <fseusb@gmail.com> <37855219+CodeF53@users.noreply.github.com>
|
||||||
|
coolGi <me@coolgi.dev> <sasanaps@hotmail.com>
|
||||||
|
James Seibel <jeseibel@gondtc.com> <jseibel@vertsys.com>
|
||||||
|
Morippi <leoleo97@libero.it> <leoloe97@libero.it>
|
||||||
|
Morippi <leoleo97@libero.it> <Morippi>
|
||||||
|
Ran <43445785+Ran-Mewo@users.noreply.github.com> <10044908-_Ran@users.noreply.gitlab.com>
|
||||||
|
Ran <43445785+Ran-Mewo@users.noreply.github.com> <43445785+Ran-Mewo@users.noreply.github.com>
|
||||||
|
Ran <43445785+Ran-Mewo@users.noreply.github.com> <43445785+RanCraftPlayz@users.noreply.github.com>
|
||||||
|
TomTheFurry <tomlee92502@yahoo.com>
|
||||||
|
TomTheFurry <tomlee92502@yahoo.com> <46843632+TomTheFurry@users.noreply.github.com>
|
||||||
|
Yeshi <yeshi@newengine.org>
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="distant-horizons [cleanroom:runClient]" type="GradleRunConfiguration" factoryName="Gradle">
|
||||||
|
<ExternalSystemSettings>
|
||||||
|
<option name="executionName" />
|
||||||
|
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||||
|
<option name="externalSystemIdString" value="GRADLE" />
|
||||||
|
<option name="scriptParameters" value="" />
|
||||||
|
<option name="taskDescriptions">
|
||||||
|
<list />
|
||||||
|
</option>
|
||||||
|
<option name="taskNames">
|
||||||
|
<list>
|
||||||
|
<option value="cleanroom:runClient" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
<option name="vmOptions" />
|
||||||
|
</ExternalSystemSettings>
|
||||||
|
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
|
||||||
|
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
|
||||||
|
<ExternalSystemDebugDisabled>false</ExternalSystemDebugDisabled>
|
||||||
|
<DebugAllEnabled>false</DebugAllEnabled>
|
||||||
|
<RunAsTest>false</RunAsTest>
|
||||||
|
<GradleProfilingDisabled>false</GradleProfilingDisabled>
|
||||||
|
<GradleCoverageDisabled>false</GradleCoverageDisabled>
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
-12
@@ -1,12 +0,0 @@
|
|||||||
FROM eclipse-temurin:17-jdk
|
|
||||||
|
|
||||||
WORKDIR /home/build/
|
|
||||||
COPY ./gradlew .
|
|
||||||
RUN chmod +x ./gradlew
|
|
||||||
CMD echo "\r========== [CLEAN: $MC_VER] ==========" && \
|
|
||||||
./gradlew clean -PmcVer="$MC_VER" --gradle-user-home .gradle-cache/ && \
|
|
||||||
echo "\r========== [BUILD: $MC_VER] ==========" && \
|
|
||||||
./gradlew build -PmcVer="$MC_VER" --gradle-user-home .gradle-cache/ && \
|
|
||||||
echo "\r========== [MERGE: $MC_VER] ==========" && \
|
|
||||||
./gradlew mergeJars -PmcVer="$MC_VER" --gradle-user-home .gradle-cache/ && \
|
|
||||||
echo "\r========== [DONE: $MC_VER] =========="
|
|
||||||
@@ -12,91 +12,18 @@ Below is a video demonstrating the system:
|
|||||||
|
|
||||||
<a href="https://youtu.be/SxQdbtjGEsc" target="_blank"></a>
|
<a href="https://youtu.be/SxQdbtjGEsc" target="_blank"></a>
|
||||||
|
|
||||||
<br>
|
## Translations
|
||||||
|
|
||||||
## Minecraft and Library Versions
|
|
||||||
|
|
||||||
### This branch supports the following versions of Minecraft:
|
|
||||||
|
|
||||||
#### 1.20.4, 1.20.3 (Default)
|
|
||||||
Fabric: 0.15.1\
|
|
||||||
Fabric API: 0.91.2+1.20.4\
|
|
||||||
Forge: 49.0.30\
|
|
||||||
NeoForge: 118-beta\
|
|
||||||
Parchment: 1.20.2:2023.12.10\
|
|
||||||
Modmenu: 9.0.0-pre.1
|
|
||||||
|
|
||||||
#### 1.20.2
|
|
||||||
Fabric: 0.14.24\
|
|
||||||
Fabric API: 0.90.4+1.20.2\
|
|
||||||
Forge: 48.0.13\
|
|
||||||
Parchment: 1.20.1:2023.09.03\
|
|
||||||
Modmenu: 8.0.0
|
|
||||||
|
|
||||||
#### 1.20.1, 1.20
|
|
||||||
Fabric: 0.14.24\
|
|
||||||
Fabric API: 0.90.4+1.20.1\
|
|
||||||
Forge: 47.2.1\
|
|
||||||
Parchment: 1.20.1:2023.09.03\
|
|
||||||
Modmenu: 7.2.2
|
|
||||||
|
|
||||||
#### 1.19.4
|
|
||||||
Fabric: 0.14.24\
|
|
||||||
Fabric API: 0.87.1+1.19.4\
|
|
||||||
Forge: 45.2.4\
|
|
||||||
Parchment: 1.19.4:2023.06.26\
|
|
||||||
Modmenu: 6.3.1
|
|
||||||
|
|
||||||
#### 1.19.2
|
|
||||||
Fabric: 0.14.24\
|
|
||||||
Fabric API: 0.76.1+1.19.2\
|
|
||||||
Forge: 43.3.2\
|
|
||||||
Parchment: 1.19.2:2022.11.27\
|
|
||||||
Modmenu: 4.2.0-beta.2
|
|
||||||
|
|
||||||
#### 1.18.2
|
|
||||||
Fabric: 0.14.24\
|
|
||||||
Fabric API: 0.76.0+1.18.2\
|
|
||||||
Forge: 40.2.10\
|
|
||||||
Parchment: 1.18.2:2022.11.06\
|
|
||||||
Modmenu: 3.2.5
|
|
||||||
|
|
||||||
#### 1.17.1, 1.17
|
|
||||||
Fabric: 0.14.24\
|
|
||||||
Fabric API: 0.46.1+1.17\
|
|
||||||
Forge: 37.1.1\
|
|
||||||
Parchment: 1.17.1:2021.12.12\
|
|
||||||
Modmenu: 2.0.14
|
|
||||||
|
|
||||||
#### 1.16.5, 1.16.4
|
|
||||||
Fabric: 0.14.24\
|
|
||||||
Fabric API: 0.42.0+1.16\
|
|
||||||
Forge: 36.2.39\
|
|
||||||
Parchment: 1.16.5:2022.03.06\
|
|
||||||
Modmenu: 1.16.22
|
|
||||||
|
|
||||||
### Versions no longer supported
|
|
||||||
- 1.18.1, 1.18
|
|
||||||
- 1.19.1, 1.19
|
|
||||||
- 1.19.3
|
|
||||||
|
|
||||||
<br>
|
|
||||||
|
|
||||||
### Plugin and Library versions
|
|
||||||
|
|
||||||
Gradle: 8.5\
|
|
||||||
Fabric loom: 1.4-SNAPSHOT\
|
|
||||||
Architectury loom (Forge gradle replacement): 1.4-SNAPSHOT\
|
|
||||||
Sponge vanilla gradle: 0.2.1-SNAPSHOT\
|
|
||||||
Java Preprocessor plugin: Manifold Preprocessor
|
|
||||||
|
|
||||||
|
[](https://crowdin.com/project/distant-horizons)\
|
||||||
|
Crowdin Project: [Distant Horizons](https://crowdin.com/project/distant-horizons)\
|
||||||
|
Guidelines: [translations.md](translations.md)
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
## Source Code Installation
|
## Source Code Installation
|
||||||
|
|
||||||
### Prerequisites
|
### Prerequisites
|
||||||
|
|
||||||
* A Java Development Kit (JDK) for Java 17 (recommended) or newer. <br>
|
* A Java Development Kit (JDK) for Java 25 (recommended) or newer. <br>
|
||||||
Visit https://www.oracle.com/java/technologies/downloads/ for installers.
|
Visit https://www.oracle.com/java/technologies/downloads/ for installers.
|
||||||
* Git or someway to clone git projects. <br>
|
* Git or someway to clone git projects. <br>
|
||||||
Visit https://git-scm.com/ for installers.
|
Visit https://git-scm.com/ for installers.
|
||||||
@@ -104,15 +31,10 @@ Java Preprocessor plugin: Manifold Preprocessor
|
|||||||
|
|
||||||
**If using IntelliJ:**
|
**If using IntelliJ:**
|
||||||
1. Install the Manifold plugin
|
1. Install the Manifold plugin
|
||||||
|
- https://plugins.jetbrains.com/plugin/10057-manifold-ij
|
||||||
2. Open IDEA and import the build.gradle
|
2. Open IDEA and import the build.gradle
|
||||||
3. Refresh the Gradle project in IDEA if required
|
3. Refresh the Gradle project in IDEA if required
|
||||||
|
|
||||||
**If using Eclipse: (Note that Eclipse doesn't support Manifold's preprocessor!)**
|
|
||||||
1. Run the command: `./gradlew geneclipseruns`
|
|
||||||
2. Run the command: `./gradlew eclipse`
|
|
||||||
3. Make sure eclipse has the JDK 17 installed. (This is needed so that eclipse can run minecraft)
|
|
||||||
4. Import the project into eclipse
|
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
## Switching Versions
|
## Switching Versions
|
||||||
@@ -127,72 +49,42 @@ In IntelliJ, you will also need to do a gradle sync if it didn't happen automati
|
|||||||
## Compiling
|
## Compiling
|
||||||
|
|
||||||
Prerequisites:
|
Prerequisites:
|
||||||
- JDK 17 or newer
|
- JDK 25 or newer
|
||||||
|
|
||||||
From the File Explorer:
|
|
||||||
1. Download and extract the project zip
|
|
||||||
2. Download the core from https://gitlab.com/distant-horizons-team/distant-horizons-core and extract into a folder called `coreSubProjects`
|
|
||||||
3. Open a terminal emulator in the project folder (On Windows you can type `cmd` in the title bar)
|
|
||||||
4. Run the commands: `./gradlew assemble` (You may need to use a `.\` on Windows)
|
|
||||||
5. Merge the jars with `./gradlew mergeJars`
|
|
||||||
6. The compiled jar file will be in the folder `Merged`
|
|
||||||
|
|
||||||
From the command line:
|
From the command line:
|
||||||
1. `git clone --recurse-submodules https://gitlab.com/distant-horizons-team/distant-horizons.git`
|
1. `git clone --recurse-submodules https://gitlab.com/distant-horizons-team/distant-horizons.git`
|
||||||
2. `cd distant-horizons`
|
2. `cd distant-horizons`
|
||||||
3. `./gradlew assemble`
|
3. `./gradlew assemble`
|
||||||
4. `./gradlew mergeJars`
|
5. The compiled jar file will be in the folder `\build\libs`
|
||||||
5. The compiled jar file will be in the folder `Merged`
|
|
||||||
|
|
||||||
Run tests with: `./gradlew test`
|
From the File Explorer:
|
||||||
|
1. Download and extract the project zip
|
||||||
|
2. Download the core from https://gitlab.com/distant-horizons-team/distant-horizons-core and extract into a folder called `coreSubProjects`
|
||||||
|
3. Open command prompt/terminal in the project folder
|
||||||
|
4. Run the commands: `./gradlew assemble`
|
||||||
|
6. The compiled jar file will be in the folder `\build\libs`
|
||||||
|
|
||||||
>Note: You can add the argument `-PmcVer=?` to tell gradle to build a selected MC version instead of having to modify the `gradle.properties` file.\
|
>Note: You can add the argument `-PmcVer=?` to tell gradle to build a selected MC version instead of having to modify the `gradle.properties` file.\
|
||||||
> For example: `./gradlew assemble -PmcVer=1.18.2`
|
> For example: `./gradlew assemble -PmcVer=1.18.2`
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
## Compiling with Docker
|
|
||||||
|
|
||||||
`./compile <version>`
|
|
||||||
|
|
||||||
You can also locally compile the DH jars without a Java environment by using Docker. Where `<version>` is the version of Minecraft to compile for (ie `1.20.1`), or the keyword `all`. See [Versions](#minecraft-and-library-versions) for a list of all supported values.
|
|
||||||
|
|
||||||
<br>
|
|
||||||
|
|
||||||
## Other commands
|
## Other commands
|
||||||
|
|
||||||
`./gradlew --refresh-dependencies` to refresh local dependencies.
|
|
||||||
|
|
||||||
`./gradlew clean` to delete any compiled code.
|
|
||||||
|
|
||||||
<br>
|
|
||||||
|
|
||||||
## Note to self
|
|
||||||
|
|
||||||
The Minecraft source code is NOT added to your workspace in an editable way. Minecraft is treated like a normal Library. Sources are there for documentation and research purposes only.
|
|
||||||
|
|
||||||
Source code uses Mojang mappings & [Parchment](https://parchmentmc.org/) mappings.
|
|
||||||
|
|
||||||
To generate the source code run `./gradlew genSources` <br>
|
|
||||||
If your IDE fails to auto-detect the source jars when browsing Minecraft classes; manually select the JAR file ending with -sources.jar when prompted by your IDE. <br>
|
|
||||||
(In IntelliJ it's at the top where it says "choose sources" when browsing a Minecraft class)
|
|
||||||
|
|
||||||
<br>
|
|
||||||
|
|
||||||
## Other Useful commands
|
|
||||||
|
|
||||||
Run the standalone jar: `./gradlew run` <br>
|
Run the standalone jar: `./gradlew run` <br>
|
||||||
Build the standalone jar: `./gradlew core:build` <br>
|
Build the standalone jar: `./gradlew core:build` <br>
|
||||||
Only build Fabric: `./gradlew fabric:assemble` or `./gradlew fabric:build` <br>
|
Only build Fabric: `./gradlew fabric:assemble` or `./gradlew fabric:build` <br>
|
||||||
Only build Forge: `./gradlew forge:assemble` or `./gradlew forge:build` <br>
|
Only build Forge: `./gradlew forge:assemble` or `./gradlew forge:build` <br>
|
||||||
Run the Fabric client (for debugging): `./gradlew fabric:runClient` <br>
|
Run the Fabric client (for debugging): `./gradlew fabric:runClient` <br>
|
||||||
Run the Forge client (for debugging): `./gradlew forge:runClient` <br>
|
Run the Forge client (for debugging): `./gradlew forge:runClient` <br>
|
||||||
|
Delete all compiled code: `./gradlew clean` <br>
|
||||||
|
Refresh local dependencies: `./gradlew --refresh-dependencies`
|
||||||
|
|
||||||
To build all versions: `./buildAll` (all builds will end up in the `Merged` folder)
|
To build all versions: `./buildAll`
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
## Open Source Acknowledgements
|
## Open Source Libraries
|
||||||
|
|
||||||
Forgix (To merge multiple mod versions into one jar) [_Formerly_ [_DHJarMerger_](https://github.com/Ran-helo/DHJarMerger)]\
|
Forgix (To merge multiple mod versions into one jar) [_Formerly_ [_DHJarMerger_](https://github.com/Ran-helo/DHJarMerger)]\
|
||||||
https://github.com/PacifistMC/Forgix
|
https://github.com/PacifistMC/Forgix
|
||||||
@@ -208,3 +100,18 @@ https://github.com/blackears/svgSalamander
|
|||||||
|
|
||||||
sqlite-jdbc\
|
sqlite-jdbc\
|
||||||
https://github.com/xerial/sqlite-jdbc
|
https://github.com/xerial/sqlite-jdbc
|
||||||
|
|
||||||
|
|
||||||
|
## Acknowledgements
|
||||||
|
|
||||||
|
Distant Horizons has been graciously provided an open source license for <a href="https://www.yourkit.com/java/profiler/">YourKit Java Profiler</a>.
|
||||||
|
|
||||||
|
> <img src="https://www.yourkit.com/images/yklogo.png">
|
||||||
|
>
|
||||||
|
> YourKit supports open source projects with innovative and intelligent tools
|
||||||
|
for monitoring and profiling Java and .NET applications.
|
||||||
|
YourKit is the creator of <a href="https://www.yourkit.com/java/profiler/">YourKit Java Profiler</a>,
|
||||||
|
<a href="https://www.yourkit.com/dotnet-profiler/">YourKit .NET Profiler</a>,
|
||||||
|
and <a href="https://www.yourkit.com/youmonitor/">YourKit YouMonitor</a>.
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+23
-719
@@ -1,730 +1,34 @@
|
|||||||
import com.github.jengelman.gradle.plugins.shadow.transformers.Transformer
|
|
||||||
import com.github.jengelman.gradle.plugins.shadow.transformers.TransformerContext
|
|
||||||
import org.apache.tools.zip.ZipEntry
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull
|
|
||||||
import org.apache.tools.zip.ZipOutputStream
|
|
||||||
|
|
||||||
import java.util.function.Function
|
|
||||||
import java.util.function.Predicate
|
|
||||||
|
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id "java"
|
id 'root'
|
||||||
|
id 'io.github.pacifistmc.forgix' version '2.+'
|
||||||
// Plugin to put dependencies inside our final jar
|
|
||||||
id "com.github.johnrengelman.shadow" version '8.1.1' apply false
|
|
||||||
|
|
||||||
// Plugin to create merged jars
|
|
||||||
id "io.github.pacifistmc.forgix" version "1.3.4"
|
|
||||||
|
|
||||||
// Manifold preprocessor
|
|
||||||
id "systems.manifold.manifold-gradle-plugin" version "0.0.2-alpha"
|
|
||||||
|
|
||||||
// Architectury is used here only as a replacement for forge's own loom
|
|
||||||
id "dev.architectury.loom" version "1.13-SNAPSHOT" apply false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
forgix {
|
||||||
|
|
||||||
/**
|
// add the mod loaders to the end of the jar
|
||||||
* Creates the list of preprocessors to use.
|
// put together in the format: "a", "a-b", "a-b-c"
|
||||||
*
|
int loaderCount = 0;
|
||||||
* @param mcVers array of all MC versions
|
String modLoaders = "";
|
||||||
* @param mcIndex array index of the currently active MC version
|
((String) gradle.builds_for)
|
||||||
*/
|
.split(",")
|
||||||
def writeBuildGradlePredefine(List<String> mcVers, int mcIndex)
|
.each
|
||||||
{
|
{ loader ->
|
||||||
// Build the list of preprocessors to use
|
def loaderName = loader.trim()
|
||||||
StringBuilder sb = new StringBuilder();
|
if (modLoaders != "")
|
||||||
|
{
|
||||||
|
modLoaders += "-";
|
||||||
|
}
|
||||||
|
|
||||||
sb.append("# DON'T TOUCH THIS FILE, This is handled by the build script\n");
|
modLoaders += loaderName;
|
||||||
|
|
||||||
|
loaderCount++;
|
||||||
for (int i = 0; i < mcVers.size(); i++)
|
|
||||||
{
|
|
||||||
String verStr = mcVers[i].replace(".", "_");
|
|
||||||
sb.append("MC_" + verStr + "=" + i.toString() + "\n");
|
|
||||||
|
|
||||||
if (mcIndex == i)
|
|
||||||
{
|
|
||||||
sb.append("MC_VER=" + i.toString() + "\n");
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
// run if there are multiple launchers that need merging
|
||||||
|
autoRun = (loaderCount > 1);
|
||||||
|
|
||||||
// Check if this is a development build
|
// merged jars are named in the format:
|
||||||
if (mod_version.toLowerCase().contains("dev"))
|
// "DistantHorizons-3.0.1-b-dev-26.1-fabric-neoforge.jar"
|
||||||
{
|
archiveClassifier = modLoaders
|
||||||
// WARNING: only use this for logging, we don't want to have confusion
|
|
||||||
// when a method doesn't work correctly in the release build.
|
|
||||||
sb.append("DEV_BUILD=\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
new File(projectDir, "build.properties").text = sb.toString()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Transfers the values set in settings.gradle to the rest of the project
|
|
||||||
project.gradle.ext.getProperties().each { prop ->
|
|
||||||
rootProject.ext.set(prop.key, prop.value)
|
|
||||||
//println "Added prop [key:" + prop.key + ", value:" + prop.value + "]"
|
|
||||||
}
|
|
||||||
// Sets up manifold stuff
|
|
||||||
writeBuildGradlePredefine(rootProject.mcVers, rootProject.mcIndex)
|
|
||||||
|
|
||||||
// Sets up the version string (the name we use for our jar)
|
|
||||||
rootProject.versionStr = rootProject.mod_version + "-" + rootProject.minecraft_version // + "-" + new Date().format("yyyy_MM_dd_HH_mm")
|
|
||||||
|
|
||||||
class NativeTransformer implements Transformer {
|
|
||||||
private Predicate<String> fileMatcher
|
|
||||||
private Function<String, String> filePathMapper
|
|
||||||
|
|
||||||
private final HashMap<String, String> replacements = new HashMap()
|
|
||||||
private final HashMap<String, byte[]> rewrittenFiles = new HashMap()
|
|
||||||
private var nativeRelocator
|
|
||||||
|
|
||||||
public File rootDir
|
|
||||||
|
|
||||||
void matchFiles(Predicate<String> matcher) {
|
|
||||||
fileMatcher = matcher
|
|
||||||
}
|
|
||||||
|
|
||||||
void mapPaths(Function<String, String> mapper) {
|
|
||||||
filePathMapper = mapper
|
|
||||||
}
|
|
||||||
|
|
||||||
void relocateNative(String target, String replacement) {
|
|
||||||
if (replacement.length() > target.length()) {
|
|
||||||
throw new GradleException("Length of value \"${replacement}\" exceeds the length of \"${target}\": ${replacement.length()} > ${target.length()}")
|
|
||||||
}
|
|
||||||
|
|
||||||
replacements.put(target, replacement)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
boolean canTransformResource(@Nonnull FileTreeElement element) {
|
|
||||||
return fileMatcher.test(element.name)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
void transform(@Nonnull TransformerContext context) {
|
|
||||||
byte[] content = context.is.readAllBytes()
|
|
||||||
|
|
||||||
if (nativeRelocator == null) {
|
|
||||||
nativeRelocator = new NativeRelocator(rootDir.toPath().resolve("relocate_natives"))
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
String path = filePathMapper != null
|
|
||||||
? filePathMapper.apply(context.path)
|
|
||||||
: context.path
|
|
||||||
content = nativeRelocator.processBinary(path, content, replacements)
|
|
||||||
|
|
||||||
rewrittenFiles.put(path, content)
|
|
||||||
}
|
|
||||||
catch (Throwable e) {
|
|
||||||
throw new GradleException("Failed to relocate", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
boolean hasTransformedResource() { return !rewrittenFiles.isEmpty() }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
void modifyOutputStream(@Nonnull ZipOutputStream os, boolean preserveFileTimestamps) {
|
|
||||||
for (Map.Entry<String, byte[]> rewrittenFile : rewrittenFiles.entrySet()) {
|
|
||||||
os.putNextEntry(new ZipEntry(rewrittenFile.key))
|
|
||||||
os.write(rewrittenFile.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
subprojects { p ->
|
|
||||||
// Does the same as "p == project(":common") || p == project(":fabric") || p == project(":quilt") || p == project(":forge") || p == project("WhateverWeAddLaterOn")"
|
|
||||||
// Useful later on so we dont have duplicated code
|
|
||||||
def isMinecraftSubProject = p != project(":core") && p != project(":api")
|
|
||||||
|
|
||||||
|
|
||||||
// Apply plugins
|
|
||||||
apply plugin: "java"
|
|
||||||
apply plugin: "com.github.johnrengelman.shadow"
|
|
||||||
if (isMinecraftSubProject)
|
|
||||||
apply plugin: "systems.manifold.manifold-gradle-plugin"
|
|
||||||
|
|
||||||
// Apply forge's loom
|
|
||||||
if ((findProject(":forge") && p == project(":forge")) ||
|
|
||||||
(findProject(":neoforge") && p == project(":neoforge"))
|
|
||||||
)
|
|
||||||
{
|
|
||||||
apply plugin: "dev.architectury.loom"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Set the manifold version (may not be required tough)
|
|
||||||
manifold {
|
|
||||||
manifoldVersion = rootProject.manifold_version
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// set up custom configurations (configurations are a way to handle dependencies)
|
|
||||||
configurations {
|
|
||||||
// extends the shadowJar configuration
|
|
||||||
shadowMe
|
|
||||||
// have implemented dependencies automatically embedded in the final jar
|
|
||||||
implementation.extendsFrom(shadowMe)
|
|
||||||
|
|
||||||
// Configuration fpr core & api
|
|
||||||
coreProjects
|
|
||||||
shadowMe.extendsFrom(coreProjects)
|
|
||||||
|
|
||||||
|
|
||||||
// FIXME this additional configuration is necessary because forge
|
|
||||||
// needs forgeRuntimeLibrary, although adding it to shadowMe
|
|
||||||
// causes runtime issues where the libraries aren't properly added
|
|
||||||
forgeShadowMe
|
|
||||||
// this should match shadowMe pretty closely
|
|
||||||
implementation.extendsFrom(forgeShadowMe)
|
|
||||||
shadowMe.extendsFrom(forgeShadowMe)
|
|
||||||
forgeRuntimeLibrary.extendsFrom(forgeShadowMe)
|
|
||||||
|
|
||||||
|
|
||||||
if (isMinecraftSubProject && p != project(":common")) {
|
|
||||||
// Shadow common
|
|
||||||
common
|
|
||||||
shadowCommon // Don't use shadow from the shadow plugin because we don't want IDEA to index this.
|
|
||||||
compileClasspath.extendsFrom common
|
|
||||||
runtimeClasspath.extendsFrom common
|
|
||||||
if (findProject(":forge"))
|
|
||||||
developmentForge.extendsFrom common
|
|
||||||
if (findProject(":neoforge"))
|
|
||||||
developmentNeoForge.extendsFrom common
|
|
||||||
compileClasspath.extendsFrom coreProjects
|
|
||||||
runtimeClasspath.extendsFrom coreProjects
|
|
||||||
if (findProject(":forge"))
|
|
||||||
developmentForge.extendsFrom coreProjects
|
|
||||||
if (findProject(":neoforge"))
|
|
||||||
developmentNeoForge.extendsFrom coreProjects
|
|
||||||
|
|
||||||
// TODO remove unused fabricLike
|
|
||||||
if (findProject(":fabricLike") && p != project(":fabricLike")) {
|
|
||||||
// Shadow fabricLike
|
|
||||||
fabricLike
|
|
||||||
shadowFabricLike
|
|
||||||
compileClasspath.extendsFrom fabricLike
|
|
||||||
runtimeClasspath.extendsFrom fabricLike
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
//=====================//
|
|
||||||
// shared dependencies //
|
|
||||||
//=====================//
|
|
||||||
|
|
||||||
// Manifold
|
|
||||||
if (isMinecraftSubProject) {
|
|
||||||
annotationProcessor("systems.manifold:manifold-preprocessor:${rootProject.manifold_version}")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log4j
|
|
||||||
if (p == project(":core"))
|
|
||||||
{
|
|
||||||
// the standalone core jar needs logging shaded otherwise it won't run
|
|
||||||
forgeShadowMe("org.apache.logging.log4j:log4j-api:${rootProject.log4j_version}")
|
|
||||||
forgeShadowMe("org.apache.logging.log4j:log4j-core:${rootProject.log4j_version}")
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// When running in MC, MC already includes logging
|
|
||||||
implementation("org.apache.logging.log4j:log4j-api:${rootProject.log4j_version}")
|
|
||||||
implementation("org.apache.logging.log4j:log4j-core:${rootProject.log4j_version}")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// JOML
|
|
||||||
if (project.hasProperty("embed_joml") && embed_joml == "true")
|
|
||||||
forgeShadowMe("org.joml:joml:${rootProject.joml_version}")
|
|
||||||
else
|
|
||||||
implementation("org.joml:joml:${rootProject.joml_version}")
|
|
||||||
|
|
||||||
// JUnit tests
|
|
||||||
implementation("org.junit.jupiter:junit-jupiter:5.8.2")
|
|
||||||
implementation("org.junit.jupiter:junit-jupiter-engine:5.8.2")
|
|
||||||
implementation("junit:junit:4.13")
|
|
||||||
|
|
||||||
// FastUtil
|
|
||||||
// Note: MC 1.16 uses 8.2.1, and versions after use 8.5.12
|
|
||||||
// We cannot relocate this library since we call some MC classes that reference it
|
|
||||||
implementation("it.unimi.dsi:fastutil:${rootProject.fastutil_version}")
|
|
||||||
|
|
||||||
forgeShadowMe("com.github.luben:zstd-jni:${rootProject.zstd_version}")
|
|
||||||
|
|
||||||
// Compression
|
|
||||||
forgeShadowMe("org.lz4:lz4-java:${rootProject.lz4_version}") // LZ4
|
|
||||||
forgeShadowMe("org.tukaani:xz:${rootProject.xz_version}") // LZMA
|
|
||||||
|
|
||||||
// Sqlite Database
|
|
||||||
forgeShadowMe("org.xerial:sqlite-jdbc:${rootProject.sqlite_jdbc_version}")
|
|
||||||
|
|
||||||
// NightConfig (includes Toml & Json)
|
|
||||||
forgeShadowMe("com.electronwill.night-config:toml:${rootProject.nightconfig_version}")
|
|
||||||
forgeShadowMe("com.electronwill.night-config:json:${rootProject.nightconfig_version}")
|
|
||||||
|
|
||||||
// SVG (not needed atm)
|
|
||||||
// forgeShadowMe("com.formdev:svgSalamander:${rootProject.svgSalamander_version}")
|
|
||||||
|
|
||||||
// Netty
|
|
||||||
implementation("io.netty:netty-buffer:${rootProject.netty_version}")
|
|
||||||
|
|
||||||
// Remember, for lwjgl dependencies that arent included in Minecraft, you need to also need to add it to the ShadowJar thing
|
|
||||||
forgeShadowMe("org.lwjgl:lwjgl-jawt:${rootProject.lwjgl_version}") {
|
|
||||||
exclude group: "org.lwjgl", module: "lwjgl" // This module is imported by Minecraft so exclude it
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//==========================//
|
|
||||||
// conditional dependencies //
|
|
||||||
//==========================//
|
|
||||||
|
|
||||||
|
|
||||||
// Add core
|
|
||||||
if (isMinecraftSubProject) {
|
|
||||||
coreProjects(project(":core")) {
|
|
||||||
// Remove Junit test libraries
|
|
||||||
exclude group: "org.junit.jupiter", module: "junit-jupiter"
|
|
||||||
exclude group: "org.junit.jupiter", module: "junit-jupiter-engine"
|
|
||||||
exclude group: "junit", module: "junit"
|
|
||||||
// Removed dependencies
|
|
||||||
transitive false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the api
|
|
||||||
if (p != project(":api")) {
|
|
||||||
coreProjects(project(":api")) {
|
|
||||||
// Remove Junit test libraries
|
|
||||||
exclude group: "org.junit.jupiter", module: "junit-jupiter"
|
|
||||||
exclude group: "org.junit.jupiter", module: "junit-jupiter-engine"
|
|
||||||
exclude group: "junit", module: "junit"
|
|
||||||
// Removed dependencies
|
|
||||||
transitive false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add common
|
|
||||||
if (isMinecraftSubProject && p != project(":common")) {
|
|
||||||
// Common
|
|
||||||
common(project(":common")) { transitive false }
|
|
||||||
shadowCommon(project(":common")) { transitive false }
|
|
||||||
|
|
||||||
// FabricLike
|
|
||||||
if (findProject(":fabricLike") && p != project(":fabricLike")) {
|
|
||||||
fabricLike(project(path: ":fabricLike")) { transitive false }
|
|
||||||
shadowFabricLike(project(path: ":fabricLike")) { transitive false }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
shadowJar {
|
|
||||||
configurations = [project.configurations.shadowMe]
|
|
||||||
if (isMinecraftSubProject && p != project(":common")) {
|
|
||||||
configurations.push(project.configurations.shadowCommon) // Shadow the common subproject
|
|
||||||
relocate "com.seibel.distanthorizons.common", "loaderCommon.${p.name}.com.seibel.distanthorizons.common" // Move the loader files to a different location
|
|
||||||
|
|
||||||
if (findProject(":fabricLike") && p != project(":fabricLike")) {
|
|
||||||
configurations.push(project.configurations.shadowFabricLike) // Shadow the fabricLike subproject
|
|
||||||
relocate "com.seibel.distanthorizons.fabriclike", "loaderCommon.${p.name}.com.seibel.distanthorizons.fabriclike" // Move the loader files to a different location
|
|
||||||
}
|
|
||||||
}
|
|
||||||
def librariesLocation = "DistantHorizons.libraries"
|
|
||||||
|
|
||||||
// LWJGL
|
|
||||||
// Only ever shadow the dependencies we use otherwise some stuff would break when running on an external client
|
|
||||||
relocate "org.lwjgl.system.jawt", "${librariesLocation}.lwjgl.system.jawt"
|
|
||||||
|
|
||||||
// Compression (LZ4)
|
|
||||||
relocate "net.jpountz", "${librariesLocation}.jpountz"
|
|
||||||
|
|
||||||
// Logging
|
|
||||||
relocate "org.slf4j", "${librariesLocation}.slf4j"
|
|
||||||
|
|
||||||
// Sqlite Database
|
|
||||||
// librariesLocation isn't used because it's too long for replacing paths in native libraries
|
|
||||||
// Allowing strings larger than the original string would require shifting the entire binary's contents
|
|
||||||
relocate "org.sqlite", "dh_sqlite", {
|
|
||||||
exclude "org/sqlite/native/**"
|
|
||||||
}
|
|
||||||
relocate "jdbc:sqlite", "jdbc:dh_sqlite"
|
|
||||||
|
|
||||||
transform(NativeTransformer) {
|
|
||||||
rootDir = project.rootDir
|
|
||||||
|
|
||||||
matchFiles { it.startsWith("org/sqlite") }
|
|
||||||
mapPaths { it.replace("org/sqlite", "dh_sqlite") }
|
|
||||||
|
|
||||||
relocateNative "org/sqlite", "dh_sqlite"
|
|
||||||
relocateNative "org_sqlite", "dh_1sqlite"
|
|
||||||
}
|
|
||||||
|
|
||||||
// ZStd
|
|
||||||
// librariesLocation isn't used because it's too long for replacing paths in native libraries
|
|
||||||
// Allowing strings larger than the original string would require shifting the entire binary's contents
|
|
||||||
relocate "com.github.luben", "dhcomgithubluben"
|
|
||||||
relocate "libzstd-jni", "libzstd-jni_dh"
|
|
||||||
relocate "zstd-jni", "zstd-jni_dh"
|
|
||||||
|
|
||||||
transform(NativeTransformer) {
|
|
||||||
rootDir = project.rootDir
|
|
||||||
|
|
||||||
matchFiles { it.contains("libzstd-jni") && !it.contains("aix/ppc64") }
|
|
||||||
mapPaths { it.replace("libzstd-jni", "libzstd-jni_dh") }
|
|
||||||
|
|
||||||
relocateNative "com/github/luben", "dhcomgithubluben"
|
|
||||||
relocateNative "com_github_luben", "dhcomgithubluben"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// JOML
|
|
||||||
if (project.hasProperty("embed_joml") && embed_joml == "true")
|
|
||||||
relocate "org.joml", "${librariesLocation}.joml"
|
|
||||||
|
|
||||||
// NightConfig (includes Toml & Json)
|
|
||||||
relocate "com.electronwill.nightconfig", "${librariesLocation}.electronwill.nightconfig"
|
|
||||||
|
|
||||||
// SVG (not needed atm)
|
|
||||||
// relocate "com.kitfox.svg", "${librariesLocation}.kitfox.svg"
|
|
||||||
|
|
||||||
// Netty
|
|
||||||
// Don't relocate, it causes problems with using MC's FriendlyByteBufs
|
|
||||||
// relocate "io.netty", "${librariesLocation}.netty"
|
|
||||||
|
|
||||||
mergeServiceFiles()
|
|
||||||
}
|
|
||||||
// Using jar.finalizedBy(shadowJar) causes issues so we do this scuffed bypass
|
|
||||||
jar.dependsOn(shadowJar)
|
|
||||||
|
|
||||||
|
|
||||||
// Put stuff from gradle.properties into the mod info
|
|
||||||
processResources {
|
|
||||||
def resourceTargets = [ // Location of where to inject the properties
|
|
||||||
// Holds info like git commit
|
|
||||||
// TODO: For some reason this script doesnt work with the core project
|
|
||||||
"build_info.json",
|
|
||||||
|
|
||||||
// Properties for each of the loaders
|
|
||||||
"fabric.mod.json",
|
|
||||||
"quilt.mod.json",
|
|
||||||
"META-INF/mods.toml",
|
|
||||||
"META-INF/neoforge.mods.toml",
|
|
||||||
|
|
||||||
// The mixins for each of the loaders
|
|
||||||
"DistantHorizons."+ p.name +".fabricLike.mixins.json"
|
|
||||||
]
|
|
||||||
def intoTargets = ["$buildDir/resources/main/"] // Location of the built resources folder
|
|
||||||
|
|
||||||
// Fix forge version numbering system as it is weird
|
|
||||||
// For whatever reason forge uses [1.18, 1.18.1, 1.18.2) instead of the standard ["1.18", "1.18.1", "1.18.2"]
|
|
||||||
def compatible_forgemc_versions = "${compatible_minecraft_versions}".replaceAll("\"", "").replaceAll("]", ",)")
|
|
||||||
// println compatible_forgemc_versions
|
|
||||||
|
|
||||||
// Quilt's custom contributors system
|
|
||||||
// This has to be like
|
|
||||||
// "Person": "Developer", "Another person": "Developer"
|
|
||||||
def quilt_contributors = []
|
|
||||||
def mod_author_list = mod_authors.replaceAll("\"", "").replace("[", "").replace("]", "").split(",")
|
|
||||||
for (dev in mod_author_list) {
|
|
||||||
quilt_contributors.push("\"${dev.strip()}\": \"Developer\"")
|
|
||||||
}
|
|
||||||
quilt_contributors.reverse()
|
|
||||||
//println quilt_contributors.join(", ")
|
|
||||||
|
|
||||||
// TODO: Find something we can use so we can basically re-map only when the jar is shadowed and relocated
|
|
||||||
// println p.tasks.findByName('shadowJar')
|
|
||||||
|
|
||||||
|
|
||||||
// These "hasProperty"'s are so that they can be passed through the cli (ie in the CI)
|
|
||||||
try {
|
|
||||||
if (infoGitCommit == "null")
|
|
||||||
infoGitCommit = 'git rev-parse --verify HEAD'.execute().text.trim()
|
|
||||||
if (infoGitBranch == "null")
|
|
||||||
infoGitBranch = 'git symbolic-ref --short HEAD'.execute().text.trim()
|
|
||||||
} catch (Exception e) {
|
|
||||||
infoGitCommit = infoGitBranch = "Git not found"
|
|
||||||
println "Git or Git project not found"
|
|
||||||
}
|
|
||||||
|
|
||||||
// The left side is what gets replaced in the mod info and the right side is where to get it from in the gradle.properties
|
|
||||||
def replaceProperties = [
|
|
||||||
version : mod_version,
|
|
||||||
mod_name : mod_readable_name,
|
|
||||||
group : maven_group,
|
|
||||||
authors : mod_authors,
|
|
||||||
description : mod_description,
|
|
||||||
homepage : mod_homepage,
|
|
||||||
source : mod_source,
|
|
||||||
issues : mod_issues,
|
|
||||||
discord : mod_discord,
|
|
||||||
minecraft_version : minecraft_version,
|
|
||||||
compatible_minecraft_versions: compatible_minecraft_versions,
|
|
||||||
compatible_forgemc_versions : compatible_forgemc_versions,
|
|
||||||
java_version : java_version,
|
|
||||||
quilt_contributors : "{"+quilt_contributors.join(", ")+"}",
|
|
||||||
|
|
||||||
info_git_commit : infoGitBranch,
|
|
||||||
info_git_branch : infoGitCommit,
|
|
||||||
info_build_source : infoBuildSource,
|
|
||||||
|
|
||||||
fabric_incompatibility_list : fabric_incompatibility_list,
|
|
||||||
fabric_recommend_list : fabric_recommend_list,
|
|
||||||
|
|
||||||
neoforge_version_range : neoforge_version_range,
|
|
||||||
]
|
|
||||||
|
|
||||||
// replace any properties in the sub-projects with the values defined here
|
|
||||||
inputs.properties replaceProperties
|
|
||||||
replaceProperties.put "project", project
|
|
||||||
filesMatching(resourceTargets) {
|
|
||||||
expand replaceProperties
|
|
||||||
}
|
|
||||||
|
|
||||||
intoTargets.each { target ->
|
|
||||||
if (file(target).exists()) {
|
|
||||||
copy {
|
|
||||||
from(sourceSets.main.resources) {
|
|
||||||
include resourceTargets
|
|
||||||
expand replaceProperties
|
|
||||||
}
|
|
||||||
into target
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ==================== Delete un-needed files ====================
|
|
||||||
exclude "DistantHorizons.fabricLike.mixins.json" // This isnt required atm, but we will be using it later
|
|
||||||
|
|
||||||
// exclude "*.distanthorizons.accesswidener"
|
|
||||||
//// include "${accessWidenerVersion}.distanthorizons.accesswidener"
|
|
||||||
|
|
||||||
// Jank solution to remove all unused accesswideners
|
|
||||||
// The line above would work..., except that (neo)forge (well, mainly architectury) requires the original accesswidener file, meaning we require this jank solution to keep it
|
|
||||||
exclude { file ->
|
|
||||||
if (file.name.contains(".distanthorizons.accesswidener") && file.name != "${accessWidenerVersion}.distanthorizons.accesswidener") {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Adds the standalone jar's entrypoint
|
|
||||||
jar {
|
|
||||||
from "LICENSE.txt"
|
|
||||||
manifest {
|
|
||||||
attributes(
|
|
||||||
'Implementation-Title': rootProject.mod_name,
|
|
||||||
'Implementation-Version': rootProject.mod_version,
|
|
||||||
'Multi-Release': true, // needed for logging in the standalone core jar
|
|
||||||
'Main-Class': 'com.seibel.distanthorizons.core.jar.JarMain', // When changing the main of the jar change this line
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// this can be un-commented if we ever wanted to make DH modular (AKA use a module-info.java file) again
|
|
||||||
/*
|
|
||||||
// Tells gradle where to look for other modules
|
|
||||||
// Why isn't the classpath added to the modules path by default?
|
|
||||||
if (p == project(":core")) {
|
|
||||||
compileJava {
|
|
||||||
inputs.property('moduleName', 'dhApi')
|
|
||||||
doFirst {
|
|
||||||
options.compilerArgs = [
|
|
||||||
'--module-path', classpath.asPath
|
|
||||||
]
|
|
||||||
classpath = files()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
allprojects { p ->
|
|
||||||
// Does the same as "p == project(":common") || p == project(":fabric") || p == project(":quilt") || p == project(":forge") || p == project("WhateverWeAddLaterOn")"
|
|
||||||
// Useful later on so we dont have duplicated code
|
|
||||||
def isMinecraftSubProject = p != project(":core") && p != project(":api")
|
|
||||||
|
|
||||||
|
|
||||||
apply plugin: "java"
|
|
||||||
apply plugin: "maven-publish"
|
|
||||||
|
|
||||||
// Sets the name of the jar, the version will contain the name of the project if it isn't the root project
|
|
||||||
archivesBaseName = rootProject.mod_name
|
|
||||||
version = (project == rootProject ? "" : project.name + "-") + rootProject.versionStr
|
|
||||||
group = rootProject.maven_group
|
|
||||||
|
|
||||||
// this is the text that appears at the top of the overview (home) page
|
|
||||||
// and is used when bookmarking a page
|
|
||||||
javadoc.title = rootProject.mod_name + "-" + project.name
|
|
||||||
|
|
||||||
// Some annotations arent "technically" part of the official java standard,
|
|
||||||
// so we define it ourself here
|
|
||||||
javadoc {
|
|
||||||
configure( options ) {
|
|
||||||
tags(
|
|
||||||
'todo:X"',
|
|
||||||
'apiNote:a:API Note:',
|
|
||||||
'implSpec:a:Implementation Requirements:',
|
|
||||||
'implNote:a:Implementation Note:'
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
repositories {
|
|
||||||
// Mojang overrides (added to fix downloading the wrong LWJGL libs on M1 Mac's and potentially other arm64 based machines)
|
|
||||||
maven { url "https://libraries.minecraft.net/" }
|
|
||||||
|
|
||||||
// The central repo
|
|
||||||
mavenCentral()
|
|
||||||
|
|
||||||
// Used for Google's Collect library
|
|
||||||
maven { url "https://repo.enonic.com/public/" }
|
|
||||||
|
|
||||||
// For parchment mappings
|
|
||||||
// versions can be found here: https://ldtteam.jfrog.io/ui/native/parchmentmc-public/org/parchmentmc/data/
|
|
||||||
maven { url "https://maven.parchmentmc.org" }
|
|
||||||
|
|
||||||
// For Architectury API
|
|
||||||
maven { url "https://maven.architectury.dev" }
|
|
||||||
|
|
||||||
// For Git repositories
|
|
||||||
maven { url "https://jitpack.io" }
|
|
||||||
|
|
||||||
// For Manifold Preprocessor
|
|
||||||
maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
|
|
||||||
|
|
||||||
// Required for importing Modrinth mods
|
|
||||||
maven {
|
|
||||||
name = "Modrinth"
|
|
||||||
url = "https://api.modrinth.com/maven"
|
|
||||||
content {
|
|
||||||
includeGroup "maven.modrinth"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Required for importing CursedForge mods
|
|
||||||
maven {
|
|
||||||
url "https://www.cursemaven.com"
|
|
||||||
content {
|
|
||||||
includeGroup "curse.maven"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// VanillaGradle and Mixins in common
|
|
||||||
maven { url "https://repo.spongepowered.org/maven/" }
|
|
||||||
|
|
||||||
// Canvas mod
|
|
||||||
maven { url "https://maven.vram.io/" }
|
|
||||||
// ModMenu mod
|
|
||||||
maven { url "https://maven.terraformersmc.com/" }
|
|
||||||
|
|
||||||
// neoforge
|
|
||||||
maven { url "https://maven.neoforged.net/releases/" }
|
|
||||||
|
|
||||||
// These 3 are for importing mods that arnt on CursedForge, Modrinth, GitHub, GitLab or anywhere opensource
|
|
||||||
flatDir {
|
|
||||||
dirs "${rootDir}/mods/fabric"
|
|
||||||
content {
|
|
||||||
includeGroup "fabric-mod"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
flatDir {
|
|
||||||
dirs "${rootDir}/mods/quilt"
|
|
||||||
content {
|
|
||||||
includeGroup "quilt-mod"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
flatDir {
|
|
||||||
dirs "${rootDir}/mods/forge"
|
|
||||||
content {
|
|
||||||
includeGroup "forge-mod"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// TODO: If neoforged is ever needed, should we use that, or call it a forge mod?
|
|
||||||
}
|
|
||||||
|
|
||||||
// Adds some dependencies that are in vanilla but not in core
|
|
||||||
if (p == project(":core")) {
|
|
||||||
OperatingSystem os = org.gradle.nativeplatform.platform.internal.DefaultNativePlatform.currentOperatingSystem;
|
|
||||||
|
|
||||||
// Set the OS lwjgl is using to the current os
|
|
||||||
project.ext.lwjglNatives = "natives-" + os.toFamilyName()
|
|
||||||
|
|
||||||
dependencies { // All of these dependencies are in Vanilla Minecraft, but we need to depend on it as we arent importing Minecraft in the core
|
|
||||||
// Imports most of lwjgl's libraries (well, only the ones that we need)
|
|
||||||
implementation platform("org.lwjgl:lwjgl-bom:${rootProject.lwjgl_version}") // TODO: Use Minecraft's version for lwjgl_version (which changes in nearly every version) instead of a hard defined version for all versions
|
|
||||||
|
|
||||||
// REMEMBER: Dont shadow stuff here, these are just the libs that are included in Minecraft so that the core can use
|
|
||||||
implementation "org.lwjgl:lwjgl"
|
|
||||||
implementation "org.lwjgl:lwjgl-assimp"
|
|
||||||
implementation "org.lwjgl:lwjgl-glfw"
|
|
||||||
implementation "org.lwjgl:lwjgl-openal"
|
|
||||||
implementation "org.lwjgl:lwjgl-opengl"
|
|
||||||
implementation "org.lwjgl:lwjgl-stb"
|
|
||||||
implementation "org.lwjgl:lwjgl-tinyfd"
|
|
||||||
runtimeOnly "org.lwjgl:lwjgl::$lwjglNatives"
|
|
||||||
runtimeOnly "org.lwjgl:lwjgl-assimp::$lwjglNatives"
|
|
||||||
runtimeOnly "org.lwjgl:lwjgl-glfw::$lwjglNatives"
|
|
||||||
runtimeOnly "org.lwjgl:lwjgl-openal::$lwjglNatives"
|
|
||||||
runtimeOnly "org.lwjgl:lwjgl-opengl::$lwjglNatives"
|
|
||||||
runtimeOnly "org.lwjgl:lwjgl-stb::$lwjglNatives"
|
|
||||||
runtimeOnly "org.lwjgl:lwjgl-tinyfd::$lwjglNatives"
|
|
||||||
implementation "org.joml:joml:${rootProject.joml_version}"
|
|
||||||
|
|
||||||
|
|
||||||
// Some other dependencies
|
|
||||||
implementation("org.jetbrains:annotations:16.0.2")
|
|
||||||
implementation("com.google.code.findbugs:jsr305:3.0.2")
|
|
||||||
implementation("com.google.common:google-collect:0.5")
|
|
||||||
implementation("com.google.guava:guava:31.1-jre")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
task copyCommonLoaderResources(type: Copy) {
|
|
||||||
from project(":common").file("src/main/resources/${accessWidenerVersion}.distanthorizons.accesswidener")
|
|
||||||
into(file(p.file("build/resources/main")))
|
|
||||||
rename "${accessWidenerVersion}.distanthorizons.accesswidener", "distanthorizons.accesswidener"
|
|
||||||
|
|
||||||
|
|
||||||
// Move the fabricLike mixin to its different places for each subproject
|
|
||||||
if (findProject(":fabricLike")) {
|
|
||||||
from project(":fabricLike").file("src/main/resources/DistantHorizons.fabricLike.mixins.json")
|
|
||||||
into(file(p.file("build/resources/main")))
|
|
||||||
rename "DistantHorizons.fabricLike.mixins.json", "DistantHorizons." + p.name + ".fabricLike.mixins.json"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
task copyCoreResources(type: Copy) {
|
|
||||||
from fileTree(project(":core").file("src/main/resources"))
|
|
||||||
into p.file("build/resources/main")
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.withType(JavaCompile) {
|
|
||||||
if (isMinecraftSubProject) {
|
|
||||||
options.release = rootProject.java_version as Integer
|
|
||||||
} else {
|
|
||||||
options.release = 8; // Core & Api should use Java 8 no matter what
|
|
||||||
//options.release = rootProject.java_version as Integer // But if you want to test some stuff, then this can be enabled
|
|
||||||
}
|
|
||||||
options.encoding = "UTF-8"
|
|
||||||
}
|
|
||||||
|
|
||||||
java {
|
|
||||||
withSourcesJar()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
echo "==================== Note: All build jars will be in the folder called 'buildAllJars' ===================="
|
echo "==================== Note: All build jars will be in the folder called 'buildAllJars' ===================="
|
||||||
mkdir -p buildAllJars
|
mkdir -p buildAllJars
|
||||||
rm -rf buildAllJars/*
|
rm -rf buildAllJars/*
|
||||||
|
rm -rf build/forgix/*
|
||||||
|
|
||||||
# Loop trough everything in the version properties folder
|
# Loop trough everything in the version properties folder
|
||||||
for d in versionProperties/*; do
|
for d in versionProperties/*; do
|
||||||
@@ -19,10 +20,6 @@ for d in versionProperties/*; do
|
|||||||
sh gradlew build -PmcVer=$version
|
sh gradlew build -PmcVer=$version
|
||||||
if [ $? != 0 ]; then continue; fi
|
if [ $? != 0 ]; then continue; fi
|
||||||
|
|
||||||
echo "==================== Merging $version ===================="
|
|
||||||
sh gradlew mergeJars -PmcVer=$version
|
|
||||||
if [ $? != 0 ]; then continue; fi
|
|
||||||
|
|
||||||
echo "==================== Moving jar ===================="
|
echo "==================== Moving jar ===================="
|
||||||
mv build/merged/*.jar buildAllJars/
|
mv build/forgix/*.jar buildAllJars/
|
||||||
done
|
done
|
||||||
|
|||||||
+2
-4
@@ -6,6 +6,7 @@
|
|||||||
echo ==================== Note: All build jars will be in the folder called 'buildAllJars' ====================
|
echo ==================== Note: All build jars will be in the folder called 'buildAllJars' ====================
|
||||||
mkdir buildAllJars
|
mkdir buildAllJars
|
||||||
del buildAllJars/*
|
del buildAllJars/*
|
||||||
|
del build/forgix/*
|
||||||
|
|
||||||
@rem Loop trough everything in the version properties folder
|
@rem Loop trough everything in the version properties folder
|
||||||
for %%f in (versionProperties\*) do (
|
for %%f in (versionProperties\*) do (
|
||||||
@@ -19,11 +20,8 @@ for %%f in (versionProperties\*) do (
|
|||||||
echo ==================== Building !version! ====================
|
echo ==================== Building !version! ====================
|
||||||
call .\gradlew.bat build -PmcVer="!version!"
|
call .\gradlew.bat build -PmcVer="!version!"
|
||||||
|
|
||||||
echo ==================== Merging !version! ====================
|
|
||||||
call .\gradlew.bat mergeJars -PmcVer="!version!"
|
|
||||||
|
|
||||||
echo ==================== Moving jar ====================
|
echo ==================== Moving jar ====================
|
||||||
move build\merged\*.jar buildAllJars\
|
move build\forgix\*.jar buildAllJars\
|
||||||
)
|
)
|
||||||
|
|
||||||
endlocal
|
endlocal
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
@echo off & setlocal enabledelayedexpansion
|
||||||
|
|
||||||
|
|
||||||
|
echo ==================== Getting versions to build... ====================
|
||||||
|
mkdir _buildAllJars 2>nul
|
||||||
|
del _buildAllJars\* /Q 2>nul
|
||||||
|
|
||||||
|
set "ROOT=%~dp0"
|
||||||
|
set "WORK_DIR=%ROOT%_buildWorkers"
|
||||||
|
mkdir "%WORK_DIR%" 2>nul
|
||||||
|
|
||||||
|
|
||||||
|
REM get the number of versions to compile
|
||||||
|
set count=0
|
||||||
|
for %%f in (versionProperties\*) do set /a count+=1
|
||||||
|
echo ==================== Found %count% versions to build in parallel ====================
|
||||||
|
|
||||||
|
REM Launch a parallel job for each version
|
||||||
|
for %%f in (%ROOT%versionProperties\*) do (
|
||||||
|
set version=%%~nf
|
||||||
|
|
||||||
|
echo starting [!version!]...
|
||||||
|
start "Build !version!" cmd /c ""%ROOT%build_worker.bat" "!version!" "%ROOT%" "%WORK_DIR%" ""..\..\_buildAllJars"""
|
||||||
|
|
||||||
|
REM Minor timeout between launches so we can stop the build early if we only want
|
||||||
|
REM to test part of the script and to reduce startup load
|
||||||
|
timeout /t 3 /nobreak
|
||||||
|
|
||||||
|
REM 2>nul to supress a harmless warning that the for loop
|
||||||
|
REM "cannot find the drive specified"
|
||||||
|
) 2>nul
|
||||||
|
|
||||||
|
|
||||||
|
echo ==================== All builds started... Completed Jars will be in _buildAllJars ====================
|
||||||
|
endlocal
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
plugins {
|
||||||
|
id 'groovy-gradle-plugin'
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
gradlePluginPortal()
|
||||||
|
mavenCentral()
|
||||||
|
maven { url = 'https://maven.wagyourtail.xyz/releases' } // Jvmdowngrader & unimined libs
|
||||||
|
maven { url = 'https://maven.outlands.top/releases' } // Hosts the kappa fork of unimined
|
||||||
|
maven { url = 'https://maven.wagyourtail.xyz/snapshots' } // The manifold gradle plugin we use
|
||||||
|
maven { url = 'https://maven.architectury.dev/' } // Minecraft mod libs
|
||||||
|
maven { url = 'https://maven.fabricmc.net/' } // Fabric
|
||||||
|
maven { url = 'https://maven.neoforged.net/releases/' } // NeoForge
|
||||||
|
maven { url = 'https://maven.minecraftforge.net/' } // Forge
|
||||||
|
maven { url = 'https://repo.spongepowered.org/repository/maven-public/' } // Hosts minecraft libs
|
||||||
|
maven { url = 'https://oss.sonatype.org/content/repositories/snapshots/' } // Hosts a few dependencies we use
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation 'com.gradleup.shadow:shadow-gradle-plugin:9.0.0'
|
||||||
|
implementation 'xyz.wagyourtail.unimined:xyz.wagyourtail.unimined.gradle.plugin:1.4.18-kappa'
|
||||||
|
implementation 'xyz.wagyourtail:manifold-gradle:1.0.0-SNAPSHOT'
|
||||||
|
implementation 'xyz.wagyourtail.jvmdowngrader:xyz.wagyourtail.jvmdowngrader.gradle.plugin:1.3.4'
|
||||||
|
}
|
||||||
@@ -0,0 +1,593 @@
|
|||||||
|
import com.github.jengelman.gradle.plugins.shadow.transformers.ResourceTransformer
|
||||||
|
import com.github.jengelman.gradle.plugins.shadow.transformers.TransformerContext
|
||||||
|
import org.apache.tools.zip.ZipEntry
|
||||||
|
import org.apache.tools.zip.ZipOutputStream
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull
|
||||||
|
import java.util.function.Function
|
||||||
|
import java.util.function.Predicate
|
||||||
|
import groovy.json.JsonSlurper
|
||||||
|
|
||||||
|
// Convention plugin for all MC-facing subprojects (common + loaders).
|
||||||
|
// Common uses this directly; loaders use it via unimined-fabric/forge/neoforge.
|
||||||
|
// IMPORTANT: unimined MUST be applied before shadow/jvmdowngrader
|
||||||
|
// so its afterEvaluate runs first and can modify configs.
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id 'java'
|
||||||
|
id 'maven-publish'
|
||||||
|
id 'xyz.wagyourtail.unimined'
|
||||||
|
id 'com.gradleup.shadow'
|
||||||
|
id 'xyz.wagyourtail.manifold'
|
||||||
|
id 'xyz.wagyourtail.jvmdowngrader'
|
||||||
|
}
|
||||||
|
|
||||||
|
def isNotCommonProject = project.name != "common"
|
||||||
|
|
||||||
|
if (isNotCommonProject) {
|
||||||
|
evaluationDependsOn(":common")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== Version Properties ====================
|
||||||
|
|
||||||
|
project.gradle.ext.getProperties().each { prop ->
|
||||||
|
rootProject.ext.set(prop.key, prop.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
manifold {
|
||||||
|
version = rootProject.manifold_version
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ==================== Repositories ====================
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
maven { url "https://libraries.minecraft.net/" }
|
||||||
|
mavenCentral()
|
||||||
|
maven { url "https://repo.enonic.com/public/" }
|
||||||
|
maven { url "https://maven.parchmentmc.org" }
|
||||||
|
maven { url "https://maven.architectury.dev" }
|
||||||
|
maven { url "https://jitpack.io" }
|
||||||
|
maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
|
||||||
|
maven {
|
||||||
|
name = "Modrinth"
|
||||||
|
url = "https://api.modrinth.com/maven"
|
||||||
|
content { includeGroup "maven.modrinth" }
|
||||||
|
}
|
||||||
|
maven {
|
||||||
|
url "https://www.cursemaven.com"
|
||||||
|
content { includeGroup "curse.maven" }
|
||||||
|
}
|
||||||
|
maven {
|
||||||
|
url "https://repo.spongepowered.org/maven/"
|
||||||
|
// exclusion is needed since sponge has a deprecated version of fabric
|
||||||
|
// that gradle would prefer to get over the up-to-date version modrinth provides
|
||||||
|
content { excludeGroupByRegex "net\\.fabricmc(\\..*)?" }
|
||||||
|
}
|
||||||
|
maven { url "https://maven.terraformersmc.com/" }
|
||||||
|
maven { url "https://maven.neoforged.net/releases/" }
|
||||||
|
flatDir {
|
||||||
|
dirs "${rootDir}/mods/fabric"
|
||||||
|
content { includeGroup "fabric-mod" }
|
||||||
|
}
|
||||||
|
flatDir {
|
||||||
|
dirs "${rootDir}/mods/quilt"
|
||||||
|
content { includeGroup "quilt-mod" }
|
||||||
|
}
|
||||||
|
flatDir {
|
||||||
|
dirs "${rootDir}/mods/forge"
|
||||||
|
content { includeGroup "forge-mod" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ==================== Java Config ====================
|
||||||
|
|
||||||
|
tasks.withType(JavaCompile).configureEach {
|
||||||
|
options.release = rootProject.java_version as Integer
|
||||||
|
options.encoding = "UTF-8"
|
||||||
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
sourceCompatibility = JavaVersion.toVersion(gradle.ext.java_version as Integer)
|
||||||
|
targetCompatibility = JavaVersion.toVersion(gradle.ext.java_version as Integer)
|
||||||
|
withSourcesJar()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ==================== Loader-Only Config ====================
|
||||||
|
|
||||||
|
if (isNotCommonProject) {
|
||||||
|
base { archivesName = rootProject.mod_name }
|
||||||
|
rootProject.ext.versionStr = rootProject.mod_version + "-" + rootProject.minecraft_version
|
||||||
|
version = project.name + "-" + rootProject.versionStr
|
||||||
|
group = rootProject.maven_group
|
||||||
|
|
||||||
|
javadoc.title = rootProject.mod_name + "-" + project.name
|
||||||
|
|
||||||
|
tasks.withType(GenerateModuleMetadata).configureEach {
|
||||||
|
enabled = false
|
||||||
|
}
|
||||||
|
tasks.withType(Test).configureEach {
|
||||||
|
enabled = false
|
||||||
|
}
|
||||||
|
compileTestJava.enabled = false
|
||||||
|
tasks.withType(Sign).configureEach {
|
||||||
|
enabled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
jar {
|
||||||
|
from "LICENSE.txt"
|
||||||
|
manifest {
|
||||||
|
attributes(
|
||||||
|
'Implementation-Title': rootProject.mod_name,
|
||||||
|
'Implementation-Version': rootProject.mod_version,
|
||||||
|
'Multi-Release': true,
|
||||||
|
'Main-Class': 'com.seibel.distanthorizons.core.jar.JarMain',
|
||||||
|
)
|
||||||
|
if (project.name == "cleanroom") {
|
||||||
|
attributes(
|
||||||
|
'ModType': 'CRL',
|
||||||
|
'MixinConfigs': "${mod_id}.default.mixin.json,${mod_id}.mod.mixin.json",
|
||||||
|
'FMLCorePlugin': 'com.seibel.distanthorizons.cleanroom.DistantHorizonsLoadingPlugin',
|
||||||
|
'FMLCorePluginContainsFMLMod': true,
|
||||||
|
'FMLAT': "${gradle.ext.accessWidenerVersion}.distanthorizons_at.cfg"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ==================== Unimined Minecraft Config ====================
|
||||||
|
|
||||||
|
unimined.minecraft(sourceSets.main, true) {
|
||||||
|
version gradle.ext.minecraft_version
|
||||||
|
|
||||||
|
if (gradle.ext.minecraft_version.startsWith("1.")) { // 26.1+ doesn't use obfuscation
|
||||||
|
mappings {
|
||||||
|
if(gradle.ext.minecraft_version.startsWith("1.12.2")){
|
||||||
|
mcp("stable", "39-1.12")
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
mojmap()
|
||||||
|
devNamespace "mojmap"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNotCommonProject) {
|
||||||
|
// Mixin remapping and common project wiring
|
||||||
|
unimined.minecraft(sourceSets.main, true) {
|
||||||
|
mods.modImplementation {
|
||||||
|
mixinRemap {
|
||||||
|
reset()
|
||||||
|
enableBaseMixin()
|
||||||
|
enableMixinExtra()
|
||||||
|
}
|
||||||
|
// Some Fabric API modules ship AW in 'named' namespace instead of 'intermediary'
|
||||||
|
catchAWNamespaceAssertion()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(project(":common"))
|
||||||
|
}
|
||||||
|
|
||||||
|
processResources {
|
||||||
|
from project(":common").sourceSets.main.resources
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.withType(JavaCompile).configureEach {
|
||||||
|
source(project(":common").sourceSets.main.allSource)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unimined.minecraft {
|
||||||
|
if (gradle.ext.minecraft_version.equals("1.12.2")) {
|
||||||
|
cleanroom {
|
||||||
|
loader gradle.ext.cleanroom_loader_version
|
||||||
|
accessTransformer project.file("src/main/resources/${gradle.ext.accessWidenerVersion}.distanthorizons_at.cfg")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fabric {
|
||||||
|
loader gradle.ext.fabric_loader_version
|
||||||
|
accessWidener project.file("src/main/resources/${gradle.ext.accessWidenerVersion}.distanthorizons.accesswidener")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
defaultRemapJar = false
|
||||||
|
runs.off = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== Configurations ====================
|
||||||
|
|
||||||
|
evaluationDependsOn(":core")
|
||||||
|
|
||||||
|
configurations {
|
||||||
|
shadowMe
|
||||||
|
coreProjects
|
||||||
|
shadowMe.extendsFrom(coreProjects)
|
||||||
|
implementation.extendsFrom(shadowMe)
|
||||||
|
|
||||||
|
common
|
||||||
|
implementation.extendsFrom(common)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ==================== Dependencies ====================
|
||||||
|
|
||||||
|
// Copy core's compileOnly deps so MC-provided deps are visible without redeclaring them.
|
||||||
|
project(":core").configurations.compileOnly.allDependencies.each { dep ->
|
||||||
|
if (!(dep instanceof ProjectDependency))
|
||||||
|
dependencies.add("compileOnly", dep)
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
// Manifold preprocessor & strings
|
||||||
|
annotationProcessor(manifold.module("preprocessor"))
|
||||||
|
|
||||||
|
// NightConfig: implementation in core (bundled) but Unimined strips it from compile classpath
|
||||||
|
compileOnly("com.electronwill.night-config:toml:${rootProject.nightconfig_version}")
|
||||||
|
|
||||||
|
// Core & API projects — bundled into shadow jar
|
||||||
|
coreProjects(project(":core"))
|
||||||
|
coreProjects(project(":api"))
|
||||||
|
|
||||||
|
// JOML: shadow for old MC versions that don't bundle it (core has it compileOnly already)
|
||||||
|
if (project.hasProperty("embed_joml") && embed_joml == "true")
|
||||||
|
shadowMe("org.joml:joml:${rootProject.joml_version}")
|
||||||
|
|
||||||
|
// Common project dependency
|
||||||
|
if (isNotCommonProject)
|
||||||
|
common(project(":common")) { transitive false }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ==================== NativeTransformer ====================
|
||||||
|
|
||||||
|
class NativeTransformer implements ResourceTransformer {
|
||||||
|
private Predicate<String> fileMatcher
|
||||||
|
private Function<String, String> filePathMapper
|
||||||
|
|
||||||
|
private final HashMap<String, String> replacements = new HashMap()
|
||||||
|
private final HashMap<String, byte[]> rewrittenFiles = new HashMap()
|
||||||
|
private nativeRelocator
|
||||||
|
|
||||||
|
public File rootDir
|
||||||
|
|
||||||
|
void matchFiles(Predicate<String> matcher) {
|
||||||
|
fileMatcher = matcher
|
||||||
|
}
|
||||||
|
|
||||||
|
void mapPaths(Function<String, String> mapper) {
|
||||||
|
filePathMapper = mapper
|
||||||
|
}
|
||||||
|
|
||||||
|
void relocateNative(String target, String replacement) {
|
||||||
|
if (replacement.length() > target.length()) {
|
||||||
|
throw new GradleException("Length of value \"${replacement}\" exceeds the length of \"${target}\": ${replacement.length()} > ${target.length()}")
|
||||||
|
}
|
||||||
|
replacements.put(target, replacement)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean canTransformResource(@Nonnull FileTreeElement element) {
|
||||||
|
return fileMatcher != null && fileMatcher.test(element.relativePath.pathString)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void transform(@Nonnull TransformerContext context) {
|
||||||
|
byte[] content = context.inputStream.readAllBytes()
|
||||||
|
|
||||||
|
if (nativeRelocator == null) {
|
||||||
|
nativeRelocator = new NativeRelocator(rootDir.toPath().resolve("relocate_natives"))
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
String path = filePathMapper != null
|
||||||
|
? filePathMapper.apply(context.path)
|
||||||
|
: context.path
|
||||||
|
content = nativeRelocator.processBinary(path, content, replacements)
|
||||||
|
rewrittenFiles.put(path, content)
|
||||||
|
}
|
||||||
|
catch (Throwable e) {
|
||||||
|
throw new GradleException("Failed to relocate", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean hasTransformedResource() { return !rewrittenFiles.isEmpty() }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void modifyOutputStream(@Nonnull ZipOutputStream os, boolean preserveFileTimestamps) {
|
||||||
|
for (Map.Entry<String, byte[]> rewrittenFile : rewrittenFiles.entrySet()) {
|
||||||
|
os.putNextEntry(new ZipEntry(rewrittenFile.key))
|
||||||
|
os.write(rewrittenFile.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ==================== Shadow JAR (loaders only) ====================
|
||||||
|
|
||||||
|
if (isNotCommonProject) {
|
||||||
|
shadowJar {
|
||||||
|
configurations = [project.configurations.shadowMe]
|
||||||
|
def librariesLocation = "DistantHorizons.libraries"
|
||||||
|
|
||||||
|
// LZ4
|
||||||
|
relocate "net.jpountz", "${librariesLocation}.jpountz"
|
||||||
|
|
||||||
|
// SLF4J
|
||||||
|
relocate "org.slf4j", "${librariesLocation}.slf4j"
|
||||||
|
|
||||||
|
// SQLite
|
||||||
|
relocate "org.sqlite", "dh_sqlite", { exclude "org/sqlite/native/**" }
|
||||||
|
relocate "jdbc:sqlite", "jdbc:dh_sqlite"
|
||||||
|
|
||||||
|
transform(NativeTransformer) {
|
||||||
|
rootDir = project.rootDir
|
||||||
|
matchFiles { it.startsWith("org/sqlite") }
|
||||||
|
mapPaths { it.replace("org/sqlite", "dh_sqlite") }
|
||||||
|
relocateNative "org/sqlite", "dh_sqlite"
|
||||||
|
relocateNative "org_sqlite", "dh_1sqlite"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZStd
|
||||||
|
relocate "com.github.luben", "dhcomgithubluben"
|
||||||
|
relocate "libzstd-jni", "libzstd-jni_dh"
|
||||||
|
relocate "zstd-jni", "zstd-jni_dh"
|
||||||
|
|
||||||
|
transform(NativeTransformer) {
|
||||||
|
rootDir = project.rootDir
|
||||||
|
matchFiles { it.contains("libzstd-jni") && !it.contains("aix/ppc64") }
|
||||||
|
mapPaths { it.replace("libzstd-jni", "libzstd-jni_dh") }
|
||||||
|
relocateNative "com/github/luben", "dhcomgithubluben"
|
||||||
|
relocateNative "com_github_luben", "dhcomgithubluben"
|
||||||
|
}
|
||||||
|
|
||||||
|
// JOML (conditional)
|
||||||
|
if (project.hasProperty("embed_joml") && embed_joml == "true")
|
||||||
|
relocate "org.joml", "${librariesLocation}.joml"
|
||||||
|
|
||||||
|
// NightConfig
|
||||||
|
relocate "com.electronwill.nightconfig", "${librariesLocation}.electronwill.nightconfig"
|
||||||
|
|
||||||
|
mergeServiceFiles()
|
||||||
|
}
|
||||||
|
afterEvaluate {
|
||||||
|
tasks.named("remapJar").configure {
|
||||||
|
dependsOn(shadowJar)
|
||||||
|
inputFile.set(shadowJar.archiveFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make run tasks use the shadow jar so relocated deps work in dev.
|
||||||
|
// Filter out jars bundled in the shadow jar, but keep jars that the loader also
|
||||||
|
// needs (e.g. NightConfig — DH relocates it, but NeoForge needs the original).
|
||||||
|
def shadowedPaths = configurations.shadowMe.resolve().collect { it.path }.toSet()
|
||||||
|
def loaderPaths = configurations.minecraftLibraries.resolve().collect { it.path }.toSet()
|
||||||
|
tasks.withType(JavaExec).configureEach { runTask ->
|
||||||
|
dependsOn(shadowJar)
|
||||||
|
if (project.name != "cleanroom") {
|
||||||
|
classpath = files(shadowJar.archiveFile) + classpath.filter { file ->
|
||||||
|
file != shadowJar.archiveFile.get().asFile &&
|
||||||
|
!file.path.contains(project.buildDir.path) &&
|
||||||
|
!file.path.contains("core${File.separator}build") &&
|
||||||
|
!file.path.contains("api${File.separator}build") &&
|
||||||
|
!file.path.contains("common${File.separator}build") &&
|
||||||
|
!(shadowedPaths.contains(file.path) && !loaderPaths.contains(file.path))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// For cleanroom, don't put shadow jar on app classpath.
|
||||||
|
// crl.dev.extrapath loads it via LaunchClassLoader instead.
|
||||||
|
classpath = classpath.filter { file ->
|
||||||
|
!file.path.contains(project.buildDir.path) &&
|
||||||
|
!file.path.contains("core${File.separator}build") &&
|
||||||
|
!file.path.contains("api${File.separator}build") &&
|
||||||
|
!file.path.contains("common${File.separator}build") &&
|
||||||
|
!(shadowedPaths.contains(file.path) && !loaderPaths.contains(file.path))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shared run directory so all loaders use the same worlds
|
||||||
|
def isClient = runTask.name.toLowerCase().contains("client")
|
||||||
|
runTask.workingDir = rootProject.file("run/${isClient ? 'client' : 'server'}")
|
||||||
|
|
||||||
|
// Minecraft automatically has G1GC args present,
|
||||||
|
// remove them so we can use ZGC instead
|
||||||
|
def filteredArgs = runTask.jvmArgs.findAll { arg ->
|
||||||
|
!arg.startsWith("-XX:+UseG1GC") &&
|
||||||
|
!arg.startsWith("-XX:G1") &&
|
||||||
|
!arg.startsWith("-XX:MaxGCPauseMillis")
|
||||||
|
}
|
||||||
|
runTask.jvmArgs = filteredArgs
|
||||||
|
|
||||||
|
if(project.name == "forge"
|
||||||
|
|| project.name == "neoforge"
|
||||||
|
|| project.name == "cleanroom")
|
||||||
|
{
|
||||||
|
// fix (Neo)forge, Cleanroom debug running
|
||||||
|
doFirst {
|
||||||
|
def modsDir = rootProject.file("run/${isClient ? 'client' : 'server'}/mods")
|
||||||
|
modsDir.mkdirs()
|
||||||
|
|
||||||
|
// Remove any stale DH jars before copying the fresh one
|
||||||
|
modsDir.listFiles()?.each({ file ->
|
||||||
|
if (file.name.startsWith(rootProject.mod_name))
|
||||||
|
{
|
||||||
|
file.delete()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Copy shadow jar into mods folder so (Neo)Forge discovers it properly
|
||||||
|
copy {
|
||||||
|
from shadowJar.archiveFile
|
||||||
|
into modsDir
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// JVM args
|
||||||
|
runTask.jvmArgs(
|
||||||
|
"-Dio.netty.leakDetection.level=advanced",
|
||||||
|
// TODO only use for modern java versions
|
||||||
|
"-XX:+UseZGC",
|
||||||
|
// TODO don't use for even more modern-er java versions
|
||||||
|
//"-XX:+ZGenerational",
|
||||||
|
rootProject.minecraftMemoryJavaArg,
|
||||||
|
)
|
||||||
|
if (isClient)
|
||||||
|
{
|
||||||
|
runTask.jvmArgs(
|
||||||
|
"-Dminecraft.api.auth.host=https://nope.invalid",
|
||||||
|
"-Dminecraft.api.account.host=https://nope.invalid",
|
||||||
|
"-Dminecraft.api.session.host=https://nope.invalid",
|
||||||
|
"-Dminecraft.api.services.host=https://nope.invalid",
|
||||||
|
)
|
||||||
|
runTask.args(
|
||||||
|
// use a consistent username for easier debugging in a given world (vs randomly teleporting to a new user each time the game boots)
|
||||||
|
"--username", "Dev",
|
||||||
|
// "--renderDebugLabels" is a Mojang command to show render names in RenderDoc
|
||||||
|
"--renderDebugLabels"
|
||||||
|
)
|
||||||
|
|
||||||
|
// enabling tracy causes constant memory growth so it isn't always desired
|
||||||
|
if (rootProject.minecraftEnableTracy == "true")
|
||||||
|
{
|
||||||
|
// "--tracy" is a Mojang command to allow individual frames to be debugged using Tracy https://github.com/wolfpld/tracy/releases/tag/v0.13.1
|
||||||
|
runTask.args("--tracy")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.downgradeJar.inputFile.set(tasks.named("remapJar").flatMap { it.archiveFile })
|
||||||
|
tasks.jar.finalizedBy(tasks.named("remapJar"))
|
||||||
|
tasks.named("remapJar").configure { finalizedBy(tasks.shadeDowngradedApi) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ==================== Process Resources (loaders only) ====================
|
||||||
|
|
||||||
|
if (isNotCommonProject) {
|
||||||
|
processResources {
|
||||||
|
def resourceTargets = [
|
||||||
|
"build_info.json",
|
||||||
|
"fabric.mod.json",
|
||||||
|
"mcmod.info",
|
||||||
|
"quilt.mod.json",
|
||||||
|
"META-INF/mods.toml",
|
||||||
|
"META-INF/neoforge.mods.toml",
|
||||||
|
]
|
||||||
|
|
||||||
|
// incoming format: `["26.2.0","26.2-alpha.9"]`
|
||||||
|
// outgoing format: `[26.2.0],[26.2-alpha.9]`
|
||||||
|
def compatible_forgemc_versions = "${rootProject.compatible_minecraft_versions}"
|
||||||
|
.replaceAll("\",\"", "],[")
|
||||||
|
.replaceAll("\"", "")
|
||||||
|
|
||||||
|
// Quilt contributors
|
||||||
|
def quilt_contributors = []
|
||||||
|
def mod_author_list = rootProject.mod_authors.replaceAll("\"", "").replace("[", "").replace("]", "").split(",")
|
||||||
|
def cleanroom_author_list = rootProject.mod_authors.replace('[', '').replace(']', '').split(',').collect({ it.trim().replace('"', '') }).join('", "')
|
||||||
|
for (dev in mod_author_list) {
|
||||||
|
quilt_contributors.push("\"${dev.strip()}\": \"Developer\"")
|
||||||
|
}
|
||||||
|
quilt_contributors.reverse()
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (rootProject.infoGitCommit == "null")
|
||||||
|
rootProject.ext.infoGitCommit = 'git rev-parse --verify HEAD'.execute().text.trim()
|
||||||
|
if (rootProject.infoGitBranch == "null")
|
||||||
|
rootProject.ext.infoGitBranch = 'git symbolic-ref --short HEAD'.execute().text.trim()
|
||||||
|
} catch (Exception e) {
|
||||||
|
rootProject.ext.infoGitCommit = "Git not found"
|
||||||
|
rootProject.ext.infoGitBranch = "Git not found"
|
||||||
|
}
|
||||||
|
|
||||||
|
def replaceProperties = [
|
||||||
|
version : rootProject.mod_version,
|
||||||
|
mod_id : rootProject.mod_id,
|
||||||
|
mod_name : rootProject.mod_readable_name,
|
||||||
|
group : rootProject.maven_group,
|
||||||
|
authors : rootProject.mod_authors,
|
||||||
|
cleanroom_authors : cleanroom_author_list,
|
||||||
|
description : rootProject.mod_description,
|
||||||
|
homepage : rootProject.mod_homepage,
|
||||||
|
source : rootProject.mod_source,
|
||||||
|
issues : rootProject.mod_issues,
|
||||||
|
discord : rootProject.mod_discord,
|
||||||
|
minecraft_version : rootProject.minecraft_version,
|
||||||
|
accessWidenerVersion : rootProject.accessWidenerVersion,
|
||||||
|
compatible_minecraft_versions: rootProject.compatible_minecraft_versions,
|
||||||
|
compatible_forgemc_versions : compatible_forgemc_versions,
|
||||||
|
java_version : rootProject.java_version,
|
||||||
|
quilt_contributors : "{" + quilt_contributors.join(", ") + "}",
|
||||||
|
info_git_commit : rootProject.infoGitBranch,
|
||||||
|
info_git_branch : rootProject.infoGitCommit,
|
||||||
|
info_build_source : rootProject.infoBuildSource,
|
||||||
|
fabric_incompatibility_list : rootProject.fabric_incompatibility_list,
|
||||||
|
fabric_recommend_list : rootProject.fabric_recommend_list,
|
||||||
|
neoforge_version_range : rootProject.neoforge_version_range,
|
||||||
|
logo_path : "assets/distanthorizons/icon.png"
|
||||||
|
]
|
||||||
|
|
||||||
|
inputs.properties replaceProperties
|
||||||
|
replaceProperties.put "project", project
|
||||||
|
filesMatching(resourceTargets) {
|
||||||
|
expand replaceProperties
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove unused access wideners
|
||||||
|
exclude { file ->
|
||||||
|
if ((file.name.contains(".distanthorizons.accesswidener") && file.name != "${rootProject.accessWidenerVersion}.distanthorizons.accesswidener")) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ==================== Resource Copy Tasks ====================
|
||||||
|
|
||||||
|
// task copyCommonLoaderResources(type: Copy) {
|
||||||
|
// from project(":common").file("src/main/resources/${rootProject.accessWidenerVersion}.distanthorizons.accesswidener")
|
||||||
|
// into(file(project.file("build/resources/main")))
|
||||||
|
// rename "${rootProject.accessWidenerVersion}.distanthorizons.accesswidener", "distanthorizons.accesswidener"
|
||||||
|
// }
|
||||||
|
|
||||||
|
task copyCoreResources(type: Copy) {
|
||||||
|
from fileTree(project(":core").file("src/main/resources"))
|
||||||
|
into project.file("build/resources/main")
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.register("convertJsonToLang") {
|
||||||
|
dependsOn(copyCoreResources)
|
||||||
|
|
||||||
|
File input = project.file("build/resources/main/assets/distanthorizons/lang/en_us.json")
|
||||||
|
File output = project.file("build/resources/main/assets/distanthorizons/lang/en_us.lang")
|
||||||
|
inputs.file(input)
|
||||||
|
outputs.file(output)
|
||||||
|
doLast {
|
||||||
|
output.withWriter("UTF-8") { writer ->
|
||||||
|
writer.writeLine("#PARSE_ESCAPES")
|
||||||
|
new JsonSlurper()
|
||||||
|
.parse(input)
|
||||||
|
.each { key, value ->
|
||||||
|
writer.writeLine("${key}=${value.toString().replace("%", "%%").replace("\n", "\\n")}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ==================== JVMDowngrader ====================
|
||||||
|
|
||||||
|
jvmdg.downgradeTo = JavaVersion.toVersion(rootProject.java_version)
|
||||||
|
downgradeJar.archiveClassifier.set(null)
|
||||||
|
shadeDowngradedApi.archiveClassifier.set(null)
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
plugins {
|
||||||
|
id 'java'
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transfer version properties from settings.gradle to project
|
||||||
|
project.gradle.ext.getProperties().each { prop ->
|
||||||
|
rootProject.ext.set(prop.key, prop.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Version string for archives
|
||||||
|
rootProject.ext.versionStr = rootProject.mod_version + "-" + rootProject.minecraft_version
|
||||||
|
rootProject.allprojects {
|
||||||
|
version = (it == rootProject ? "" : it.name + "-") + rootProject.versionStr
|
||||||
|
group = rootProject.maven_group
|
||||||
|
|
||||||
|
// Custom javadoc tags for all subprojects
|
||||||
|
plugins.withType(JavaPlugin) {
|
||||||
|
javadoc {
|
||||||
|
options.tags(
|
||||||
|
'todo:X"',
|
||||||
|
'apiNote:a:API Note:',
|
||||||
|
'implSpec:a:Implementation Requirements:',
|
||||||
|
'implNote:a:Implementation Note:'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create build.properties with preprocessor definitions
|
||||||
|
def writePreprocessorDefinitions() {
|
||||||
|
StringBuilder sb = new StringBuilder()
|
||||||
|
sb.append("# DON'T TOUCH THIS FILE, This is handled by the build script\n")
|
||||||
|
|
||||||
|
gradle.ext.mcVers.eachWithIndex { ver, idx ->
|
||||||
|
sb.append("MC_${ver.replace('.', '_')}=${idx}\n")
|
||||||
|
if (gradle.ext.mcIndex == idx)
|
||||||
|
sb.append("MC_VER=${idx}\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rootProject.mod_version.toLowerCase().contains("dev")) {
|
||||||
|
sb.append("DEV_BUILD=\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
new File(rootDir, "build.properties").text = sb.toString()
|
||||||
|
}
|
||||||
|
writePreprocessorDefinitions()
|
||||||
|
|
||||||
|
// Wire JVMDowngrader to process remapped jars
|
||||||
|
gradle.projectsEvaluated {
|
||||||
|
rootProject.subprojects.each {
|
||||||
|
if (it.tasks.findByName('remapJar') == null) return
|
||||||
|
it.tasks.downgradeJar.inputFile = it.tasks.remapJar.archiveFile
|
||||||
|
it.tasks.jar.finalizedBy(it.tasks.remapJar)
|
||||||
|
it.tasks.remapJar.finalizedBy(it.tasks.shadeDowngradedApi)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
plugins {
|
||||||
|
id 'dh-loader'
|
||||||
|
}
|
||||||
|
|
||||||
|
unimined.minecraft {
|
||||||
|
cleanroom {
|
||||||
|
loader gradle.ext.cleanroom_loader_version
|
||||||
|
useToolchains = false
|
||||||
|
accessTransformer project(":common").file("src/main/resources/${gradle.ext.accessWidenerVersion}.distanthorizons_at.cfg")
|
||||||
|
runs.all {
|
||||||
|
systemProperty("crl.dev.mixin", "${mod_id}.default.mixin.json,${mod_id}.mod.mixin.json")
|
||||||
|
systemProperty("fml.coreMods.load", "com.seibel.distanthorizons.cleanroom.DistantHorizonsLoadingPlugin")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
plugins {
|
||||||
|
id 'dh-loader'
|
||||||
|
}
|
||||||
|
|
||||||
|
unimined.minecraft {
|
||||||
|
fabric {
|
||||||
|
loader gradle.ext.fabric_loader_version
|
||||||
|
accessWidener project(":common").file("src/main/resources/${gradle.ext.accessWidenerVersion}.distanthorizons.accesswidener")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
runClient.javaLauncher = null
|
||||||
|
runServer.javaLauncher = null
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
plugins {
|
||||||
|
id 'dh-loader'
|
||||||
|
}
|
||||||
|
|
||||||
|
def awFile = project(":common").file("src/main/resources/${gradle.ext.accessWidenerVersion}.distanthorizons.accesswidener")
|
||||||
|
|
||||||
|
unimined.minecraft {
|
||||||
|
forge {
|
||||||
|
loader gradle.ext.forge_version
|
||||||
|
useToolchains = false
|
||||||
|
mixinConfig("DistantHorizons.forge.mixins.json")
|
||||||
|
accessTransformer aw2at(awFile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
runClient.javaLauncher = null
|
||||||
|
runServer.javaLauncher = null
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
plugins {
|
||||||
|
id 'dh-loader'
|
||||||
|
}
|
||||||
|
|
||||||
|
def awFile = project(":common").file("src/main/resources/${gradle.ext.accessWidenerVersion}.distanthorizons.accesswidener")
|
||||||
|
|
||||||
|
unimined.minecraft {
|
||||||
|
neoForged {
|
||||||
|
loader gradle.ext.neoforge_version
|
||||||
|
useToolchains = false
|
||||||
|
accessTransformer aw2at(awFile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
runClient.javaLauncher = null
|
||||||
|
runServer.javaLauncher = null
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
@echo off & setlocal enabledelayedexpansion
|
||||||
|
|
||||||
|
set "VERSION=%~1"
|
||||||
|
set "ROOT=%~2"
|
||||||
|
set "WORK_DIR=%~3"
|
||||||
|
set "WORKER=%WORK_DIR%\%VERSION%"
|
||||||
|
set "JAR_OUTPUT_DIR=%~4"
|
||||||
|
|
||||||
|
REM remove the ending "\" from the root folder, otherwise the final quote
|
||||||
|
REM in the robocopy command will be escaped and it won't run
|
||||||
|
if "%ROOT:~-1%"=="\" set "ROOT=%ROOT:~0,-1%"
|
||||||
|
set "WORKER=%~3\%~1"
|
||||||
|
|
||||||
|
set "BUILT_JAR_DIR=%WORKER%\build\forgix"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
echo ==================== [%VERSION%] Copying workspace ====================
|
||||||
|
mkdir "%WORKER%"
|
||||||
|
robocopy "%ROOT%" "%WORKER%" /E /XD "%WORKER%" "_buildWorkers" "buildAllJars" ".gradle" "build" ".git" ".idea" ".gitlab" "run" "testScripts" /NFL /NDL
|
||||||
|
|
||||||
|
echo ==================== [%VERSION%] Cleaning ====================
|
||||||
|
cd /d "%WORKER%"
|
||||||
|
call .\gradlew.bat clean
|
||||||
|
REM optional arg that can be added if we want to log the result to a file
|
||||||
|
REM >"%WORK_DIR%\build_%VERSION%.log" 2>&1
|
||||||
|
|
||||||
|
echo ==================== [%VERSION%] Assembling ====================
|
||||||
|
call .\gradlew.bat assemble -PmcVer="%VERSION%"
|
||||||
|
REM optional arg that can be added if we want to log the result to a file
|
||||||
|
REM >>"%WORK_DIR%\build_%VERSION%.log" 2>&1
|
||||||
|
|
||||||
|
echo ==================== [%VERSION%] Exporting ====================
|
||||||
|
mkdir "%JAR_OUTPUT_DIR%"
|
||||||
|
robocopy "%BUILT_JAR_DIR%" "%JAR_OUTPUT_DIR%" /NFL /NDL
|
||||||
|
|
||||||
|
echo ==================== [%VERSION%] Done ====================
|
||||||
|
endlocal
|
||||||
|
|
||||||
|
REM can be uncommented for debugging
|
||||||
|
REM pause
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
plugins {
|
||||||
|
id 'unimined-cleanroom'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ==================== Mod Dependency Helper ====================
|
||||||
|
|
||||||
|
def addMod(path, enabled) {
|
||||||
|
if (enabled == "2")
|
||||||
|
dependencies { modImplementation(path) }
|
||||||
|
else if (enabled == "1")
|
||||||
|
dependencies { compileOnly(path) }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ==================== Dependencies ====================
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ==================== Tasks ====================
|
||||||
|
|
||||||
|
task deleteResources(type: Delete) {
|
||||||
|
delete file("build/resources/main")
|
||||||
|
}
|
||||||
|
|
||||||
|
processResources {
|
||||||
|
rename '(.+_at.cfg)', 'META-INF/$1'
|
||||||
|
dependsOn(copyCoreResources)
|
||||||
|
dependsOn(convertJsonToLang)
|
||||||
|
// dependsOn(copyCommonLoaderResources)
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.named('runClient') {
|
||||||
|
dependsOn(copyCoreResources)
|
||||||
|
// dependsOn(copyCommonLoaderResources)
|
||||||
|
finalizedBy(deleteResources)
|
||||||
|
}
|
||||||
|
|
||||||
|
sourcesJar {
|
||||||
|
def commonSources = project(":common").sourcesJar
|
||||||
|
dependsOn commonSources
|
||||||
|
from commonSources.archiveFile.map { zipTree(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
+251
@@ -0,0 +1,251 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Distant Horizons mod
|
||||||
|
* licensed under the GNU LGPL v3 License.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 James Seibel
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.distanthorizons.cleanroom;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.common.AbstractModInitializer;
|
||||||
|
import com.seibel.distanthorizons.common.util.ProxyUtil;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
||||||
|
import com.seibel.distanthorizons.core.api.internal.ServerApi;
|
||||||
|
import com.seibel.distanthorizons.core.api.internal.SharedApi;
|
||||||
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import com.seibel.distanthorizons.core.logging.f3.F3Screen;
|
||||||
|
import com.seibel.distanthorizons.core.network.messages.AbstractNetworkMessage;
|
||||||
|
import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.multiplayer.WorldClient;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraft.world.chunk.Chunk;
|
||||||
|
import net.minecraftforge.client.event.RenderGameOverlayEvent;
|
||||||
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
|
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
|
||||||
|
import net.minecraftforge.event.world.ChunkEvent;
|
||||||
|
import net.minecraftforge.event.world.WorldEvent;
|
||||||
|
import net.minecraftforge.fml.common.FMLCommonHandler;
|
||||||
|
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||||
|
import net.minecraftforge.fml.common.gameevent.InputEvent;
|
||||||
|
import net.minecraftforge.fml.common.gameevent.TickEvent;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
import org.lwjgl.opengl.GL32;
|
||||||
|
|
||||||
|
import java.util.concurrent.AbstractExecutorService;
|
||||||
|
|
||||||
|
public class CleanroomClientProxy implements AbstractModInitializer.IEventProxy
|
||||||
|
{
|
||||||
|
private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
|
||||||
|
private static final CleanroomPluginPacketSender PACKET_SENDER = (CleanroomPluginPacketSender) SingletonInjector.INSTANCE.get(IPluginPacketSender.class);
|
||||||
|
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
|
|
||||||
|
private static World GetEventLevel(WorldEvent e) { return e.getWorld(); }
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerEvents()
|
||||||
|
{
|
||||||
|
MinecraftForge.EVENT_BUS.register(this);
|
||||||
|
MinecraftForge.EVENT_BUS.register(FMLCommonHandler.instance());
|
||||||
|
CleanroomPluginPacketSender.setPacketHandler(ClientApi.INSTANCE::pluginMessageReceived);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//==============//
|
||||||
|
// world events //
|
||||||
|
//==============//
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void clientLevelLoadEvent(WorldEvent.Load event)
|
||||||
|
{
|
||||||
|
LOGGER.info("level load");
|
||||||
|
|
||||||
|
World level = event.getWorld();
|
||||||
|
if (!(level instanceof WorldClient clientLevel))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
IClientLevelWrapper clientLevelWrapper = ClientLevelWrapper.getWrapper(clientLevel, true);
|
||||||
|
ClientApi.INSTANCE.clientLevelLoadEvent(clientLevelWrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void clientLevelUnloadEvent(WorldEvent.Unload event)
|
||||||
|
{
|
||||||
|
LOGGER.info("level unload");
|
||||||
|
|
||||||
|
World level = event.getWorld();
|
||||||
|
if (!(level instanceof WorldClient clientLevel))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
IClientLevelWrapper clientLevelWrapper = ClientLevelWrapper.getWrapper(clientLevel);
|
||||||
|
ClientApi.INSTANCE.clientLevelUnloadEvent(clientLevelWrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//==============//
|
||||||
|
// chunk events //
|
||||||
|
//==============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void rightClickBlockEvent(PlayerInteractEvent.RightClickBlock event)
|
||||||
|
{
|
||||||
|
if (MC.clientConnectedToDedicatedServer())
|
||||||
|
{
|
||||||
|
World level = event.getWorld();
|
||||||
|
|
||||||
|
ILevelWrapper wrappedLevel = ProxyUtil.getLevelWrapper(level);
|
||||||
|
if (SharedApi.isChunkAtBlockPosAlreadyUpdating(wrappedLevel, event.getPos().getX(), event.getPos().getZ()))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AbstractExecutorService executor = ThreadPoolUtil.getFileHandlerExecutor();
|
||||||
|
if (executor != null)
|
||||||
|
{
|
||||||
|
executor.execute(() ->
|
||||||
|
{
|
||||||
|
Chunk chunk = level.getChunk(event.getPos());
|
||||||
|
SharedApi.INSTANCE.applyChunkUpdate(new ChunkWrapper(chunk, wrappedLevel), wrappedLevel);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@SubscribeEvent
|
||||||
|
public void leftClickBlockEvent(PlayerInteractEvent.LeftClickBlock event)
|
||||||
|
{
|
||||||
|
if (MC.clientConnectedToDedicatedServer())
|
||||||
|
{
|
||||||
|
World level = event.getWorld();
|
||||||
|
|
||||||
|
ILevelWrapper wrappedLevel = ProxyUtil.getLevelWrapper(level);
|
||||||
|
if (SharedApi.isChunkAtBlockPosAlreadyUpdating(wrappedLevel, event.getPos().getX(), event.getPos().getZ()))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AbstractExecutorService executor = ThreadPoolUtil.getFileHandlerExecutor();
|
||||||
|
if (executor != null)
|
||||||
|
{
|
||||||
|
executor.execute(() ->
|
||||||
|
{
|
||||||
|
Chunk chunk = level.getChunk(event.getPos());
|
||||||
|
SharedApi.INSTANCE.applyChunkUpdate(new ChunkWrapper(chunk, wrappedLevel), wrappedLevel);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void clientChunkLoadEvent(ChunkEvent.Load event)
|
||||||
|
{
|
||||||
|
if (MC.clientConnectedToDedicatedServer())
|
||||||
|
{
|
||||||
|
ILevelWrapper wrappedLevel = ProxyUtil.getLevelWrapper(GetEventLevel(event));
|
||||||
|
IChunkWrapper chunkWrapper = new ChunkWrapper(event.getChunk(), wrappedLevel);
|
||||||
|
SharedApi.INSTANCE.applyChunkUpdate(chunkWrapper, wrappedLevel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//==============//
|
||||||
|
// key bindings //
|
||||||
|
//==============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void registerKeyBindings(InputEvent.KeyInputEvent event)
|
||||||
|
{
|
||||||
|
/* if (Minecraft.getMinecraft().player == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (event.getAction() != GLFW.GLFW_PRESS)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientApi.INSTANCE.keyPressedEvent(event.getKey());*/
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//===========//
|
||||||
|
// rendering //
|
||||||
|
//===========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void afterLevelRenderEvent(TickEvent.RenderTickEvent event)
|
||||||
|
{
|
||||||
|
if (event.type.equals(TickEvent.RenderTickEvent.Type.RENDER))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// should generally only need to be set once per game session
|
||||||
|
// allows DH to render directly to Optifine's level frame buffer,
|
||||||
|
// allowing better shader support
|
||||||
|
MinecraftRenderWrapper.INSTANCE.finalLevelFrameBufferId = GL32.glGetInteger(GL32.GL_FRAMEBUFFER_BINDING);
|
||||||
|
}
|
||||||
|
catch (Exception | Error e)
|
||||||
|
{
|
||||||
|
LOGGER.error("Unexpected error in afterLevelRenderEvent: "+e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void onRenderOverlay(RenderGameOverlayEvent.Text event)
|
||||||
|
{
|
||||||
|
Minecraft mc = Minecraft.getMinecraft();
|
||||||
|
if (event.isCanceled()
|
||||||
|
|| !mc.gameSettings.showDebugInfo)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
F3Screen.addStringToDisplay(event.getRight());
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,147 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Distant Horizons mod
|
||||||
|
* licensed under the GNU LGPL v3 License.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 James Seibel
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.distanthorizons.cleanroom;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.cleanroom.modAccessor.ModChecker;
|
||||||
|
import com.seibel.distanthorizons.common.AbstractModInitializer;
|
||||||
|
import com.seibel.distanthorizons.common.commands.CommandInitializer;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.worldGeneration.InternalServerGenerator;
|
||||||
|
import com.seibel.distanthorizons.core.api.internal.ServerApi;
|
||||||
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker;
|
||||||
|
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraftforge.common.ForgeChunkManager;
|
||||||
|
import net.minecraftforge.fml.common.FMLCommonHandler;
|
||||||
|
import net.minecraftforge.fml.common.Mod;
|
||||||
|
import net.minecraftforge.fml.common.event.*;
|
||||||
|
import org.apache.logging.log4j.Level;
|
||||||
|
import org.apache.logging.log4j.core.config.Configurator;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize and setup the Mod. <br>
|
||||||
|
* If you are looking for the real start of the mod
|
||||||
|
* check out the ClientProxy.
|
||||||
|
*/
|
||||||
|
@Mod(modid = ModInfo.ID, name = ModInfo.NAME, version = ModInfo.VERSION)
|
||||||
|
public class CleanroomMain extends AbstractModInitializer
|
||||||
|
{
|
||||||
|
@Mod.Instance
|
||||||
|
public static CleanroomMain instance;
|
||||||
|
|
||||||
|
@Mod.EventHandler
|
||||||
|
public void preinit(FMLPreInitializationEvent event)
|
||||||
|
{
|
||||||
|
Configurator.setLevel("org.sqlite", Level.INFO);
|
||||||
|
ForgeChunkManager.setForcedChunkLoadingCallback(CleanroomMain.instance, (tickets, world) -> { });
|
||||||
|
}
|
||||||
|
|
||||||
|
@Mod.EventHandler
|
||||||
|
public void init(FMLInitializationEvent event)
|
||||||
|
{
|
||||||
|
if (FMLCommonHandler.instance().getEffectiveSide().isClient())
|
||||||
|
{
|
||||||
|
this.onInitializeClient();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.onInitializeServer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void createInitialSharedBindings()
|
||||||
|
{
|
||||||
|
SingletonInjector.INSTANCE.bind(IModChecker.class, ModChecker.INSTANCE);
|
||||||
|
SingletonInjector.INSTANCE.bind(IPluginPacketSender.class, new CleanroomPluginPacketSender());
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
protected void createInitialClientBindings() { /* no additional setup needed currently */ }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected IEventProxy createClientProxy() { return new CleanroomClientProxy(); }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected IEventProxy createServerProxy(boolean isDedicated) { return new CleanroomServerProxy(isDedicated); }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initializeModCompat()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* @Override
|
||||||
|
protected void subscribeRegisterCommandsEvent(Consumer<CommandDispatcher<CommandSourceStack>> eventHandler)
|
||||||
|
{ MinecraftForge.EVENT_BUS.addListener((RegisterCommandsEvent e) -> { eventHandler.accept(e.getDispatcher()); }); }*/
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void subscribeClientStartedEvent(Runnable eventHandler)
|
||||||
|
{
|
||||||
|
// Just run the event handler, since there are no proper ClientLifecycleEvent for the client
|
||||||
|
// to signify readiness other than FmlClientSetupEvent
|
||||||
|
eventHandler.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Mod.EventHandler
|
||||||
|
public void onServerStarting(FMLServerStartingEvent event)
|
||||||
|
{
|
||||||
|
event.registerServerCommand(CommandInitializer.initCommands());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Mod.EventHandler
|
||||||
|
public void onServerAboutToStart(FMLServerAboutToStartEvent event)
|
||||||
|
{
|
||||||
|
if (eventHandlerStartServer != null)
|
||||||
|
{
|
||||||
|
eventHandlerStartServer.accept(event.getServer());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Consumer<MinecraftServer> eventHandlerStartServer;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void subscribeServerStartingEvent(Consumer<MinecraftServer> eventHandler)
|
||||||
|
{
|
||||||
|
eventHandlerStartServer = eventHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void runDelayedSetup() { SingletonInjector.INSTANCE.runDelayedSetup(); }
|
||||||
|
|
||||||
|
// ServerWorldLoadEvent
|
||||||
|
@Mod.EventHandler
|
||||||
|
public void dedicatedWorldLoadEvent(FMLServerAboutToStartEvent event)
|
||||||
|
{
|
||||||
|
ServerApi.INSTANCE.serverLoadEvent(event.getServer().isDedicatedServer());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServerWorldUnloadEvent
|
||||||
|
@Mod.EventHandler
|
||||||
|
public void serverWorldUnloadEvent(FMLServerStoppingEvent event)
|
||||||
|
{
|
||||||
|
ServerApi.INSTANCE.serverUnloadEvent();
|
||||||
|
}
|
||||||
|
}
|
||||||
+136
@@ -0,0 +1,136 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Distant Horizons mod
|
||||||
|
* licensed under the GNU LGPL v3 License.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 James Seibel
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.distanthorizons.cleanroom;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.common.AbstractPluginPacketSender;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.misc.ServerPlayerWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.network.messages.AbstractNetworkMessage;
|
||||||
|
import com.seibel.distanthorizons.core.network.messages.MessageRegistry;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import net.minecraft.entity.player.EntityPlayerMP;
|
||||||
|
import net.minecraftforge.fml.common.network.NetworkRegistry;
|
||||||
|
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
|
||||||
|
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
|
||||||
|
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
|
||||||
|
import net.minecraftforge.fml.common.network.simpleimpl.SimpleNetworkWrapper;
|
||||||
|
import net.minecraftforge.fml.relauncher.Side;
|
||||||
|
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public class CleanroomPluginPacketSender extends AbstractPluginPacketSender
|
||||||
|
{
|
||||||
|
public static final SimpleNetworkWrapper PLUGIN_CHANNEL =
|
||||||
|
NetworkRegistry.INSTANCE.newSimpleChannel(
|
||||||
|
AbstractPluginPacketSender.WRAPPER_PACKET_RESOURCE
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static void setPacketHandler(Consumer<AbstractNetworkMessage> consumer)
|
||||||
|
{ setPacketHandler((player, message) -> consumer.accept(message)); }
|
||||||
|
static BiConsumer<IServerPlayerWrapper, AbstractNetworkMessage> consumerPacket;
|
||||||
|
public static void setPacketHandler(BiConsumer<IServerPlayerWrapper, AbstractNetworkMessage> consumer)
|
||||||
|
{
|
||||||
|
PLUGIN_CHANNEL.registerMessage(MessageWrapper.Handler.class, MessageWrapper.class, 0, Side.CLIENT);
|
||||||
|
PLUGIN_CHANNEL.registerMessage(MessageWrapper.Handler.class, MessageWrapper.class, 0, Side.SERVER);
|
||||||
|
consumerPacket = consumer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendToServer(AbstractNetworkMessage message)
|
||||||
|
{ PLUGIN_CHANNEL.sendToServer(new MessageWrapper(message)); }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendToClient(EntityPlayerMP serverPlayer, AbstractNetworkMessage message)
|
||||||
|
{ PLUGIN_CHANNEL.sendTo(new MessageWrapper(message), serverPlayer); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// helper classes //
|
||||||
|
//================//
|
||||||
|
//region
|
||||||
|
|
||||||
|
// Forge doesn't support using abstract classes
|
||||||
|
@SuppressWarnings({"ClassCanBeRecord", "RedundantSuppression"})
|
||||||
|
public static class MessageWrapper implements IMessage
|
||||||
|
{
|
||||||
|
public AbstractNetworkMessage message;
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public MessageWrapper(AbstractNetworkMessage message) { this.message = message; }
|
||||||
|
|
||||||
|
public MessageWrapper()
|
||||||
|
{
|
||||||
|
// For reflection
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fromBytes(ByteBuf buf)
|
||||||
|
{
|
||||||
|
int messageId = buf.readByte();
|
||||||
|
message = MessageRegistry.INSTANCE.createMessage(messageId);
|
||||||
|
message.decode(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void toBytes(ByteBuf buf)
|
||||||
|
{
|
||||||
|
buf.writeByte(MessageRegistry.INSTANCE.getMessageId(message));
|
||||||
|
message.encode(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Handler implements IMessageHandler<MessageWrapper, IMessage>
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public IMessage onMessage(MessageWrapper wrapper, MessageContext context)
|
||||||
|
{
|
||||||
|
if (wrapper.message != null)
|
||||||
|
{
|
||||||
|
if (context.side == Side.SERVER)
|
||||||
|
{
|
||||||
|
consumerPacket.accept(ServerPlayerWrapper.getWrapper(context.getServerHandler().player), wrapper.message);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
consumerPacket.accept(null, wrapper.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null; // No response needed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+181
@@ -0,0 +1,181 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Distant Horizons mod
|
||||||
|
* licensed under the GNU LGPL v3 License.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 James Seibel
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.distanthorizons.cleanroom;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.common.AbstractModInitializer;
|
||||||
|
import com.seibel.distanthorizons.common.commands.CommandInitializer;
|
||||||
|
import com.seibel.distanthorizons.common.commonMixins.MixinChunkMapCommon;
|
||||||
|
import com.seibel.distanthorizons.common.util.ProxyUtil;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.misc.ServerPlayerWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.worldGeneration.InternalServerGenerator;
|
||||||
|
import com.seibel.distanthorizons.core.api.internal.ServerApi;
|
||||||
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||||
|
import net.minecraft.entity.player.EntityPlayerMP;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraft.world.WorldServer;
|
||||||
|
import net.minecraftforge.common.ForgeChunkManager;
|
||||||
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
|
import net.minecraftforge.event.world.ChunkDataEvent;
|
||||||
|
import net.minecraftforge.event.world.ChunkEvent;
|
||||||
|
import net.minecraftforge.event.world.WorldEvent;
|
||||||
|
import net.minecraftforge.fml.common.FMLCommonHandler;
|
||||||
|
import net.minecraftforge.fml.common.Mod;
|
||||||
|
import net.minecraftforge.fml.common.event.FMLServerAboutToStartEvent;
|
||||||
|
import net.minecraftforge.fml.common.event.FMLServerStartingEvent;
|
||||||
|
import net.minecraftforge.fml.common.event.FMLServerStoppingEvent;
|
||||||
|
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||||
|
import net.minecraftforge.fml.common.gameevent.PlayerEvent;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
|
||||||
|
import static com.seibel.distanthorizons.cleanroom.CleanroomMain.instance;
|
||||||
|
|
||||||
|
public class CleanroomServerProxy implements AbstractModInitializer.IEventProxy
|
||||||
|
{
|
||||||
|
private static final CleanroomPluginPacketSender PACKET_SENDER = (CleanroomPluginPacketSender) SingletonInjector.INSTANCE.get(IPluginPacketSender.class);
|
||||||
|
private static World GetEventLevel(WorldEvent e) { return e.getWorld(); }
|
||||||
|
|
||||||
|
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
|
private final ServerApi serverApi = ServerApi.INSTANCE;
|
||||||
|
private final boolean isDedicated;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerEvents()
|
||||||
|
{
|
||||||
|
MinecraftForge.EVENT_BUS.register(this);
|
||||||
|
FMLCommonHandler.instance().bus().register(this);
|
||||||
|
if (this.isDedicated)
|
||||||
|
{
|
||||||
|
PACKET_SENDER.setPacketHandler(ServerApi.INSTANCE::pluginMessageReceived);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public CleanroomServerProxy(boolean isDedicated) { this.isDedicated = isDedicated; }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//========//
|
||||||
|
// events //
|
||||||
|
//========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
// ServerLevelLoadEvent
|
||||||
|
@SubscribeEvent
|
||||||
|
public void serverLevelLoadEvent(WorldEvent.Load event)
|
||||||
|
{
|
||||||
|
if (GetEventLevel(event) instanceof WorldServer)
|
||||||
|
{
|
||||||
|
this.serverApi.serverLevelLoadEvent(getServerLevelWrapper((WorldServer) GetEventLevel(event)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServerLevelUnloadEvent
|
||||||
|
@SubscribeEvent
|
||||||
|
public void serverLevelUnloadEvent(WorldEvent.Unload event)
|
||||||
|
{
|
||||||
|
if (GetEventLevel(event) instanceof WorldServer)
|
||||||
|
{
|
||||||
|
this.serverApi.serverLevelUnloadEvent(getServerLevelWrapper((WorldServer) GetEventLevel(event)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void serverChunkLoadEvent(ChunkEvent.Load event)
|
||||||
|
{
|
||||||
|
ILevelWrapper levelWrapper = ProxyUtil.getLevelWrapper(GetEventLevel(event));
|
||||||
|
IChunkWrapper chunk = new ChunkWrapper(event.getChunk(), levelWrapper);
|
||||||
|
this.serverApi.serverChunkLoadEvent(chunk, levelWrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void serverChunkSaveEvent(ChunkDataEvent.Save event)
|
||||||
|
{
|
||||||
|
if (event.getWorld() instanceof WorldServer worldServer)
|
||||||
|
{
|
||||||
|
MixinChunkMapCommon.onChunkSave(worldServer, event.getChunk());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void playerLoggedInEvent(PlayerEvent.PlayerLoggedInEvent event)
|
||||||
|
{ this.serverApi.serverPlayerJoinEvent(getServerPlayerWrapper(event)); }
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void playerLoggedOutEvent(PlayerEvent.PlayerLoggedOutEvent event)
|
||||||
|
{ this.serverApi.serverPlayerDisconnectEvent(getServerPlayerWrapper(event)); }
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void playerChangedDimensionEvent(PlayerEvent.PlayerChangedDimensionEvent event)
|
||||||
|
{
|
||||||
|
this.serverApi.serverPlayerLevelChangeEvent(
|
||||||
|
getServerPlayerWrapper(event),
|
||||||
|
getServerLevelWrapper(event.fromDim, event),
|
||||||
|
getServerLevelWrapper(event.toDim, event)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// helper methods //
|
||||||
|
//================//
|
||||||
|
//region
|
||||||
|
|
||||||
|
private static ServerLevelWrapper getServerLevelWrapper(WorldServer level) { return ServerLevelWrapper.getWrapper(level); }
|
||||||
|
|
||||||
|
private static ServerLevelWrapper getServerLevelWrapper(int dimensionId, PlayerEvent event)
|
||||||
|
{
|
||||||
|
MinecraftServer server = event.player.getServer();
|
||||||
|
if (server == null)
|
||||||
|
{
|
||||||
|
LOGGER.error("getServerLevelWrapper: server is null for player {}", event.player.getName());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return getServerLevelWrapper(server.getWorld(dimensionId));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ServerPlayerWrapper getServerPlayerWrapper(PlayerEvent event)
|
||||||
|
{ return ServerPlayerWrapper.getWrapper((EntityPlayerMP) event.player); }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+56
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Distant Horizons mod
|
||||||
|
* licensed under the GNU LGPL v3 License.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 James Seibel
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.distanthorizons.cleanroom;
|
||||||
|
|
||||||
|
import net.minecraftforge.fml.common.Loader;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
|
import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
|
||||||
|
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class DistantHorizonsConfigPlugin implements IMixinConfigPlugin
|
||||||
|
{
|
||||||
|
private static final Logger LOGGER = LogManager.getLogger();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoad(String mixinPackage)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldApplyMixin(String targetClassName, String mixinClassName)
|
||||||
|
{
|
||||||
|
/* return switch (mixinClassName.split("\\.")[5]) {
|
||||||
|
case "mist" -> Loader.isModLoaded("mist");
|
||||||
|
default -> true;
|
||||||
|
};*/
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public String getRefMapperConfig() { return null; }
|
||||||
|
@Override public void acceptTargets(Set<String> myTargets, Set<String> otherTargets) { }
|
||||||
|
@Override public List<String> getMixins() { return null; }
|
||||||
|
@Override public void preApply(String targetClassName, ClassNode classNode, String mixinClassName, IMixinInfo mixinInfo) { }
|
||||||
|
@Override public void postApply(String targetClassName, ClassNode classNode, String mixinClassName, IMixinInfo mixinInfo) { }
|
||||||
|
|
||||||
|
}
|
||||||
+30
-10
@@ -17,16 +17,36 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.seibel.distanthorizons.common.util;
|
package com.seibel.distanthorizons.cleanroom;
|
||||||
|
|
||||||
/**
|
import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin;
|
||||||
* Added to MC's dynamic textures via mixins
|
import org.jetbrains.annotations.Nullable;
|
||||||
* in order to denote whether a texture is a lightmap or not. <br><br>
|
|
||||||
*
|
import java.util.Map;
|
||||||
* If not done any dynamic texture could be used as the lightmap
|
|
||||||
* which causes some weird rendering bugs.
|
public class DistantHorizonsLoadingPlugin implements IFMLLoadingPlugin
|
||||||
*/
|
|
||||||
public interface ILightTextureMarker
|
|
||||||
{
|
{
|
||||||
void markLightTexture();
|
@Override
|
||||||
|
public @Nullable String[] getASMTransformerClass()
|
||||||
|
{
|
||||||
|
return new String[0];
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public @Nullable String getModContainerClass()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public @Nullable String getSetupClass()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void injectData(Map<String, Object> data) { }
|
||||||
|
@Override
|
||||||
|
public @Nullable String getAccessTransformerClass()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+84
@@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Distant Horizons mod
|
||||||
|
* licensed under the GNU LGPL v3 License.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 James Seibel
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.distanthorizons.cleanroom.mixins.client;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.common.commonMixins.MixinVanillaFogCommon;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
||||||
|
import com.seibel.distanthorizons.core.config.Config;
|
||||||
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.renderer.EntityRenderer;
|
||||||
|
import net.minecraft.client.renderer.GlStateManager;
|
||||||
|
import net.minecraft.client.renderer.texture.DynamicTexture;
|
||||||
|
import net.minecraft.init.MobEffects;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.spongepowered.asm.mixin.Final;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
@Mixin(EntityRenderer.class)
|
||||||
|
public class MixinEntityRenderer
|
||||||
|
{
|
||||||
|
@Shadow
|
||||||
|
@Final
|
||||||
|
private DynamicTexture lightmapTexture;
|
||||||
|
|
||||||
|
@Shadow @Final private Minecraft mc;
|
||||||
|
@Shadow @Final private static Logger LOGGER;
|
||||||
|
private static final float A_REALLY_REALLY_BIG_VALUE = 420694206942069.F;
|
||||||
|
private static final float A_EVEN_LARGER_VALUE = 42069420694206942069.F;
|
||||||
|
|
||||||
|
@Inject(at = @At("TAIL"), method = "updateLightmap")
|
||||||
|
public void onUpdateLightmap(float patrialTicks, CallbackInfo ci)
|
||||||
|
{
|
||||||
|
IMinecraftClientWrapper mc = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
|
||||||
|
if (mc == null || mc.getWrappedClientLevel() == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
IClientLevelWrapper clientLevel = mc.getWrappedClientLevel();
|
||||||
|
MinecraftRenderWrapper renderWrapper = (MinecraftRenderWrapper)SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
|
||||||
|
renderWrapper.setLightmapId(lightmapTexture.getGlTextureId(), clientLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(at = @At("RETURN"), method = "setupFog")
|
||||||
|
private void disableSetupFog(int startCoords, float partialTicks, CallbackInfo ci)
|
||||||
|
{
|
||||||
|
boolean cancelFog = MixinVanillaFogCommon.cancelFog(startCoords, mc);
|
||||||
|
if (cancelFog)
|
||||||
|
{
|
||||||
|
GlStateManager.setFogStart(A_REALLY_REALLY_BIG_VALUE);
|
||||||
|
GlStateManager.setFogEnd(A_EVEN_LARGER_VALUE);
|
||||||
|
ClientApi.RENDER_STATE.vanillaFogEnabled = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ClientApi.RENDER_STATE.vanillaFogEnabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+46
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Distant Horizons mod
|
||||||
|
* licensed under the GNU LGPL v3 License.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 James Seibel
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.distanthorizons.cleanroom.mixins.client;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
||||||
|
import net.minecraft.client.network.NetHandlerPlayClient;
|
||||||
|
import net.minecraft.network.play.server.SPacketJoinGame;
|
||||||
|
import net.minecraft.util.text.ITextComponent;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
@Mixin(NetHandlerPlayClient.class)
|
||||||
|
public class MixinNetHandlerPlayClient
|
||||||
|
{
|
||||||
|
@Inject(method = "handleJoinGame", at = @At("RETURN"))
|
||||||
|
private void onHandleJoinGameEnd(SPacketJoinGame packet, CallbackInfo ci)
|
||||||
|
{
|
||||||
|
ClientApi.INSTANCE.onClientOnlyConnected();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "onDisconnect", at = @At("RETURN"))
|
||||||
|
private void onDisconnect(ITextComponent reason, CallbackInfo ci)
|
||||||
|
{
|
||||||
|
ClientApi.INSTANCE.onClientOnlyDisconnected();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+83
@@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Distant Horizons mod
|
||||||
|
* licensed under the GNU LGPL v3 License.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 James Seibel
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.distanthorizons.cleanroom.mixins.client;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.gui.GetConfigScreen;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.gui.TexturedButtonWidget;
|
||||||
|
import com.seibel.distanthorizons.core.config.Config;
|
||||||
|
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.gui.GuiButton;
|
||||||
|
import net.minecraft.client.gui.GuiOptions;
|
||||||
|
import net.minecraft.client.gui.GuiScreen;
|
||||||
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a button to the menu to goto the config
|
||||||
|
*
|
||||||
|
* @author coolGi
|
||||||
|
* @version 12-02-2021
|
||||||
|
*/
|
||||||
|
@Mixin(GuiOptions.class)
|
||||||
|
public class MixinOptionsScreen extends GuiScreen
|
||||||
|
{
|
||||||
|
// Get the texture for the button
|
||||||
|
@Unique private static final ResourceLocation ICON_TEXTURE = new ResourceLocation(ModInfo.ID, "textures/gui/button.png");
|
||||||
|
|
||||||
|
@Unique private static final int button_id = 99;
|
||||||
|
|
||||||
|
@Inject(at = @At("HEAD"), method = "initGui")
|
||||||
|
private void lodconfig$init(CallbackInfo ci)
|
||||||
|
{
|
||||||
|
if (Config.Client.showDhOptionsButtonInMinecraftUi.get())
|
||||||
|
this.buttonList.add(
|
||||||
|
(new TexturedButtonWidget(
|
||||||
|
button_id,
|
||||||
|
// Where the button is on the screen
|
||||||
|
this.width / 2 - 180, this.height / 6 - 12,
|
||||||
|
// Width and height of the button
|
||||||
|
20, 20,
|
||||||
|
// Offset
|
||||||
|
0, 0,
|
||||||
|
// Some textuary stuff
|
||||||
|
20, ICON_TEXTURE, 20, 40,
|
||||||
|
// Create the button and tell it where to go
|
||||||
|
// For now it goes to the client option by default
|
||||||
|
// Add a title to the button
|
||||||
|
ModInfo.ID + ".title")));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(at = @At("HEAD"), method = "actionPerformed", cancellable = true)
|
||||||
|
private void lodconfig$actionPerformed(GuiButton button, CallbackInfo ci)
|
||||||
|
{
|
||||||
|
if (button.id == button_id)
|
||||||
|
{
|
||||||
|
Minecraft.getMinecraft().displayGuiScreen(GetConfigScreen.getScreen(this));
|
||||||
|
ci.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+81
@@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Distant Horizons mod
|
||||||
|
* licensed under the GNU LGPL v3 License.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 James Seibel
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.distanthorizons.cleanroom.mixins.client;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
||||||
|
import com.seibel.distanthorizons.core.util.math.Mat4f;
|
||||||
|
import net.minecraft.client.multiplayer.WorldClient;
|
||||||
|
import net.minecraft.client.renderer.GlStateManager;
|
||||||
|
import net.minecraft.client.renderer.RenderGlobal;
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.util.BlockRenderLayer;
|
||||||
|
import org.lwjgl.opengl.GL11;
|
||||||
|
import org.lwjgl.opengl.GL15;
|
||||||
|
import org.lwjgl.opengl.GL20;
|
||||||
|
import org.lwjgl.opengl.GL30;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
@Mixin(RenderGlobal.class)
|
||||||
|
public class MixinRenderGlobal
|
||||||
|
{
|
||||||
|
@Shadow private WorldClient world;
|
||||||
|
|
||||||
|
@Inject(method = "renderBlockLayer(Lnet/minecraft/util/BlockRenderLayer;DILnet/minecraft/entity/Entity;)I", at = @At("HEAD"))
|
||||||
|
private void renderChunkLayer(BlockRenderLayer blockLayerIn, double partialTicks, int pass, Entity entityIn, CallbackInfoReturnable<Integer> cir)
|
||||||
|
{
|
||||||
|
if (blockLayerIn == BlockRenderLayer.SOLID)
|
||||||
|
{
|
||||||
|
float[] mcProjMatrixRaw = new float[16];
|
||||||
|
GL11.glGetFloatv(GL11.GL_PROJECTION_MATRIX, mcProjMatrixRaw);
|
||||||
|
ClientApi.RENDER_STATE.mcProjectionMatrix = new Mat4f(mcProjMatrixRaw);
|
||||||
|
ClientApi.RENDER_STATE.mcProjectionMatrix.transpose();
|
||||||
|
|
||||||
|
float[] mcModelViewRaw = new float[16];
|
||||||
|
GL11.glGetFloatv(GL11.GL_MODELVIEW_MATRIX, mcModelViewRaw);
|
||||||
|
ClientApi.RENDER_STATE.mcModelViewMatrix = new Mat4f(mcModelViewRaw);
|
||||||
|
ClientApi.RENDER_STATE.mcModelViewMatrix.transpose();
|
||||||
|
|
||||||
|
ClientApi.RENDER_STATE.partialTickTime = (float) partialTicks;
|
||||||
|
ClientApi.RENDER_STATE.clientLevelWrapper = ClientLevelWrapper.getWrapperIfDifferent(ClientApi.RENDER_STATE.clientLevelWrapper, this.world);
|
||||||
|
|
||||||
|
int blendSrc = GL11.glGetInteger(GL11.GL_BLEND_SRC);
|
||||||
|
int blendDst = GL11.glGetInteger(GL11.GL_BLEND_DST);
|
||||||
|
int boundTexture = GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D);
|
||||||
|
|
||||||
|
ClientApi.INSTANCE.renderLods();
|
||||||
|
|
||||||
|
GL30.glBindVertexArray(0);
|
||||||
|
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||||
|
GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||||
|
GL20.glUseProgram(0);
|
||||||
|
|
||||||
|
//Restore vanilla states
|
||||||
|
GlStateManager.depthFunc(GL11.GL_LEQUAL);
|
||||||
|
GlStateManager.bindTexture(boundTexture);
|
||||||
|
GlStateManager.tryBlendFuncSeparate(blendSrc, blendDst, GL11.GL_ONE, GL11.GL_ZERO);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
package com.seibel.distanthorizons.cleanroom.mixins.common;
|
||||||
|
|
||||||
|
import net.minecraft.world.storage.ThreadedFileIOBase;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
|
||||||
|
@Mixin(ThreadedFileIOBase.class)
|
||||||
|
public class MixinThreadedFileIOBase
|
||||||
|
{
|
||||||
|
@Redirect(method = "processQueue", at = @At(value = "INVOKE", target = "Ljava/lang/Thread;sleep(J)V"))
|
||||||
|
private void reduceSleep(long millis) throws InterruptedException
|
||||||
|
{
|
||||||
|
// 0ms between chunks, 5ms when idle
|
||||||
|
Thread.sleep(millis == 25L ? 5L : 0L);
|
||||||
|
}
|
||||||
|
}
|
||||||
+66
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Distant Horizons mod
|
||||||
|
* licensed under the GNU LGPL v3 License.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 James Seibel
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.distanthorizons.cleanroom.mixins.server;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.misc.IMixinServerPlayer;
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.entity.player.EntityPlayerMP;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.world.WorldServer;
|
||||||
|
import net.minecraftforge.common.util.ITeleporter;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.spongepowered.asm.mixin.Final;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
@Mixin(EntityPlayerMP.class)
|
||||||
|
public abstract class MixinEntityPlayerMP implements IMixinServerPlayer
|
||||||
|
{
|
||||||
|
@Shadow
|
||||||
|
@Final
|
||||||
|
public MinecraftServer server;
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
@Nullable
|
||||||
|
private volatile WorldServer distantHorizons$dimensionChangeDestination;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public WorldServer distantHorizons$getDimensionChangeDestination()
|
||||||
|
{ return this.distantHorizons$dimensionChangeDestination; }
|
||||||
|
|
||||||
|
@Inject(at = @At("HEAD"), method = "changeDimension(ILnet/minecraftforge/common/util/ITeleporter;)Lnet/minecraft/entity/Entity;")
|
||||||
|
public void setDimensionChangeDestination(int destinationDimensionID, ITeleporter teleporter, CallbackInfoReturnable<Entity> cir)
|
||||||
|
{ this.distantHorizons$dimensionChangeDestination = this.server.getWorld(destinationDimensionID); }
|
||||||
|
|
||||||
|
@Inject(at = @At("RETURN"), method = "clearInvulnerableDimensionChange")
|
||||||
|
public void clearDimensionChangeDestination(CallbackInfo ci)
|
||||||
|
{ this.distantHorizons$dimensionChangeDestination = null; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+52
@@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Distant Horizons mod
|
||||||
|
* licensed under the GNU LGPL v3 License.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 James Seibel
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.distanthorizons.cleanroom.modAccessor;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker;
|
||||||
|
import net.minecraftforge.fml.common.Loader;
|
||||||
|
import net.minecraftforge.fml.common.ModContainer;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public class ModChecker implements IModChecker
|
||||||
|
{
|
||||||
|
public static final ModChecker INSTANCE = new ModChecker();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isModLoaded(String modid)
|
||||||
|
{
|
||||||
|
return Loader.isModLoaded(modid);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public File modLocation(String modid)
|
||||||
|
{
|
||||||
|
Stream<ModContainer> foundStream = Loader.instance().getModList().stream().filter(x -> x.getModId().equals(modid));
|
||||||
|
Optional<ModContainer> container = foundStream.findFirst();
|
||||||
|
if (!container.isPresent())
|
||||||
|
{
|
||||||
|
throw new RuntimeException("Mod not found: " + modid);
|
||||||
|
}
|
||||||
|
return container.get().getSource();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"required": true,
|
||||||
|
"package": "com.seibel.distanthorizons.cleanroom.mixins",
|
||||||
|
"compatibilityLevel": "JAVA_8",
|
||||||
|
"target": "@env(DEFAULT)",
|
||||||
|
"mixins": [
|
||||||
|
"common.MixinThreadedFileIOBase"
|
||||||
|
],
|
||||||
|
"minVersion": "0.8.7",
|
||||||
|
"server": [
|
||||||
|
"server.MixinEntityPlayerMP"
|
||||||
|
],
|
||||||
|
"client": [
|
||||||
|
"client.MixinEntityRenderer",
|
||||||
|
"client.MixinNetHandlerPlayClient",
|
||||||
|
"client.MixinOptionsScreen",
|
||||||
|
"client.MixinRenderGlobal"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"required": false,
|
||||||
|
"package": "com.seibel.distanthorizons.cleanroom.mixins.mod",
|
||||||
|
"compatibilityLevel": "JAVA_8",
|
||||||
|
"target": "@env(MOD)",
|
||||||
|
"mixins": [],
|
||||||
|
"minVersion": "0.8.7",
|
||||||
|
"plugin": "com.seibel.distanthorizons.cleanroom.DistantHorizonsConfigPlugin",
|
||||||
|
"client": [
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
[{
|
||||||
|
"modid": "${mod_id}",
|
||||||
|
"name": "${mod_name}",
|
||||||
|
"version": "${version}",
|
||||||
|
"mcversion": "1.12.2",
|
||||||
|
"description": "${description}",
|
||||||
|
"authorList": ["${cleanroom_authors}"],
|
||||||
|
"credits": "",
|
||||||
|
"url": "",
|
||||||
|
"updateJSON": "",
|
||||||
|
"logoFile": "${logo_path}"
|
||||||
|
}]
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"pack": {
|
||||||
|
"description": "${mod_name} Resources",
|
||||||
|
"pack_format": 3
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-39
@@ -1,41 +1,3 @@
|
|||||||
|
|
||||||
// temporary fix for broken spongepowered version
|
|
||||||
buildscript {
|
|
||||||
configurations.configureEach {
|
|
||||||
resolutionStrategy {
|
|
||||||
force 'org.spongepowered:vanillagradle:0.2.1-20240507.024226-82'
|
|
||||||
// newer versions can be found by going to the link:
|
|
||||||
// https://repo.spongepowered.org/#browse/browse:maven-public:org%2Fspongepowered%2Fvanillagradle%2F0.2.1-SNAPSHOT
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id "org.spongepowered.gradle.vanilla" version "0.2.1-SNAPSHOT"
|
id 'dh-loader'
|
||||||
}
|
}
|
||||||
|
|
||||||
minecraft {
|
|
||||||
accessWideners(project(":common").file("src/main/resources/${accessWidenerVersion}.distanthorizons.accesswidener"))
|
|
||||||
version(rootProject.minecraft_version)
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
// So mixins can be written in common
|
|
||||||
compileOnly group:'org.spongepowered', name:'mixin', version:'0.8.5'
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
publishing {
|
|
||||||
publications {
|
|
||||||
mavenCommon(MavenPublication) {
|
|
||||||
artifactId = rootProject.mod_readable_name
|
|
||||||
from components.java
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing.
|
|
||||||
repositories {
|
|
||||||
// Add repositories to publish to here.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
+144
-11
@@ -1,14 +1,14 @@
|
|||||||
package com.seibel.distanthorizons.common;
|
package com.seibel.distanthorizons.common;
|
||||||
|
|
||||||
import com.mojang.brigadier.CommandDispatcher;
|
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderingEngine;
|
||||||
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiAfterDhInitEvent;
|
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiAfterDhInitEvent;
|
||||||
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeDhInitEvent;
|
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeDhInitEvent;
|
||||||
import com.seibel.distanthorizons.common.commands.CommandInitializer;
|
import com.seibel.distanthorizons.common.commands.CommandInitializer;
|
||||||
import com.seibel.distanthorizons.common.wrappers.DependencySetup;
|
import com.seibel.distanthorizons.common.wrappers.DependencySetup;
|
||||||
import com.seibel.distanthorizons.common.wrappers.gui.DhDebugScreenEntry;
|
import com.seibel.distanthorizons.common.wrappers.gui.DhDebugScreenEntry;
|
||||||
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftServerWrapper;
|
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftServerWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.Initializer;
|
||||||
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
||||||
import com.seibel.distanthorizons.core.api.internal.SharedApi;
|
|
||||||
import com.seibel.distanthorizons.core.config.Config;
|
import com.seibel.distanthorizons.core.config.Config;
|
||||||
import com.seibel.distanthorizons.core.config.ConfigHandler;
|
import com.seibel.distanthorizons.core.config.ConfigHandler;
|
||||||
import com.seibel.distanthorizons.core.config.eventHandlers.presets.ThreadPresetConfigEventHandler;
|
import com.seibel.distanthorizons.core.config.eventHandlers.presets.ThreadPresetConfigEventHandler;
|
||||||
@@ -18,18 +18,30 @@ import com.seibel.distanthorizons.core.enums.MinecraftTextFormat;
|
|||||||
import com.seibel.distanthorizons.core.jar.ModJarInfo;
|
import com.seibel.distanthorizons.core.jar.ModJarInfo;
|
||||||
import com.seibel.distanthorizons.core.jar.updater.SelfUpdater;
|
import com.seibel.distanthorizons.core.jar.updater.SelfUpdater;
|
||||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import com.seibel.distanthorizons.core.render.renderer.AbstractDebugWireframeRenderer;
|
||||||
|
import com.seibel.distanthorizons.core.render.renderer.StubDebugWireframeRenderer;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.gui.NativeDialogUtil;
|
||||||
|
import com.seibel.distanthorizons.core.util.ThreadUtil;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IIrisAccessor;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModAccessor;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModAccessor;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker;
|
||||||
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
|
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
|
||||||
import com.seibel.distanthorizons.coreapi.ModInfo;
|
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||||
import net.minecraft.commands.CommandSourceStack;
|
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.server.dedicated.DedicatedServer;
|
import net.minecraft.server.dedicated.DedicatedServer;
|
||||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
#if MC_VER > MC_1_12_2
|
||||||
|
import com.mojang.brigadier.CommandDispatcher;
|
||||||
|
import net.minecraft.commands.CommandSourceStack;
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base for all mod loader initializers
|
* Base for all mod loader initializers
|
||||||
* and handles most setup.
|
* and handles most setup.
|
||||||
@@ -45,6 +57,7 @@ public abstract class AbstractModInitializer
|
|||||||
//==================//
|
//==================//
|
||||||
// abstract methods //
|
// abstract methods //
|
||||||
//==================//
|
//==================//
|
||||||
|
//region
|
||||||
|
|
||||||
protected abstract void createInitialSharedBindings();
|
protected abstract void createInitialSharedBindings();
|
||||||
protected abstract void createInitialClientBindings();
|
protected abstract void createInitialClientBindings();
|
||||||
@@ -52,17 +65,22 @@ public abstract class AbstractModInitializer
|
|||||||
protected abstract IEventProxy createServerProxy(boolean isDedicated);
|
protected abstract IEventProxy createServerProxy(boolean isDedicated);
|
||||||
protected abstract void initializeModCompat();
|
protected abstract void initializeModCompat();
|
||||||
|
|
||||||
|
#if MC_VER > MC_1_12_2
|
||||||
protected abstract void subscribeRegisterCommandsEvent(Consumer<CommandDispatcher<CommandSourceStack>> eventHandler);
|
protected abstract void subscribeRegisterCommandsEvent(Consumer<CommandDispatcher<CommandSourceStack>> eventHandler);
|
||||||
|
#endif
|
||||||
|
|
||||||
protected abstract void subscribeClientStartedEvent(Runnable eventHandler);
|
protected abstract void subscribeClientStartedEvent(Runnable eventHandler);
|
||||||
protected abstract void subscribeServerStartingEvent(Consumer<MinecraftServer> eventHandler);
|
protected abstract void subscribeServerStartingEvent(Consumer<MinecraftServer> eventHandler);
|
||||||
protected abstract void runDelayedSetup();
|
protected abstract void runDelayedSetup();
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//===================//
|
//===================//
|
||||||
// initialize events //
|
// initialize events //
|
||||||
//===================//
|
//===================//
|
||||||
|
//region
|
||||||
|
|
||||||
public void onInitializeClient()
|
public void onInitializeClient()
|
||||||
{
|
{
|
||||||
@@ -82,7 +100,9 @@ public abstract class AbstractModInitializer
|
|||||||
|
|
||||||
// Client uses config for auto-updater, so it's initialized here instead of post-init stage
|
// Client uses config for auto-updater, so it's initialized here instead of post-init stage
|
||||||
this.initConfig();
|
this.initConfig();
|
||||||
logModIncompatibilityWarnings(); // needs to be called after config loading
|
logIncompatibilityWarnings(); // needs to be called after config loading
|
||||||
|
setUnsupportedConfigsBasedOnMcVersion();
|
||||||
|
Initializer.postConfigInit();
|
||||||
|
|
||||||
LOGGER.info(ModInfo.READABLE_NAME + " client Initialized.");
|
LOGGER.info(ModInfo.READABLE_NAME + " client Initialized.");
|
||||||
|
|
||||||
@@ -93,6 +113,7 @@ public abstract class AbstractModInitializer
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
this.subscribeClientStartedEvent(this::postInit);
|
this.subscribeClientStartedEvent(this::postInit);
|
||||||
|
this.subscribeClientStartedEvent(this::postClientInit);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onInitializeServer()
|
public void onInitializeServer()
|
||||||
@@ -115,33 +136,49 @@ public abstract class AbstractModInitializer
|
|||||||
this.initializeModCompat();
|
this.initializeModCompat();
|
||||||
|
|
||||||
LOGGER.info(ModInfo.READABLE_NAME + " server Initialized, adding event subscribers...");
|
LOGGER.info(ModInfo.READABLE_NAME + " server Initialized, adding event subscribers...");
|
||||||
|
#if MC_VER > MC_1_12_2
|
||||||
this.commandInitializer = new CommandInitializer();
|
this.commandInitializer = new CommandInitializer();
|
||||||
this.subscribeRegisterCommandsEvent(dispatcher -> { this.commandInitializer.initCommands(dispatcher); });
|
this.subscribeRegisterCommandsEvent(dispatcher -> { this.commandInitializer.initCommands(dispatcher); });
|
||||||
|
#endif
|
||||||
|
|
||||||
this.subscribeServerStartingEvent(server ->
|
this.subscribeServerStartingEvent(server ->
|
||||||
{
|
{
|
||||||
MinecraftServerWrapper.INSTANCE.dedicatedServer = (DedicatedServer)server;
|
MinecraftServerWrapper.INSTANCE.dedicatedServer = (DedicatedServer)server;
|
||||||
|
|
||||||
this.initConfig();
|
this.initConfig();
|
||||||
|
Initializer.postConfigInit();
|
||||||
this.postInit();
|
this.postInit();
|
||||||
|
this.postServerInit();
|
||||||
|
#if MC_VER > MC_1_12_2
|
||||||
this.commandInitializer.onServerReady();
|
this.commandInitializer.onServerReady();
|
||||||
|
#endif
|
||||||
|
|
||||||
this.checkForUpdates();
|
this.checkForUpdates();
|
||||||
|
|
||||||
LOGGER.info(ModInfo.READABLE_NAME + " server Initialized at " + server.getServerDirectory());
|
String serverFolderPath;
|
||||||
|
#if MC_VER <= MC_1_12_2
|
||||||
|
serverFolderPath = server.getDataDirectory() + "";
|
||||||
|
#else
|
||||||
|
serverFolderPath = server.getServerDirectory() + "";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
LOGGER.info(ModInfo.READABLE_NAME + " server Initialized at " + serverFolderPath);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//===========================//
|
//===========================//
|
||||||
// inner initializer methods //
|
// inner initializer methods //
|
||||||
//===========================//
|
//===========================//
|
||||||
|
//region
|
||||||
|
|
||||||
private void startup()
|
private void startup()
|
||||||
{
|
{
|
||||||
DependencySetup.createSharedBindings();
|
DependencySetup.createSharedBindings();
|
||||||
SharedApi.init();
|
Initializer.preConfigInit();
|
||||||
this.createInitialSharedBindings();
|
this.createInitialSharedBindings();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,11 +246,44 @@ public abstract class AbstractModInitializer
|
|||||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiAfterDhInitEvent.class, null);
|
ApiEventInjector.INSTANCE.fireAllEvents(DhApiAfterDhInitEvent.class, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void postClientInit()
|
||||||
|
{
|
||||||
|
CompletableFuture<Void> future = new CompletableFuture<>();
|
||||||
|
|
||||||
|
// This method may be called from either the render thread,
|
||||||
|
// or some other random setup thread depending on the mod loader.
|
||||||
|
// In order to avoid confusion/inconsistent problems, we're always going
|
||||||
|
// to run setup on our own thread.
|
||||||
|
Thread dhSetupThread = new Thread(() ->
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
DependencySetup.setRenderingApiBindings();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
future.completeExceptionally(e);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
future.complete(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
dhSetupThread.setName(ThreadUtil.THREAD_NAME_PREFIX + "PostClientInit Thread");
|
||||||
|
dhSetupThread.start();
|
||||||
|
|
||||||
|
future.join();
|
||||||
|
}
|
||||||
|
private void postServerInit() { SingletonInjector.INSTANCE.bind(AbstractDebugWireframeRenderer.class, new StubDebugWireframeRenderer()); }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
//==================================//
|
|
||||||
// mod partial compatibility checks //
|
//======================//
|
||||||
//==================================//
|
// compatibility checks //
|
||||||
|
//======================//
|
||||||
|
//region
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Some mods will work with a few tweaks
|
* Some mods will work with a few tweaks
|
||||||
@@ -221,7 +291,7 @@ public abstract class AbstractModInitializer
|
|||||||
* This method will log (and display to chat if enabled)
|
* This method will log (and display to chat if enabled)
|
||||||
* these warnings and potential fixes.
|
* these warnings and potential fixes.
|
||||||
*/
|
*/
|
||||||
private static void logModIncompatibilityWarnings()
|
private static void logIncompatibilityWarnings()
|
||||||
{
|
{
|
||||||
boolean showChatWarnings = Config.Common.Logging.Warning.showModCompatibilityWarningsOnStartup.get();
|
boolean showChatWarnings = Config.Common.Logging.Warning.showModCompatibilityWarningsOnStartup.get();
|
||||||
IModChecker modChecker = SingletonInjector.INSTANCE.get(IModChecker.class);
|
IModChecker modChecker = SingletonInjector.INSTANCE.get(IModChecker.class);
|
||||||
@@ -231,6 +301,7 @@ public abstract class AbstractModInitializer
|
|||||||
|
|
||||||
|
|
||||||
// Alex's caves
|
// Alex's caves
|
||||||
|
//region
|
||||||
if (modChecker.isModLoaded("alexscaves"))
|
if (modChecker.isModLoaded("alexscaves"))
|
||||||
{
|
{
|
||||||
// There've been a few reports about this mod breaking DH at a few different points in time
|
// There've been a few reports about this mod breaking DH at a few different points in time
|
||||||
@@ -247,8 +318,10 @@ public abstract class AbstractModInitializer
|
|||||||
|
|
||||||
LOGGER.warn(startingString + "[Alex's Caves] may require some config changes in order to render Distant Horizons correctly.");
|
LOGGER.warn(startingString + "[Alex's Caves] may require some config changes in order to render Distant Horizons correctly.");
|
||||||
}
|
}
|
||||||
|
//endregion
|
||||||
|
|
||||||
// William Wythers' Overhauled Overworld (WWOO)
|
// William Wythers' Overhauled Overworld (WWOO)
|
||||||
|
//region
|
||||||
if (modChecker.isModLoaded("wwoo"))
|
if (modChecker.isModLoaded("wwoo"))
|
||||||
{
|
{
|
||||||
// WWOO has a bug with it's world gen that can't be fixed by DH or WWOO
|
// WWOO has a bug with it's world gen that can't be fixed by DH or WWOO
|
||||||
@@ -269,8 +342,11 @@ public abstract class AbstractModInitializer
|
|||||||
|
|
||||||
LOGGER.warn(startingString + "[WWOO] "+ wwooWarning);
|
LOGGER.warn(startingString + "[WWOO] "+ wwooWarning);
|
||||||
}
|
}
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
// Chunky //
|
||||||
|
//region
|
||||||
|
|
||||||
// Chunky
|
|
||||||
boolean chunkyPresent = false;
|
boolean chunkyPresent = false;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -300,17 +376,74 @@ public abstract class AbstractModInitializer
|
|||||||
LOGGER.warn(startingString + "[Chunky] "+ chunkyWarning);
|
LOGGER.warn(startingString + "[Chunky] "+ chunkyWarning);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
// iris //
|
||||||
|
//region
|
||||||
|
|
||||||
|
IIrisAccessor iris = ModAccessorInjector.INSTANCE.get(IIrisAccessor.class);
|
||||||
|
if (iris != null)
|
||||||
|
{
|
||||||
|
// get the currently selected rendering API
|
||||||
|
EDhApiRenderingEngine renderApi = Config.Client.Advanced.Graphics.Experimental.renderingEngine.get();
|
||||||
|
if (renderApi == EDhApiRenderingEngine.AUTO)
|
||||||
|
{
|
||||||
|
IVersionConstants versionConstants = SingletonInjector.INSTANCE.get(IVersionConstants.class);
|
||||||
|
renderApi = versionConstants.getDefaultRenderingEngine();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iris only supports native OpenGL
|
||||||
|
if (renderApi != EDhApiRenderingEngine.OPEN_GL)
|
||||||
|
{
|
||||||
|
String irisUnsupportedMessage = "Iris doesn't support DH when using the ["+ EDhApiRenderingEngine.BLAZE_3D+"] rendering engine, this will need to be fixed on Iris end. As a temporary fix please change the rendering engine to ["+ EDhApiRenderingEngine.OPEN_GL+"] in the DH config file.";
|
||||||
|
LOGGER.fatal(irisUnsupportedMessage);
|
||||||
|
NativeDialogUtil.showDialog(ModInfo.READABLE_NAME, irisUnsupportedMessage, "ok", "error");
|
||||||
|
|
||||||
|
IMinecraftClientWrapper mc = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
|
||||||
|
String errorMessage = "loading Distant Horizons. "+irisUnsupportedMessage;
|
||||||
|
String exceptionError = "Distant Horizons conditional mod config Exception";
|
||||||
|
mc.crashMinecraft(errorMessage, new Exception(exceptionError));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Some Minecraft versions don't support all
|
||||||
|
* DH options.
|
||||||
|
* In that case we need to override what options are available.
|
||||||
|
*/
|
||||||
|
private static void setUnsupportedConfigsBasedOnMcVersion()
|
||||||
|
{
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_12_2
|
||||||
|
Config.Client.Advanced.Graphics.Experimental.renderingEngine.setMcVersionOverrideValue(EDhApiRenderingEngine.OPEN_GL);
|
||||||
|
Config.Client.Advanced.Graphics.Quality.vanillaFadeMode.setMcVersionOverrideValue(EDhApiMcRenderingFadeMode.NONE);
|
||||||
|
Config.Common.WorldGenerator.distantGeneratorMode.setMcVersionOverrideValue(EDhApiDistantGeneratorMode.INTERNAL_SERVER);
|
||||||
|
#elif MC_VER <= MC_1_21_10
|
||||||
|
Config.Client.Advanced.Graphics.Experimental.renderingEngine.setMcVersionOverrideValue(EDhApiRenderingEngine.OPEN_GL);
|
||||||
|
#else
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//================//
|
//================//
|
||||||
// helper classes //
|
// helper classes //
|
||||||
//================//
|
//================//
|
||||||
|
//region
|
||||||
|
|
||||||
public interface IEventProxy
|
public interface IEventProxy
|
||||||
{
|
{
|
||||||
void registerEvents();
|
void registerEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+29
-2
@@ -12,10 +12,17 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSende
|
|||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
|
||||||
import com.seibel.distanthorizons.coreapi.ModInfo;
|
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||||
import io.netty.buffer.ByteBufUtil;
|
import io.netty.buffer.ByteBufUtil;
|
||||||
|
#if MC_VER <= MC_1_12_2
|
||||||
|
import net.minecraft.entity.player.EntityPlayerMP;
|
||||||
|
import net.minecraft.network.PacketBuffer;
|
||||||
|
#else
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if MC_VER <= MC_1_21_10
|
#if MC_VER <= MC_1_12_2
|
||||||
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
#elif MC_VER <= MC_1_21_10
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
#else
|
#else
|
||||||
import net.minecraft.resources.Identifier;
|
import net.minecraft.resources.Identifier;
|
||||||
@@ -30,7 +37,9 @@ public abstract class AbstractPluginPacketSender implements IPluginPacketSender
|
|||||||
.fileLevelConfig(Config.Common.Logging.logNetworkEventToFile)
|
.fileLevelConfig(Config.Common.Logging.logNetworkEventToFile)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
#if MC_VER <= MC_1_20_6
|
#if MC_VER <= MC_1_12_2
|
||||||
|
public static final String WRAPPER_PACKET_RESOURCE = ModInfo.RESOURCE_NAMESPACE + ModInfo.WRAPPER_PACKET_PATH;
|
||||||
|
#elif MC_VER <= MC_1_20_6
|
||||||
public static final ResourceLocation WRAPPER_PACKET_RESOURCE = new ResourceLocation(ModInfo.RESOURCE_NAMESPACE, ModInfo.WRAPPER_PACKET_PATH);
|
public static final ResourceLocation WRAPPER_PACKET_RESOURCE = new ResourceLocation(ModInfo.RESOURCE_NAMESPACE, ModInfo.WRAPPER_PACKET_PATH);
|
||||||
#elif MC_VER <= MC_1_21_10
|
#elif MC_VER <= MC_1_21_10
|
||||||
public static final ResourceLocation WRAPPER_PACKET_RESOURCE = ResourceLocation.fromNamespaceAndPath(ModInfo.RESOURCE_NAMESPACE, ModInfo.WRAPPER_PACKET_PATH);
|
public static final ResourceLocation WRAPPER_PACKET_RESOURCE = ResourceLocation.fromNamespaceAndPath(ModInfo.RESOURCE_NAMESPACE, ModInfo.WRAPPER_PACKET_PATH);
|
||||||
@@ -52,14 +61,28 @@ public abstract class AbstractPluginPacketSender implements IPluginPacketSender
|
|||||||
@Override
|
@Override
|
||||||
public final void sendToClient(IServerPlayerWrapper serverPlayer, AbstractNetworkMessage message)
|
public final void sendToClient(IServerPlayerWrapper serverPlayer, AbstractNetworkMessage message)
|
||||||
{
|
{
|
||||||
|
#if MC_VER <= MC_1_12_2
|
||||||
|
this.sendToClient((EntityPlayerMP) serverPlayer.getWrappedMcObject(), message);
|
||||||
|
#else
|
||||||
this.sendToClient((ServerPlayer) serverPlayer.getWrappedMcObject(), message);
|
this.sendToClient((ServerPlayer) serverPlayer.getWrappedMcObject(), message);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_12_2
|
||||||
|
public abstract void sendToClient(EntityPlayerMP serverPlayer, AbstractNetworkMessage message);
|
||||||
|
#else
|
||||||
public abstract void sendToClient(ServerPlayer serverPlayer, AbstractNetworkMessage message);
|
public abstract void sendToClient(ServerPlayer serverPlayer, AbstractNetworkMessage message);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public abstract void sendToServer(AbstractNetworkMessage message);
|
public abstract void sendToServer(AbstractNetworkMessage message);
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_12_2
|
||||||
|
public AbstractNetworkMessage decodeMessage(PacketBuffer in)
|
||||||
|
#else
|
||||||
public AbstractNetworkMessage decodeMessage(FriendlyByteBuf in)
|
public AbstractNetworkMessage decodeMessage(FriendlyByteBuf in)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
AbstractNetworkMessage message = null;
|
AbstractNetworkMessage message = null;
|
||||||
|
|
||||||
@@ -100,7 +123,11 @@ public abstract class AbstractPluginPacketSender implements IPluginPacketSender
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_12_2
|
||||||
|
public void encodeMessage(PacketBuffer out, AbstractNetworkMessage message)
|
||||||
|
#else
|
||||||
public void encodeMessage(FriendlyByteBuf out, AbstractNetworkMessage message)
|
public void encodeMessage(FriendlyByteBuf out, AbstractNetworkMessage message)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
// This is intentionally unhandled, because errors related to this are unlikely to appear in wild
|
// This is intentionally unhandled, because errors related to this are unlikely to appear in wild
|
||||||
Objects.requireNonNull(message);
|
Objects.requireNonNull(message);
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
package com.seibel.distanthorizons.common.commands;
|
package com.seibel.distanthorizons.common.commands;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_12_2
|
||||||
|
public abstract class AbstractCommand {}
|
||||||
|
|
||||||
|
#else
|
||||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||||
import com.mojang.brigadier.context.CommandContext;
|
import com.mojang.brigadier.context.CommandContext;
|
||||||
import com.seibel.distanthorizons.common.wrappers.misc.ServerPlayerWrapper;
|
import com.seibel.distanthorizons.common.wrappers.misc.ServerPlayerWrapper;
|
||||||
@@ -100,3 +104,4 @@ public abstract class AbstractCommand
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
+81
-3
@@ -1,12 +1,26 @@
|
|||||||
package com.seibel.distanthorizons.common.commands;
|
package com.seibel.distanthorizons.common.commands;
|
||||||
|
#if MC_VER <= MC_1_12_2
|
||||||
|
import com.seibel.distanthorizons.core.config.ConfigHandler;
|
||||||
|
import com.seibel.distanthorizons.core.config.types.AbstractConfigBase;
|
||||||
|
import com.seibel.distanthorizons.core.config.types.ConfigEntry;
|
||||||
|
import com.seibel.distanthorizons.core.logging.f3.F3Screen;
|
||||||
|
import net.minecraft.command.CommandBase;
|
||||||
|
import net.minecraft.command.ICommand;
|
||||||
|
import net.minecraft.command.ICommandSender;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.util.text.TextComponentString;
|
||||||
|
#else
|
||||||
import com.mojang.brigadier.CommandDispatcher;
|
import com.mojang.brigadier.CommandDispatcher;
|
||||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||||
import net.minecraft.commands.CommandSourceStack;
|
import net.minecraft.commands.CommandSourceStack;
|
||||||
|
import static net.minecraft.commands.Commands.literal;
|
||||||
|
#endif
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import static com.seibel.distanthorizons.core.network.messages.MessageRegistry.DEBUG_CODEC_CRASH_MESSAGE;
|
import static com.seibel.distanthorizons.core.network.messages.MessageRegistry.DEBUG_CODEC_CRASH_MESSAGE;
|
||||||
import static net.minecraft.commands.Commands.literal;
|
|
||||||
|
|
||||||
#if MC_VER <= MC_1_21_10
|
#if MC_VER <= MC_1_21_10
|
||||||
#else
|
#else
|
||||||
@@ -25,6 +39,70 @@ public class CommandInitializer
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_12_2
|
||||||
|
public static ICommand initCommands()
|
||||||
|
{
|
||||||
|
return new CommandBase()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public String getName() { return "dh"; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUsage(ICommandSender sender) { return "/dh <debug|config|pregen>"; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(MinecraftServer server, ICommandSender sender, String[] args)
|
||||||
|
{
|
||||||
|
if (args.length == 0)
|
||||||
|
{
|
||||||
|
if (DEBUG_CODEC_CRASH_MESSAGE)
|
||||||
|
{
|
||||||
|
sender.sendMessage(new TextComponentString("Usage: /dh <debug|config|crash|pregen>"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sender.sendMessage(new TextComponentString("Usage: /dh <debug|config|pregen"));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (args[0])
|
||||||
|
{
|
||||||
|
case "debug":
|
||||||
|
DebugCommand debugCommand = new DebugCommand();
|
||||||
|
debugCommand.execute(sender);
|
||||||
|
break;
|
||||||
|
case "config":
|
||||||
|
ConfigCommand configCommand = new ConfigCommand();
|
||||||
|
configCommand.execute(sender, args);
|
||||||
|
break;
|
||||||
|
case "crash":
|
||||||
|
if (DEBUG_CODEC_CRASH_MESSAGE)
|
||||||
|
{
|
||||||
|
CrashCommand crashCommand = new CrashCommand();
|
||||||
|
crashCommand.execute(sender, args);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "pregen":
|
||||||
|
if (!server.isDedicatedServer())
|
||||||
|
{
|
||||||
|
sender.sendMessage(new TextComponentString("Pregen command is only available on dedicated servers"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
PregenCommand pregenCommand = new PregenCommand();
|
||||||
|
pregenCommand.execute(server, sender, args);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sender.sendMessage(new TextComponentString("Unknown subcommand: " + args[0]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A received command dispatcher, which is held until the server is ready to initialize the commands.
|
* A received command dispatcher, which is held until the server is ready to initialize the commands.
|
||||||
*/
|
*/
|
||||||
@@ -80,5 +158,5 @@ public class CommandInitializer
|
|||||||
|
|
||||||
commandDispatcher.register(builder);
|
commandDispatcher.register(builder);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,25 @@
|
|||||||
package com.seibel.distanthorizons.common.commands;
|
package com.seibel.distanthorizons.common.commands;
|
||||||
|
|
||||||
import com.mojang.brigadier.arguments.*;
|
|
||||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
|
||||||
import com.mojang.brigadier.context.CommandContext;
|
|
||||||
import com.seibel.distanthorizons.core.config.ConfigHandler;
|
import com.seibel.distanthorizons.core.config.ConfigHandler;
|
||||||
import com.seibel.distanthorizons.core.config.types.AbstractConfigBase;
|
import com.seibel.distanthorizons.core.config.types.AbstractConfigBase;
|
||||||
import com.seibel.distanthorizons.core.config.types.ConfigEntry;
|
import com.seibel.distanthorizons.core.config.types.ConfigEntry;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_12_2
|
||||||
|
import net.minecraft.command.ICommandSender;
|
||||||
|
import net.minecraft.util.text.TextComponentString;
|
||||||
|
#else
|
||||||
|
import com.mojang.brigadier.arguments.*;
|
||||||
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||||
|
import com.mojang.brigadier.context.CommandContext;
|
||||||
import net.minecraft.commands.CommandSourceStack;
|
import net.minecraft.commands.CommandSourceStack;
|
||||||
|
|
||||||
|
import static com.mojang.brigadier.arguments.DoubleArgumentType.doubleArg;
|
||||||
|
import static com.mojang.brigadier.arguments.IntegerArgumentType.integer;
|
||||||
|
import static net.minecraft.commands.Commands.argument;
|
||||||
|
import static net.minecraft.commands.Commands.literal;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -16,16 +28,75 @@ import java.util.function.Function;
|
|||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import java.util.function.ToIntBiFunction;
|
import java.util.function.ToIntBiFunction;
|
||||||
|
|
||||||
import static com.mojang.brigadier.arguments.DoubleArgumentType.doubleArg;
|
|
||||||
import static com.mojang.brigadier.arguments.IntegerArgumentType.integer;
|
|
||||||
import static net.minecraft.commands.Commands.argument;
|
|
||||||
import static net.minecraft.commands.Commands.literal;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Command for managing config.
|
* Command for managing config.
|
||||||
*/
|
*/
|
||||||
public class ConfigCommand extends AbstractCommand
|
public class ConfigCommand extends AbstractCommand
|
||||||
{
|
{
|
||||||
|
#if MC_VER <= MC_1_12_2
|
||||||
|
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||||
|
private static void setConfigValue(ConfigEntry<?> configEntry, String value)
|
||||||
|
{
|
||||||
|
Class<?> type = configEntry.getType();
|
||||||
|
|
||||||
|
if (type == Boolean.class) ((ConfigEntry) configEntry).set(Boolean.parseBoolean(value));
|
||||||
|
else if (type == Integer.class) ((ConfigEntry) configEntry).set(Integer.parseInt(value));
|
||||||
|
else if (type == Double.class) ((ConfigEntry) configEntry).set(Double.parseDouble(value));
|
||||||
|
else if (type == Float.class) ((ConfigEntry) configEntry).set(Float.parseFloat(value));
|
||||||
|
else if (type == Long.class) ((ConfigEntry) configEntry).set(Long.parseLong(value));
|
||||||
|
else if (type == String.class) ((ConfigEntry) configEntry).set(value);
|
||||||
|
else if (type.isEnum()) ((ConfigEntry) configEntry).set(Enum.valueOf((Class<Enum>) type, value));
|
||||||
|
else throw new RuntimeException("Unsupported config type: " + type.getSimpleName());
|
||||||
|
}
|
||||||
|
public void execute(ICommandSender sender, String[] args)
|
||||||
|
{
|
||||||
|
if (args.length < 2)
|
||||||
|
{
|
||||||
|
sender.sendMessage(new TextComponentString("Usage: /dh config <name> [value]"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String configName = args[1];
|
||||||
|
AbstractConfigBase<?> found = null;
|
||||||
|
for (AbstractConfigBase<?> entry : ConfigHandler.INSTANCE.configBaseList)
|
||||||
|
{
|
||||||
|
if (entry instanceof ConfigEntry && configName.equals(((ConfigEntry<?>) entry).getChatCommandName()))
|
||||||
|
{
|
||||||
|
found = entry;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found == null)
|
||||||
|
{
|
||||||
|
sender.sendMessage(new TextComponentString("Unknown config: " + configName));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfigEntry<?> configEntry = (ConfigEntry<?>) found;
|
||||||
|
if (args.length == 2)
|
||||||
|
{
|
||||||
|
sender.sendMessage(new TextComponentString("Current value of " + configName + " is " + configEntry.get()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
String value = args[2];
|
||||||
|
try
|
||||||
|
{
|
||||||
|
setConfigValue(configEntry, value);
|
||||||
|
sender.sendMessage(new TextComponentString("Changed " + configName + " to " + value));
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
sender.sendMessage(new TextComponentString("Invalid value: " + value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
private static final List<CommandArgumentData<?>> commandArguments = Arrays.asList(
|
private static final List<CommandArgumentData<?>> commandArguments = Arrays.asList(
|
||||||
new CommandArgumentData<>(Integer.class, configEntry -> integer(configEntry.getMin(), configEntry.getMax()), IntegerArgumentType::getInteger),
|
new CommandArgumentData<>(Integer.class, configEntry -> integer(configEntry.getMin(), configEntry.getMax()), IntegerArgumentType::getInteger),
|
||||||
new CommandArgumentData<>(Double.class, configEntry -> doubleArg(configEntry.getMin(), configEntry.getMax()), DoubleArgumentType::getDouble),
|
new CommandArgumentData<>(Double.class, configEntry -> doubleArg(configEntry.getMin(), configEntry.getMax()), DoubleArgumentType::getDouble),
|
||||||
@@ -150,5 +221,6 @@ public class ConfigCommand extends AbstractCommand
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,15 +1,60 @@
|
|||||||
package com.seibel.distanthorizons.common.commands;
|
package com.seibel.distanthorizons.common.commands;
|
||||||
|
|
||||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
|
||||||
import com.seibel.distanthorizons.core.api.internal.SharedApi;
|
import com.seibel.distanthorizons.core.api.internal.SharedApi;
|
||||||
import com.seibel.distanthorizons.core.multiplayer.server.ServerPlayerState;
|
import com.seibel.distanthorizons.core.multiplayer.server.ServerPlayerState;
|
||||||
import com.seibel.distanthorizons.core.network.messages.base.CodecCrashMessage;
|
import com.seibel.distanthorizons.core.network.messages.base.CodecCrashMessage;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_12_2
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.misc.ServerPlayerWrapper;
|
||||||
|
import net.minecraft.command.ICommandSender;
|
||||||
|
import net.minecraft.entity.player.EntityPlayerMP;
|
||||||
|
import net.minecraft.util.text.TextComponentString;
|
||||||
|
#else
|
||||||
import net.minecraft.commands.CommandSourceStack;
|
import net.minecraft.commands.CommandSourceStack;
|
||||||
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||||
|
|
||||||
import static net.minecraft.commands.Commands.literal;
|
import static net.minecraft.commands.Commands.literal;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
public class CrashCommand extends AbstractCommand
|
public class CrashCommand extends AbstractCommand
|
||||||
{
|
{
|
||||||
|
#if MC_VER <= MC_1_12_2
|
||||||
|
public void execute(ICommandSender sender, String[] args)
|
||||||
|
{
|
||||||
|
if (!(sender instanceof EntityPlayerMP))
|
||||||
|
{
|
||||||
|
sender.sendMessage(new TextComponentString("This command can only be run by a player"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.length < 2)
|
||||||
|
{
|
||||||
|
sender.sendMessage(new TextComponentString("Usage: /dh crash <encode|decode>"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SharedApi.tryGetDhServerWorld() == null) return;
|
||||||
|
|
||||||
|
ServerPlayerState serverPlayerState = SharedApi.tryGetDhServerWorld()
|
||||||
|
.getServerPlayerStateManager()
|
||||||
|
.getConnectedPlayer(ServerPlayerWrapper.getWrapper((EntityPlayerMP) sender));
|
||||||
|
|
||||||
|
if (serverPlayerState == null) return;
|
||||||
|
|
||||||
|
switch (args[1])
|
||||||
|
{
|
||||||
|
case "encode":
|
||||||
|
serverPlayerState.networkSession.sendMessage(new CodecCrashMessage(CodecCrashMessage.ECrashPhase.ENCODE));
|
||||||
|
break;
|
||||||
|
case "decode":
|
||||||
|
serverPlayerState.networkSession.sendMessage(new CodecCrashMessage(CodecCrashMessage.ECrashPhase.DECODE));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sender.sendMessage(new TextComponentString("Usage: /dh crash <encode|decode>"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
@Override
|
@Override
|
||||||
public LiteralArgumentBuilder<CommandSourceStack> buildCommand()
|
public LiteralArgumentBuilder<CommandSourceStack> buildCommand()
|
||||||
{
|
{
|
||||||
@@ -40,5 +85,6 @@ public class CrashCommand extends AbstractCommand
|
|||||||
return 1;
|
return 1;
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,44 @@
|
|||||||
package com.seibel.distanthorizons.common.commands;
|
package com.seibel.distanthorizons.common.commands;
|
||||||
|
|
||||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
|
||||||
import com.seibel.distanthorizons.core.logging.f3.F3Screen;
|
import com.seibel.distanthorizons.core.logging.f3.F3Screen;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_12_2
|
||||||
|
import net.minecraft.command.ICommandSender;
|
||||||
|
import net.minecraft.util.text.TextComponentString;
|
||||||
|
#else
|
||||||
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||||
import net.minecraft.commands.CommandSourceStack;
|
import net.minecraft.commands.CommandSourceStack;
|
||||||
|
|
||||||
|
import static net.minecraft.commands.Commands.literal;
|
||||||
|
#endif
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static net.minecraft.commands.Commands.literal;
|
|
||||||
|
|
||||||
public class DebugCommand extends AbstractCommand
|
public class DebugCommand extends AbstractCommand
|
||||||
{
|
{
|
||||||
|
private static String getDebugString()
|
||||||
|
{
|
||||||
|
List<String> lines = new ArrayList<>();
|
||||||
|
F3Screen.addStringToDisplay(lines);
|
||||||
|
return String.join("\n", lines);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if MC_VER > MC_1_12_2
|
||||||
@Override
|
@Override
|
||||||
public LiteralArgumentBuilder<CommandSourceStack> buildCommand()
|
public LiteralArgumentBuilder<CommandSourceStack> buildCommand()
|
||||||
{
|
{
|
||||||
return literal("debug")
|
return literal("debug")
|
||||||
.executes(c -> {
|
.executes(c -> {
|
||||||
List<String> lines = new ArrayList<>();
|
return this.sendSuccessResponse(c, getDebugString(), false);
|
||||||
F3Screen.addStringToDisplay(lines);
|
});
|
||||||
return this.sendSuccessResponse(c, String.join("\n", lines), false);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
public void execute(ICommandSender sender)
|
||||||
|
{
|
||||||
|
sender.sendMessage(new TextComponentString(getDebugString()));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+122
-11
@@ -1,29 +1,140 @@
|
|||||||
package com.seibel.distanthorizons.common.commands;
|
package com.seibel.distanthorizons.common.commands;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.api.internal.SharedApi;
|
||||||
|
import com.seibel.distanthorizons.core.generation.PregenManager;
|
||||||
|
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos2D;
|
||||||
|
import com.seibel.distanthorizons.core.world.DhServerWorld;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_12_2
|
||||||
|
import net.minecraft.command.ICommandSender;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.util.text.TextComponentString;
|
||||||
|
import net.minecraft.world.WorldServer;
|
||||||
|
#else
|
||||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||||
import com.mojang.brigadier.context.CommandContext;
|
import com.mojang.brigadier.context.CommandContext;
|
||||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||||
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
|
|
||||||
import com.seibel.distanthorizons.core.generation.PregenManager;
|
|
||||||
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos2D;
|
|
||||||
import net.minecraft.commands.CommandSourceStack;
|
import net.minecraft.commands.CommandSourceStack;
|
||||||
import net.minecraft.commands.arguments.DimensionArgument;
|
import net.minecraft.commands.arguments.DimensionArgument;
|
||||||
import net.minecraft.commands.arguments.coordinates.ColumnPosArgument;
|
import net.minecraft.commands.arguments.coordinates.ColumnPosArgument;
|
||||||
import net.minecraft.server.level.ColumnPos;
|
import net.minecraft.server.level.ColumnPos;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
|
||||||
import java.util.concurrent.CancellationException;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
|
|
||||||
import static com.mojang.brigadier.arguments.IntegerArgumentType.getInteger;
|
import static com.mojang.brigadier.arguments.IntegerArgumentType.getInteger;
|
||||||
import static com.mojang.brigadier.arguments.IntegerArgumentType.integer;
|
import static com.mojang.brigadier.arguments.IntegerArgumentType.integer;
|
||||||
import static net.minecraft.commands.Commands.argument;
|
import static net.minecraft.commands.Commands.argument;
|
||||||
import static net.minecraft.commands.Commands.literal;
|
import static net.minecraft.commands.Commands.literal;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.CancellationException;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
|
||||||
public class PregenCommand extends AbstractCommand
|
public class PregenCommand extends AbstractCommand
|
||||||
{
|
{
|
||||||
private final PregenManager pregenManager = new PregenManager();
|
private PregenManager getPregenManager()
|
||||||
|
{
|
||||||
|
DhServerWorld world = (DhServerWorld) Objects.requireNonNull(SharedApi.getAbstractDhWorld());
|
||||||
|
return world.getPregenManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_12_2
|
||||||
|
public void execute(MinecraftServer server, ICommandSender sender, String[] args)
|
||||||
|
{
|
||||||
|
if (args.length < 2)
|
||||||
|
{
|
||||||
|
sender.sendMessage(new TextComponentString("Usage: /dh pregen <status|start|stop>"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (args[1])
|
||||||
|
{
|
||||||
|
case "status":
|
||||||
|
{
|
||||||
|
String statusString = this.getPregenManager().getStatusString();
|
||||||
|
sender.sendMessage(new TextComponentString(
|
||||||
|
statusString != null ? statusString : "Pregen is not running"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "start":
|
||||||
|
{
|
||||||
|
if (args.length < 5)
|
||||||
|
{
|
||||||
|
sender.sendMessage(new TextComponentString("Usage: /dh pregen start <dimension> <x> <z> <chunkRadius>"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
String dimensionName = args[2];
|
||||||
|
int x = Integer.parseInt(args[3]);
|
||||||
|
int z = Integer.parseInt(args[4]);
|
||||||
|
int chunkRadius = args.length >= 6 ? Integer.parseInt(args[5]) : 32;
|
||||||
|
|
||||||
|
// find the world by dimension name
|
||||||
|
WorldServer world = null;
|
||||||
|
for (WorldServer w : server.worlds)
|
||||||
|
{
|
||||||
|
if (w.provider.getDimensionType().getName().equals(dimensionName))
|
||||||
|
{
|
||||||
|
world = w;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (world == null)
|
||||||
|
{
|
||||||
|
sender.sendMessage(new TextComponentString("Unknown dimension: " + dimensionName));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sender.sendMessage(new TextComponentString("Starting pregen. Progress will be in the server console."));
|
||||||
|
|
||||||
|
final ICommandSender finalSender = sender;
|
||||||
|
CompletableFuture<Void> future = this.getPregenManager().startPregen(
|
||||||
|
ServerLevelWrapper.getWrapper(world),
|
||||||
|
new DhBlockPos2D(x, z),
|
||||||
|
chunkRadius
|
||||||
|
);
|
||||||
|
|
||||||
|
future.whenComplete((result, throwable) -> {
|
||||||
|
if (throwable instanceof CancellationException)
|
||||||
|
{
|
||||||
|
finalSender.sendMessage(new TextComponentString("Pregen is cancelled"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (throwable != null)
|
||||||
|
{
|
||||||
|
finalSender.sendMessage(new TextComponentString("Pregen failed: " + throwable.getMessage()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
finalSender.sendMessage(new TextComponentString("Pregen is complete"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (NumberFormatException e)
|
||||||
|
{
|
||||||
|
sender.sendMessage(new TextComponentString("Invalid number format"));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "stop":
|
||||||
|
{
|
||||||
|
CompletableFuture<Void> runningPregen = this.getPregenManager().getRunningPregen();
|
||||||
|
if (runningPregen == null)
|
||||||
|
{
|
||||||
|
sender.sendMessage(new TextComponentString("Pregen is not running"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
runningPregen.cancel(true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
sender.sendMessage(new TextComponentString("Unknown subcommand: " + args[1]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
@Override
|
@Override
|
||||||
public LiteralArgumentBuilder<CommandSourceStack> buildCommand()
|
public LiteralArgumentBuilder<CommandSourceStack> buildCommand()
|
||||||
{
|
{
|
||||||
@@ -48,7 +159,7 @@ public class PregenCommand extends AbstractCommand
|
|||||||
|
|
||||||
private int pregenStatus(CommandContext<CommandSourceStack> c)
|
private int pregenStatus(CommandContext<CommandSourceStack> c)
|
||||||
{
|
{
|
||||||
String statusString = this.pregenManager.getStatusString();
|
String statusString = this.getPregenManager().getStatusString();
|
||||||
//noinspection ReplaceNullCheck
|
//noinspection ReplaceNullCheck
|
||||||
if (statusString != null)
|
if (statusString != null)
|
||||||
{
|
{
|
||||||
@@ -68,7 +179,7 @@ public class PregenCommand extends AbstractCommand
|
|||||||
ColumnPos origin = ColumnPosArgument.getColumnPos(c, "origin");
|
ColumnPos origin = ColumnPosArgument.getColumnPos(c, "origin");
|
||||||
int chunkRadius = getInteger(c, "chunkRadius");
|
int chunkRadius = getInteger(c, "chunkRadius");
|
||||||
|
|
||||||
CompletableFuture<Void> future = this.pregenManager.startPregen(
|
CompletableFuture<Void> future = this.getPregenManager().startPregen(
|
||||||
ServerLevelWrapper.getWrapper(level),
|
ServerLevelWrapper.getWrapper(level),
|
||||||
new DhBlockPos2D(#if MC_VER >= MC_1_19_2 origin.x(), origin.z() #else origin.x, origin.z #endif),
|
new DhBlockPos2D(#if MC_VER >= MC_1_19_2 origin.x(), origin.z() #else origin.x, origin.z #endif),
|
||||||
chunkRadius
|
chunkRadius
|
||||||
@@ -94,7 +205,7 @@ public class PregenCommand extends AbstractCommand
|
|||||||
|
|
||||||
private int pregenStop(CommandContext<CommandSourceStack> c)
|
private int pregenStop(CommandContext<CommandSourceStack> c)
|
||||||
{
|
{
|
||||||
CompletableFuture<Void> runningPregen = this.pregenManager.getRunningPregen();
|
CompletableFuture<Void> runningPregen = this.getPregenManager().getRunningPregen();
|
||||||
if (runningPregen == null)
|
if (runningPregen == null)
|
||||||
{
|
{
|
||||||
return this.sendFailureResponse(c, "Pregen is not running");
|
return this.sendFailureResponse(c, "Pregen is not running");
|
||||||
@@ -103,5 +214,5 @@ public class PregenCommand extends AbstractCommand
|
|||||||
runningPregen.cancel(true);
|
runningPregen.cancel(true);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
+107
@@ -0,0 +1,107 @@
|
|||||||
|
package com.seibel.distanthorizons.common.commonMixins;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.api.enums.config.EDhApiUpdateBranch;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.gui.DhScreenUtil;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.gui.updater.UpdateModScreen;
|
||||||
|
import com.seibel.distanthorizons.core.config.Config;
|
||||||
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
|
import com.seibel.distanthorizons.core.jar.installer.GitlabGetter;
|
||||||
|
import com.seibel.distanthorizons.core.jar.installer.ModrinthGetter;
|
||||||
|
import com.seibel.distanthorizons.core.jar.updater.SelfUpdater;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import com.seibel.distanthorizons.core.render.RenderThreadTaskHandler;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
#if MC_VER <= MC_1_12_2
|
||||||
|
import net.minecraft.client.gui.GuiMainMenu;
|
||||||
|
#else
|
||||||
|
import net.minecraft.client.gui.screens.TitleScreen;
|
||||||
|
#endif
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class DhUpdateScreenBase
|
||||||
|
{
|
||||||
|
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_12_2
|
||||||
|
private static final Minecraft MC = Minecraft.getMinecraft();
|
||||||
|
#else
|
||||||
|
private static final Minecraft MC = Minecraft.getInstance();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public static void tryShowUpdateScreenAndRunAutoUpdateStartup(Runnable runnable)
|
||||||
|
{
|
||||||
|
// always needs to be called, otherwise auto update setup won't be completed
|
||||||
|
boolean newUpdateAvailable = SelfUpdater.onStart();
|
||||||
|
if (!newUpdateAvailable)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Config.Client.Advanced.AutoUpdater.enableAutoUpdater.get())
|
||||||
|
{
|
||||||
|
LOGGER.info("Auto update disabled, ignoring new version...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
runnable = () ->
|
||||||
|
{
|
||||||
|
String versionId;
|
||||||
|
EDhApiUpdateBranch updateBranch = EDhApiUpdateBranch.convertAutoToStableOrNightly(Config.Client.Advanced.AutoUpdater.updateBranch.get());
|
||||||
|
if (updateBranch == EDhApiUpdateBranch.STABLE)
|
||||||
|
{
|
||||||
|
versionId = ModrinthGetter.getLatestIDForVersion(SingletonInjector.INSTANCE.get(IVersionConstants.class).getMinecraftVersion());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ArrayList<com.electronwill.nightconfig.core.Config> pipelines = GitlabGetter.INSTANCE.projectPipelines;
|
||||||
|
if (pipelines != null
|
||||||
|
&& pipelines.size() > 0)
|
||||||
|
{
|
||||||
|
versionId = pipelines.get(0).get("sha");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
versionId = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (versionId == null)
|
||||||
|
{
|
||||||
|
LOGGER.info("Unable to find new DH update for the ["+updateBranch+"] branch. Assuming DH is up to date...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// running on the render thread is required since setting the MC screen may trigger
|
||||||
|
// before its allowed, silently failing
|
||||||
|
RenderThreadTaskHandler.INSTANCE.queueRunningOnRenderThread("Update Screen", () ->
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
#if MC_VER <= MC_1_12_2
|
||||||
|
DhScreenUtil.showScreen(new UpdateModScreen(
|
||||||
|
new TitleScreen(false),
|
||||||
|
versionId
|
||||||
|
));
|
||||||
|
#else
|
||||||
|
DhScreenUtil.setScreen(new UpdateModScreen(
|
||||||
|
new TitleScreen(false),
|
||||||
|
versionId
|
||||||
|
));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
// info instead of error since this can be ignored and probably just means
|
||||||
|
// there isn't a new DH version available
|
||||||
|
LOGGER.error("Unable to show DH update screen, reason: ["+e.getMessage()+"].");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
runnable.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+41
-12
@@ -4,17 +4,40 @@ import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
|||||||
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
|
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
|
||||||
import com.seibel.distanthorizons.core.api.internal.ServerApi;
|
import com.seibel.distanthorizons.core.api.internal.ServerApi;
|
||||||
import com.seibel.distanthorizons.core.api.internal.SharedApi;
|
import com.seibel.distanthorizons.core.api.internal.SharedApi;
|
||||||
|
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
|
||||||
|
#if MC_VER <= MC_1_12_2
|
||||||
|
import net.minecraft.world.WorldServer;
|
||||||
|
import net.minecraft.world.chunk.Chunk;
|
||||||
|
#else
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
|
import net.minecraft.world.level.chunk.ProtoChunk;
|
||||||
|
#endif
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
public class MixinChunkMapCommon
|
public class MixinChunkMapCommon
|
||||||
{
|
{
|
||||||
|
#if MC_VER <= MC_1_12_2
|
||||||
|
public static void onChunkSave(WorldServer level, Chunk chunk)
|
||||||
|
#else
|
||||||
public static void onChunkSave(ServerLevel level, ChunkAccess chunk, CallbackInfoReturnable<Boolean> ci)
|
public static void onChunkSave(ServerLevel level, ChunkAccess chunk, CallbackInfoReturnable<Boolean> ci)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
|
IServerLevelWrapper levelWrapper = ServerLevelWrapper.getWrapper(level);
|
||||||
|
|
||||||
|
int chunkPosX;
|
||||||
|
int chunkPosZ;
|
||||||
|
#if MC_VER <= MC_1_21_11
|
||||||
|
chunkPosX = chunk.getPos().x;
|
||||||
|
chunkPosZ = chunk.getPos().z;
|
||||||
|
#else
|
||||||
|
chunkPosX = chunk.getPos().x();
|
||||||
|
chunkPosZ = chunk.getPos().z();
|
||||||
|
#endif
|
||||||
|
|
||||||
// is this position already being updated?
|
// is this position already being updated?
|
||||||
if (SharedApi.isChunkAtChunkPosAlreadyUpdating(chunk.getPos().x, chunk.getPos().z))
|
if (SharedApi.isChunkAtChunkPosAlreadyUpdating(levelWrapper, chunkPosX, chunkPosZ))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -22,30 +45,31 @@ public class MixinChunkMapCommon
|
|||||||
|
|
||||||
|
|
||||||
// is this chunk being saved to disk?
|
// is this chunk being saved to disk?
|
||||||
boolean savingChunkToDisk = ci.getReturnValue();
|
boolean savingChunkToDisk = #if MC_VER <= MC_1_12_2 true #else ci.getReturnValue() #endif;
|
||||||
// true means a chunk was saved to disk
|
// true means a chunk was saved to disk
|
||||||
if (!savingChunkToDisk)
|
if (!savingChunkToDisk)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO are the following validations necessary since we are checking above if
|
|
||||||
// the callback return value should state if the chunk was actually saved or not?
|
|
||||||
// Do we trust it to always be correct?
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// corrupt/incomplete chunk validation //
|
// corrupt/incomplete chunk validation //
|
||||||
|
|
||||||
// MC has a tendency to try saving incomplete or corrupted chunks (which show up as empty or black chunks)
|
// MC has a tendency to try saving incomplete or corrupted chunks (which show up as empty or black chunks)
|
||||||
// this logic should prevent that from happening
|
// this logic should prevent that from happening
|
||||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
#if MC_VER <= MC_1_12_2
|
||||||
|
if (!chunk.isTerrainPopulated() || !chunk.isLightPopulated())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#elif MC_VER <= MC_1_17_1
|
||||||
if (chunk.isUnsaved() || chunk.getUpgradeData() != null || !chunk.isLightCorrect())
|
if (chunk.isUnsaved() || chunk.getUpgradeData() != null || !chunk.isLightCorrect())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (chunk.isUnsaved() || chunk.isUpgrading() || !chunk.isLightCorrect())
|
if (chunk.isUnsaved() || chunk.isUpgrading() || !chunk.isLightCorrect() || chunk instanceof ProtoChunk)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -56,7 +80,12 @@ public class MixinChunkMapCommon
|
|||||||
// biome validation //
|
// biome validation //
|
||||||
|
|
||||||
// some chunks may be missing their biomes, which cause issues when attempting to save them
|
// some chunks may be missing their biomes, which cause issues when attempting to save them
|
||||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
#if MC_VER <= MC_1_12_2
|
||||||
|
if (chunk. getBiomeArray() == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#elif MC_VER <= MC_1_17_1
|
||||||
if (chunk.getBiomes() == null)
|
if (chunk.getBiomes() == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -77,8 +106,8 @@ public class MixinChunkMapCommon
|
|||||||
|
|
||||||
// submit the update event
|
// submit the update event
|
||||||
ServerApi.INSTANCE.serverChunkSaveEvent(
|
ServerApi.INSTANCE.serverChunkSaveEvent(
|
||||||
new ChunkWrapper(chunk, ServerLevelWrapper.getWrapper(level)),
|
new ChunkWrapper(chunk, levelWrapper),
|
||||||
ServerLevelWrapper.getWrapper(level)
|
levelWrapper
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+127
@@ -0,0 +1,127 @@
|
|||||||
|
package com.seibel.distanthorizons.common.commonMixins;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftClientWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
||||||
|
import com.seibel.distanthorizons.core.config.Config;
|
||||||
|
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
|
||||||
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||||
|
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
#if MC_VER <= MC_1_12_2
|
||||||
|
#else
|
||||||
|
import net.minecraft.client.Camera;
|
||||||
|
import net.minecraft.world.effect.MobEffects;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_12_2
|
||||||
|
import net.minecraft.client.entity.EntityPlayerSP;
|
||||||
|
import net.minecraft.init.MobEffects;
|
||||||
|
#elif MC_VER < MC_1_17_1
|
||||||
|
import net.minecraft.world.level.material.FluidState;
|
||||||
|
import net.minecraft.client.renderer.FogRenderer;
|
||||||
|
import net.minecraft.client.renderer.FogRenderer.FogMode;
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
#elif MC_VER < MC_1_21_3
|
||||||
|
import net.minecraft.world.level.material.FogType;
|
||||||
|
import net.minecraft.client.renderer.FogRenderer;
|
||||||
|
import net.minecraft.client.renderer.FogRenderer.FogMode;
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
#elif MC_VER < MC_1_21_6
|
||||||
|
import net.minecraft.world.level.material.FogType;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
import com.mojang.blaze3d.shaders.FogShape;
|
||||||
|
import net.minecraft.client.renderer.FogRenderer;
|
||||||
|
import net.minecraft.client.renderer.FogRenderer.FogMode;
|
||||||
|
import net.minecraft.client.renderer.FogParameters;
|
||||||
|
import org.joml.Vector4f;
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
#else
|
||||||
|
import net.minecraft.world.level.material.FogType;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
public class MixinVanillaFogCommon
|
||||||
|
{
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_12_2
|
||||||
|
public static boolean cancelFog(int startCoords, Minecraft mc)
|
||||||
|
#elif MC_VER < MC_1_21_6
|
||||||
|
public static boolean cancelFog(Camera camera, FogRenderer.FogMode fogMode)
|
||||||
|
#else
|
||||||
|
public static boolean cancelFog()
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_12_2
|
||||||
|
EntityPlayerSP entity = mc.player;
|
||||||
|
#elif MC_VER < MC_1_21_6
|
||||||
|
Entity entity = camera.getEntity();
|
||||||
|
#elif MC_VER <= MC_1_21_10
|
||||||
|
Camera camera = Minecraft.getInstance().gameRenderer.getMainCamera();
|
||||||
|
Entity entity = camera.getEntity();
|
||||||
|
#elif MC_VER <= MC_26_1_2
|
||||||
|
Camera camera = Minecraft.getInstance().gameRenderer.getMainCamera();
|
||||||
|
Entity entity = camera.entity();
|
||||||
|
#else
|
||||||
|
Camera camera = Minecraft.getInstance().gameRenderer.mainCamera();
|
||||||
|
Entity entity = camera.entity();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_12_2
|
||||||
|
boolean cameraNotInFluid = cameraNotInFluid(mc);
|
||||||
|
#else
|
||||||
|
boolean cameraNotInFluid = cameraNotInFluid(camera);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_12_2
|
||||||
|
boolean isSpecialFog = entity.isPotionActive(MobEffects.BLINDNESS);
|
||||||
|
#else
|
||||||
|
boolean isSpecialFog = (entity instanceof LivingEntity) && ((LivingEntity) entity).hasEffect(MobEffects.BLINDNESS);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
boolean cancelFog = !isSpecialFog;
|
||||||
|
cancelFog = cancelFog && cameraNotInFluid;
|
||||||
|
#if MC_VER <= MC_1_12_2
|
||||||
|
cancelFog = cancelFog && startCoords == 0; // 0 = terrain fog
|
||||||
|
#elif MC_VER < MC_1_21_6
|
||||||
|
cancelFog = cancelFog && (fogMode == FogRenderer.FogMode.FOG_TERRAIN);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
cancelFog = cancelFog && !SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class).isFogStateSpecial();
|
||||||
|
cancelFog = cancelFog && !Config.Client.Advanced.Graphics.Fog.enableVanillaFog.get();
|
||||||
|
|
||||||
|
|
||||||
|
return cancelFog;
|
||||||
|
}
|
||||||
|
#if MC_VER <= MC_1_12_2
|
||||||
|
private static boolean cameraNotInFluid(Minecraft mc)
|
||||||
|
#else
|
||||||
|
private static boolean cameraNotInFluid(Camera camera)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
#if MC_VER <= MC_1_12_2
|
||||||
|
boolean cameraNotInFluid = mc.getRenderViewEntity() != null && !mc.world.getBlockState(mc.getRenderViewEntity().getPosition()).getMaterial().isLiquid();
|
||||||
|
#elif MC_VER < MC_1_17_1
|
||||||
|
FluidState fluidState = camera.getFluidInCamera();
|
||||||
|
boolean cameraNotInFluid = fluidState.isEmpty();
|
||||||
|
#else
|
||||||
|
FogType fogTypes = camera.getFluidInCamera();
|
||||||
|
boolean cameraNotInFluid = fogTypes == FogType.NONE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return cameraNotInFluid;
|
||||||
|
}
|
||||||
|
}
|
||||||
+313
@@ -0,0 +1,313 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Distant Horizons mod
|
||||||
|
* licensed under the GNU LGPL v3 License.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 James Seibel
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.distanthorizons.common.render.blaze;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_21_10
|
||||||
|
public class BlazeDebugWireframeRenderer {}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.buffers.GpuBuffer;
|
||||||
|
import com.mojang.blaze3d.buffers.GpuBufferSlice;
|
||||||
|
import com.mojang.blaze3d.pipeline.RenderPipeline;
|
||||||
|
import com.mojang.blaze3d.systems.CommandEncoder;
|
||||||
|
import com.mojang.blaze3d.systems.GpuDevice;
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.util.BlazeDhVertexFormatUtil;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.BlazeVertexFormatBuilder;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPassWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPipelineBuilderWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.uniform.BlazeUniformBufferWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import com.seibel.distanthorizons.core.render.EDhRenderDepth;
|
||||||
|
import com.seibel.distanthorizons.core.render.renderer.AbstractDebugWireframeRenderer;
|
||||||
|
import com.seibel.distanthorizons.core.util.math.Mat4f;
|
||||||
|
import com.seibel.distanthorizons.core.util.math.Vec3d;
|
||||||
|
import com.seibel.distanthorizons.core.util.math.Vec3f;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
|
||||||
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles rendering the wireframe particles
|
||||||
|
* that are used for seeing what the system's doing.
|
||||||
|
*/
|
||||||
|
public class BlazeDebugWireframeRenderer extends AbstractDebugWireframeRenderer
|
||||||
|
{
|
||||||
|
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
|
|
||||||
|
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
|
||||||
|
private static final AbstractDhRenderApiDefinition RENDER_API_DEF = SingletonInjector.INSTANCE.get(AbstractDhRenderApiDefinition.class);
|
||||||
|
|
||||||
|
public static BlazeDebugWireframeRenderer INSTANCE = new BlazeDebugWireframeRenderer();
|
||||||
|
|
||||||
|
/** A box from 0,0,0 to 1,1,1 */
|
||||||
|
private static final float[] BOX_VERTICES = {
|
||||||
|
//region
|
||||||
|
// Pos x y z
|
||||||
|
0, 0, 0,
|
||||||
|
1, 0, 0,
|
||||||
|
1, 1, 0,
|
||||||
|
0, 1, 0,
|
||||||
|
0, 0, 1,
|
||||||
|
1, 0, 1,
|
||||||
|
1, 1, 1,
|
||||||
|
0, 1, 1,
|
||||||
|
//endregion
|
||||||
|
};
|
||||||
|
|
||||||
|
private static final int[] BOX_OUTLINE_INDICES = {
|
||||||
|
//region
|
||||||
|
0, 1,
|
||||||
|
1, 2,
|
||||||
|
2, 3,
|
||||||
|
3, 0,
|
||||||
|
|
||||||
|
4, 5,
|
||||||
|
5, 6,
|
||||||
|
6, 7,
|
||||||
|
7, 4,
|
||||||
|
|
||||||
|
0, 4,
|
||||||
|
1, 5,
|
||||||
|
2, 6,
|
||||||
|
3, 7,
|
||||||
|
//endregion
|
||||||
|
};
|
||||||
|
|
||||||
|
private static final Mat4f TRANSFORM_MATRIX = new Mat4f();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// rendering setup
|
||||||
|
private boolean init = false;
|
||||||
|
|
||||||
|
private RenderPipeline pipeline;
|
||||||
|
|
||||||
|
private GpuBuffer boxVertexBuffer;
|
||||||
|
private GpuBuffer boxIndexBuffer;
|
||||||
|
|
||||||
|
private final BlazeUniformBufferWrapper uniformBufferWrapper = new BlazeUniformBufferWrapper("debugWireframeUniformBlock");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public BlazeDebugWireframeRenderer() { }
|
||||||
|
|
||||||
|
public void init()
|
||||||
|
{
|
||||||
|
if (this.init)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.init = true;
|
||||||
|
|
||||||
|
this.createPipelines();
|
||||||
|
this.createBuffers();
|
||||||
|
|
||||||
|
}
|
||||||
|
private void createPipelines()
|
||||||
|
{
|
||||||
|
RenderPipelineBuilderWrapper pipelineBuilder = new RenderPipelineBuilderWrapper();
|
||||||
|
{
|
||||||
|
pipelineBuilder.withFaceCulling(false);
|
||||||
|
pipelineBuilder.withDepthWrite(true);
|
||||||
|
if (RENDER_API_DEF.getRenderDepth() == EDhRenderDepth.FORWARD_Z)
|
||||||
|
{
|
||||||
|
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.LESS);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.GREATER);
|
||||||
|
}
|
||||||
|
pipelineBuilder.withColorWrite(true);
|
||||||
|
pipelineBuilder.withoutBlend();
|
||||||
|
pipelineBuilder.withPolygonMode(RenderPipelineBuilderWrapper.EDhPolygonMode.WIREFRAME);
|
||||||
|
pipelineBuilder.withName("debug_wireframe_renderer");
|
||||||
|
|
||||||
|
pipelineBuilder.withVertexShader("debug/blaze/vert");
|
||||||
|
pipelineBuilder.withFragmentShader("debug/blaze/frag");
|
||||||
|
|
||||||
|
pipelineBuilder.withUniformBuffer("uniformBlock");
|
||||||
|
|
||||||
|
|
||||||
|
VertexFormat vertexFormat = new BlazeVertexFormatBuilder()
|
||||||
|
.add("vPosition", BlazeDhVertexFormatUtil.FLOAT_XYZ_POS)
|
||||||
|
.build();
|
||||||
|
pipelineBuilder.withVertexFormat(vertexFormat);
|
||||||
|
pipelineBuilder.withVertexMode(RenderPipelineBuilderWrapper.EDhVertexMode.LINES);
|
||||||
|
}
|
||||||
|
this.pipeline = pipelineBuilder.build();
|
||||||
|
|
||||||
|
}
|
||||||
|
private void createBuffers()
|
||||||
|
{
|
||||||
|
GpuDevice GPU_DEVICE = RenderSystem.getDevice();
|
||||||
|
CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
|
||||||
|
|
||||||
|
|
||||||
|
// box vertices
|
||||||
|
ByteBuffer boxVerticesBuffer = MemoryUtil.memAlloc(BOX_VERTICES.length * Float.BYTES);
|
||||||
|
boxVerticesBuffer.asFloatBuffer().put(BOX_VERTICES);
|
||||||
|
boxVerticesBuffer.rewind();
|
||||||
|
MemoryUtil.memFree(boxVerticesBuffer);
|
||||||
|
|
||||||
|
// upload vertex data
|
||||||
|
{
|
||||||
|
int usage = GpuBuffer.USAGE_COPY_DST
|
||||||
|
| GpuBuffer.USAGE_VERTEX;
|
||||||
|
int size = BOX_VERTICES.length * Float.BYTES;
|
||||||
|
this.boxVertexBuffer = GPU_DEVICE.createBuffer(() -> "distantHorizons:DebugWireframeBox", usage, size);
|
||||||
|
|
||||||
|
{
|
||||||
|
int length = BOX_VERTICES.length * Float.BYTES;
|
||||||
|
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.boxVertexBuffer, /*offset*/ 0, length);
|
||||||
|
|
||||||
|
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(BOX_VERTICES.length * Float.BYTES);
|
||||||
|
byteBuffer.order(ByteOrder.nativeOrder());
|
||||||
|
byteBuffer.asFloatBuffer().put(BOX_VERTICES);
|
||||||
|
byteBuffer.rewind();
|
||||||
|
|
||||||
|
COMMAND_ENCODER.writeToBuffer(bufferSlice, byteBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// box vertex indexes
|
||||||
|
{
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocateDirect(BOX_OUTLINE_INDICES.length * Integer.BYTES);
|
||||||
|
buffer.order(ByteOrder.nativeOrder());
|
||||||
|
buffer.asIntBuffer().put(BOX_OUTLINE_INDICES);
|
||||||
|
buffer.rewind();
|
||||||
|
|
||||||
|
|
||||||
|
int usage = GpuBuffer.USAGE_COPY_DST
|
||||||
|
| GpuBuffer.USAGE_VERTEX
|
||||||
|
| GpuBuffer.USAGE_INDEX
|
||||||
|
| GpuBuffer.USAGE_UNIFORM;
|
||||||
|
this.boxIndexBuffer = GPU_DEVICE.createBuffer(() -> "DH Debug Index Buffer", usage, buffer.capacity());
|
||||||
|
|
||||||
|
int offset = 0;
|
||||||
|
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.boxIndexBuffer, offset, buffer.capacity());
|
||||||
|
COMMAND_ENCODER.writeToBuffer(bufferSlice, buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//===========//
|
||||||
|
// rendering //
|
||||||
|
//===========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderBox(Box box)
|
||||||
|
{
|
||||||
|
this.init();
|
||||||
|
|
||||||
|
//if (BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.isEmpty()
|
||||||
|
// || BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.isEmpty())
|
||||||
|
//{
|
||||||
|
// return;
|
||||||
|
//}
|
||||||
|
|
||||||
|
// shouldn't happen, but just in case
|
||||||
|
if (box == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// delayed getters since this class may be initialized before
|
||||||
|
// the GPU device has been set
|
||||||
|
GpuDevice gpuDevice = RenderSystem.getDevice();
|
||||||
|
CommandEncoder commandEncoder = gpuDevice.createCommandEncoder();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// uniforms
|
||||||
|
{
|
||||||
|
// create data //
|
||||||
|
Vec3d camPos = MC_RENDER.getCameraExactPosition();
|
||||||
|
Vec3f camPosFloatThisFrame = new Vec3f((float) camPos.x, (float) camPos.y, (float) camPos.z);
|
||||||
|
|
||||||
|
Mat4f boxTransform = Mat4f.createTranslateMatrix(
|
||||||
|
box.minPos.x - camPosFloatThisFrame.x,
|
||||||
|
box.minPos.y - camPosFloatThisFrame.y,
|
||||||
|
box.minPos.z - camPosFloatThisFrame.z);
|
||||||
|
boxTransform.multiply(Mat4f.createScaleMatrix(
|
||||||
|
box.maxPos.x - box.minPos.x,
|
||||||
|
box.maxPos.y - box.minPos.y,
|
||||||
|
box.maxPos.z - box.minPos.z));
|
||||||
|
|
||||||
|
TRANSFORM_MATRIX.set(this.dhMvmProjMatrixThisFrame);
|
||||||
|
TRANSFORM_MATRIX.multiply(boxTransform);
|
||||||
|
|
||||||
|
|
||||||
|
// upload data //
|
||||||
|
this.uniformBufferWrapper
|
||||||
|
.putMat4f(TRANSFORM_MATRIX) // uTransform
|
||||||
|
.putVec4f(
|
||||||
|
box.color.getRed() / 255.0f,
|
||||||
|
box.color.getGreen() / 255.0f,
|
||||||
|
box.color.getBlue() / 255.0f,
|
||||||
|
box.color.getAlpha() / 255.0f) // uColor
|
||||||
|
.finishAndUpload()
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// render //
|
||||||
|
|
||||||
|
try (RenderPassWrapper renderPassWrapper = new RenderPassWrapper(
|
||||||
|
this::getRenderPassName,
|
||||||
|
BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper,
|
||||||
|
BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper))
|
||||||
|
{
|
||||||
|
// Bind instance data //
|
||||||
|
renderPassWrapper.setUniform("uniformBlock", this.uniformBufferWrapper);
|
||||||
|
|
||||||
|
renderPassWrapper.setPipeline(this.pipeline);
|
||||||
|
renderPassWrapper.setIndexBuffer(this.boxIndexBuffer);
|
||||||
|
|
||||||
|
renderPassWrapper.setVertexBuffer(this.boxVertexBuffer);
|
||||||
|
|
||||||
|
renderPassWrapper.drawIndexed(BOX_OUTLINE_INDICES.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private String getRenderPassName() { return "distantHorizons:DebugRenderer"; }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+613
@@ -0,0 +1,613 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Distant Horizons mod
|
||||||
|
* licensed under the GNU LGPL v3 License.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 James Seibel
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.distanthorizons.common.render.blaze;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_21_10
|
||||||
|
public class BlazeDhGenericObjectRenderer {}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.pipeline.BlendFunction;
|
||||||
|
import com.mojang.blaze3d.pipeline.RenderPipeline;
|
||||||
|
import com.mojang.blaze3d.systems.CommandEncoder;
|
||||||
|
import com.mojang.blaze3d.systems.GpuDevice;
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||||
|
import com.seibel.distanthorizons.api.enums.rendering.EDhApiBlockMaterial;
|
||||||
|
import com.seibel.distanthorizons.api.interfaces.render.IDhApiCustomRenderRegister;
|
||||||
|
import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderableBoxGroup;
|
||||||
|
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeGenericObjectRenderEvent;
|
||||||
|
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeGenericRenderCleanupEvent;
|
||||||
|
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeGenericRenderSetupEvent;
|
||||||
|
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
|
||||||
|
import com.seibel.distanthorizons.api.objects.math.DhApiVec3d;
|
||||||
|
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox;
|
||||||
|
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBoxGroupShading;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.objects.BlazeGenericObjectVertexContainer;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.util.BlazeDhVertexFormatUtil;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.BlazeVertexFormatBuilder;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPassWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPipelineBuilderWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureViewWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.uniform.BlazeUniformBufferWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.misc.LightMapWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import com.seibel.distanthorizons.core.logging.f3.F3Screen;
|
||||||
|
import com.seibel.distanthorizons.core.render.EDhRenderDepth;
|
||||||
|
import com.seibel.distanthorizons.core.render.RenderParams;
|
||||||
|
import com.seibel.distanthorizons.core.render.RenderThreadTaskHandler;
|
||||||
|
import com.seibel.distanthorizons.core.render.renderer.GenericRenderObjectFactory;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IDhGenericObjectVertexBufferContainer;
|
||||||
|
import com.seibel.distanthorizons.core.render.renderer.RenderableBoxGroup;
|
||||||
|
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||||
|
import com.seibel.distanthorizons.core.util.math.Mat4f;
|
||||||
|
import com.seibel.distanthorizons.core.util.math.Vec3d;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IProfilerWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhGenericRenderer;
|
||||||
|
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
|
||||||
|
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles rendering generic groups of {@link DhApiRenderableBox}.
|
||||||
|
*
|
||||||
|
* @see IDhApiCustomRenderRegister
|
||||||
|
* @see DhApiRenderableBox
|
||||||
|
*/
|
||||||
|
public class BlazeDhGenericObjectRenderer implements IDhGenericRenderer
|
||||||
|
{
|
||||||
|
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
|
|
||||||
|
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
|
||||||
|
private static final AbstractDhRenderApiDefinition RENDER_API_DEF = SingletonInjector.INSTANCE.get(AbstractDhRenderApiDefinition.class);
|
||||||
|
|
||||||
|
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
|
||||||
|
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
|
||||||
|
|
||||||
|
private static final DhApiRenderableBoxGroupShading DEFAULT_SHADING = DhApiRenderableBoxGroupShading.getUnshaded();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Can be used to troubleshoot the renderer.
|
||||||
|
* If enabled several debug objects will render around (0,150,0).
|
||||||
|
*/
|
||||||
|
public static final boolean RENDER_DEBUG_OBJECTS = false;
|
||||||
|
|
||||||
|
private static final DhApiBeforeGenericObjectRenderEvent.EventParam EVENT_PARAM = new DhApiBeforeGenericObjectRenderEvent.EventParam();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private final ConcurrentHashMap<Long, RenderableBoxGroup> boxGroupById = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
|
||||||
|
// rendering setup
|
||||||
|
private boolean init = false;
|
||||||
|
|
||||||
|
private RenderPipeline pipeline;
|
||||||
|
|
||||||
|
private final BlazeUniformBufferWrapper vertUniformBufferWrapper = new BlazeUniformBufferWrapper("vertUniformBlock");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public BlazeDhGenericObjectRenderer() { }
|
||||||
|
|
||||||
|
public void init()
|
||||||
|
{
|
||||||
|
if (this.init)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.init = true;
|
||||||
|
|
||||||
|
this.createPipelines();
|
||||||
|
|
||||||
|
if (RENDER_DEBUG_OBJECTS)
|
||||||
|
{
|
||||||
|
this.addGenericDebugObjects();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void createPipelines()
|
||||||
|
{
|
||||||
|
RenderPipelineBuilderWrapper pipelineBuilder = new RenderPipelineBuilderWrapper();
|
||||||
|
{
|
||||||
|
pipelineBuilder.withFaceCulling(true);
|
||||||
|
pipelineBuilder.withDepthWrite(true);
|
||||||
|
if (RENDER_API_DEF.getRenderDepth() == EDhRenderDepth.FORWARD_Z)
|
||||||
|
{
|
||||||
|
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.LESS);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.GREATER);
|
||||||
|
}
|
||||||
|
pipelineBuilder.withBlend(BlendFunction.TRANSLUCENT); // TRANSLUCENT = new BlendFunction(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ONE_MINUS_SRC_ALPHA);
|
||||||
|
pipelineBuilder.withColorWrite(true);
|
||||||
|
pipelineBuilder.withPolygonMode(RenderPipelineBuilderWrapper.EDhPolygonMode.FILL);
|
||||||
|
pipelineBuilder.withName("generic_objects");
|
||||||
|
|
||||||
|
pipelineBuilder.withVertexShader("generic/blaze/vert");
|
||||||
|
pipelineBuilder.withFragmentShader("generic/blaze/frag");
|
||||||
|
|
||||||
|
pipelineBuilder.withSampler("uLightMap");
|
||||||
|
|
||||||
|
pipelineBuilder.withUniformBuffer("vertUniformBlock");
|
||||||
|
|
||||||
|
VertexFormat vertexFormat = new BlazeVertexFormatBuilder()
|
||||||
|
.add("vPosition", BlazeDhVertexFormatUtil.FLOAT_XYZ_POS)
|
||||||
|
.add("aColor", BlazeDhVertexFormatUtil.RGBA_UBYTE_COLOR)
|
||||||
|
.add("aMaterial", BlazeDhVertexFormatUtil.IRIS_MATERIAL)
|
||||||
|
|
||||||
|
.add("paddingOne", BlazeDhVertexFormatUtil.BYTE_PAD)
|
||||||
|
.add("paddingTwo", BlazeDhVertexFormatUtil.BYTE_PAD)
|
||||||
|
.add("paddingThree", BlazeDhVertexFormatUtil.BYTE_PAD)
|
||||||
|
.build();
|
||||||
|
pipelineBuilder.withVertexFormat(vertexFormat);
|
||||||
|
pipelineBuilder.withVertexMode(RenderPipelineBuilderWrapper.EDhVertexMode.TRIANGLES);
|
||||||
|
}
|
||||||
|
this.pipeline = pipelineBuilder.build();
|
||||||
|
}
|
||||||
|
private void addGenericDebugObjects()
|
||||||
|
{
|
||||||
|
GenericRenderObjectFactory factory = GenericRenderObjectFactory.INSTANCE;
|
||||||
|
|
||||||
|
|
||||||
|
// single giant box
|
||||||
|
IDhApiRenderableBoxGroup singleGiantBoxGroup = factory.createForSingleBox(
|
||||||
|
ModInfo.NAME + ":CyanChunkBox",
|
||||||
|
new DhApiRenderableBox(
|
||||||
|
new DhApiVec3d(0,0,0), new DhApiVec3d(16,190,16),
|
||||||
|
new Color(Color.CYAN.getRed(), Color.CYAN.getGreen(), Color.CYAN.getBlue(), 125),
|
||||||
|
EDhApiBlockMaterial.WATER)
|
||||||
|
);
|
||||||
|
singleGiantBoxGroup.setSkyLight(LodUtil.MAX_MC_LIGHT);
|
||||||
|
singleGiantBoxGroup.setBlockLight(LodUtil.MAX_MC_LIGHT);
|
||||||
|
this.add(singleGiantBoxGroup);
|
||||||
|
|
||||||
|
|
||||||
|
// single slender box
|
||||||
|
IDhApiRenderableBoxGroup singleTallBoxGroup = factory.createForSingleBox(
|
||||||
|
ModInfo.NAME + ":GreenBeacon",
|
||||||
|
new DhApiRenderableBox(
|
||||||
|
new DhApiVec3d(16,0,31), new DhApiVec3d(17,2000,32),
|
||||||
|
new Color(Color.GREEN.getRed(), Color.GREEN.getGreen(), Color.GREEN.getBlue(), 125),
|
||||||
|
EDhApiBlockMaterial.ILLUMINATED)
|
||||||
|
);
|
||||||
|
singleTallBoxGroup.setSkyLight(LodUtil.MAX_MC_LIGHT);
|
||||||
|
singleTallBoxGroup.setBlockLight(LodUtil.MAX_MC_LIGHT);
|
||||||
|
this.add(singleTallBoxGroup);
|
||||||
|
|
||||||
|
|
||||||
|
// absolute box group
|
||||||
|
ArrayList<DhApiRenderableBox> absBoxList = new ArrayList<>();
|
||||||
|
for (int i = 0; i < 18; i++)
|
||||||
|
{
|
||||||
|
absBoxList.add(new DhApiRenderableBox(
|
||||||
|
new DhApiVec3d(i,150+i,24), new DhApiVec3d(1+i,151+i,25),
|
||||||
|
new Color(Color.ORANGE.getRed(), Color.ORANGE.getGreen(), Color.ORANGE.getBlue()),
|
||||||
|
EDhApiBlockMaterial.LAVA
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
IDhApiRenderableBoxGroup absolutePosBoxGroup = factory.createAbsolutePositionedGroup(ModInfo.NAME + ":OrangeStairs", absBoxList);
|
||||||
|
this.add(absolutePosBoxGroup);
|
||||||
|
|
||||||
|
|
||||||
|
// relative box group
|
||||||
|
ArrayList<DhApiRenderableBox> relBoxList = new ArrayList<>();
|
||||||
|
for (int i = 0; i < 8; i+=2)
|
||||||
|
{
|
||||||
|
relBoxList.add(new DhApiRenderableBox(
|
||||||
|
new DhApiVec3d(0,i,0), new DhApiVec3d(1,1+i,1),
|
||||||
|
new Color(Color.MAGENTA.getRed(), Color.MAGENTA.getGreen(), Color.MAGENTA.getBlue()),
|
||||||
|
EDhApiBlockMaterial.METAL
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
IDhApiRenderableBoxGroup relativePosBoxGroup = factory.createRelativePositionedGroup(
|
||||||
|
ModInfo.NAME + ":MovingMagentaGroup",
|
||||||
|
new DhApiVec3d(24, 140, 24),
|
||||||
|
relBoxList);
|
||||||
|
relativePosBoxGroup.setPreRenderFunc((event) ->
|
||||||
|
{
|
||||||
|
DhApiVec3d pos = relativePosBoxGroup.getOriginBlockPos();
|
||||||
|
pos.x += event.partialTicks / 2;
|
||||||
|
pos.x %= 32;
|
||||||
|
relativePosBoxGroup.setOriginBlockPos(pos);
|
||||||
|
});
|
||||||
|
this.add(relativePosBoxGroup);
|
||||||
|
|
||||||
|
|
||||||
|
// massive relative box group
|
||||||
|
ArrayList<DhApiRenderableBox> massRelBoxList = new ArrayList<>();
|
||||||
|
for (int x = 0; x < 50*2; x+=2)
|
||||||
|
{
|
||||||
|
for (int z = 0; z < 50*2; z+=2)
|
||||||
|
{
|
||||||
|
massRelBoxList.add(new DhApiRenderableBox(
|
||||||
|
new DhApiVec3d(-x, 0, -z), new DhApiVec3d(1-x, 1, 1-z),
|
||||||
|
new Color(Color.RED.getRed(), Color.RED.getGreen(), Color.RED.getBlue()),
|
||||||
|
EDhApiBlockMaterial.TERRACOTTA
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IDhApiRenderableBoxGroup massRelativePosBoxGroup = factory.createRelativePositionedGroup(
|
||||||
|
ModInfo.NAME + ":MassRedGroup",
|
||||||
|
new DhApiVec3d(-25, 140, 0),
|
||||||
|
massRelBoxList);
|
||||||
|
massRelativePosBoxGroup.setPreRenderFunc((event) ->
|
||||||
|
{
|
||||||
|
DhApiVec3d blockPos = massRelativePosBoxGroup.getOriginBlockPos();
|
||||||
|
blockPos.y += event.partialTicks / 4;
|
||||||
|
if (blockPos.y > 150f)
|
||||||
|
{
|
||||||
|
blockPos.y = 140f;
|
||||||
|
|
||||||
|
Color newColor = (massRelativePosBoxGroup.get(0).color == Color.RED) ? Color.RED.darker() : Color.RED;
|
||||||
|
massRelativePosBoxGroup.forEach((box) -> { box.color = newColor; });
|
||||||
|
massRelativePosBoxGroup.triggerBoxChange();
|
||||||
|
}
|
||||||
|
|
||||||
|
massRelativePosBoxGroup.setOriginBlockPos(blockPos);
|
||||||
|
});
|
||||||
|
this.add(massRelativePosBoxGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//==============//
|
||||||
|
// registration //
|
||||||
|
//==============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void add(IDhApiRenderableBoxGroup iBoxGroup) throws IllegalArgumentException
|
||||||
|
{
|
||||||
|
if (!(iBoxGroup instanceof RenderableBoxGroup))
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("Box group must be of type ["+ RenderableBoxGroup.class.getSimpleName()+"], type received: ["+(iBoxGroup != null ? iBoxGroup.getClass() : "NULL")+"].");
|
||||||
|
}
|
||||||
|
RenderableBoxGroup boxGroup = (RenderableBoxGroup) iBoxGroup;
|
||||||
|
if (boxGroup.size() != 0)
|
||||||
|
{
|
||||||
|
// trigger a box change to make sure the initial data is uploaded
|
||||||
|
boxGroup.triggerBoxChange();
|
||||||
|
}
|
||||||
|
|
||||||
|
long id = boxGroup.getId();
|
||||||
|
if (this.boxGroupById.containsKey(id))
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("A box group with the ID [" + id + "] is already present.");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.boxGroupById.put(id, boxGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IDhApiRenderableBoxGroup remove(long id) { return this.boxGroupById.remove(id); }
|
||||||
|
|
||||||
|
public void clear() { this.boxGroupById.clear(); }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//===========//
|
||||||
|
// rendering //
|
||||||
|
//===========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param renderingWithSsao
|
||||||
|
* if true that means this render call is happening before the SSAO pass
|
||||||
|
* and any objects rendered in this pass will have SSAO applied to them.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void render(RenderParams renderEventParam, IProfilerWrapper profiler, boolean renderingWithSsao)
|
||||||
|
{
|
||||||
|
|
||||||
|
try (IProfilerWrapper.IProfileBlock generic_profile = profiler.push("setup"))
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
//==============//
|
||||||
|
// render setup //
|
||||||
|
//==============//
|
||||||
|
//#region
|
||||||
|
|
||||||
|
this.init();
|
||||||
|
|
||||||
|
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericRenderSetupEvent.class, renderEventParam.apiCopy);
|
||||||
|
|
||||||
|
Vec3d camPos = MC_RENDER.getCameraExactPosition();
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
if (BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.isEmpty()
|
||||||
|
|| BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.isEmpty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//===========//
|
||||||
|
// rendering //
|
||||||
|
//===========//
|
||||||
|
//#region
|
||||||
|
|
||||||
|
Collection<RenderableBoxGroup> boxList = this.boxGroupById.values();
|
||||||
|
for (RenderableBoxGroup boxGroup : boxList)
|
||||||
|
{
|
||||||
|
// validation //
|
||||||
|
|
||||||
|
// shouldn't happen, but just in case
|
||||||
|
if (boxGroup == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip boxes that shouldn't render this pass
|
||||||
|
if (boxGroup.ssaoEnabled != renderingWithSsao)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
profiler.popPush("render prep");
|
||||||
|
boxGroup.preRender(renderEventParam); // called even if the group is inactive, so the group can be activate if desired
|
||||||
|
|
||||||
|
// ignore inactive groups
|
||||||
|
if (!boxGroup.active)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// allow API users to cancel this object's rendering
|
||||||
|
EVENT_PARAM.update(renderEventParam, boxGroup);
|
||||||
|
boolean cancelRendering = ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericObjectRenderEvent.class, EVENT_PARAM);
|
||||||
|
if (cancelRendering)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update instanced data if needed
|
||||||
|
{
|
||||||
|
boxGroup.tryUpdateInstancedDataAsync();
|
||||||
|
|
||||||
|
// skip groups that haven't been uploaded yet
|
||||||
|
if (boxGroup.vertexBufferContainer.getState() != IDhGenericObjectVertexBufferContainer.EState.RENDER)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DhApiRenderableBoxGroupShading shading = boxGroup.shading;
|
||||||
|
if (shading == null)
|
||||||
|
{
|
||||||
|
shading = DEFAULT_SHADING;
|
||||||
|
}
|
||||||
|
|
||||||
|
// uniforms
|
||||||
|
{
|
||||||
|
// create data //
|
||||||
|
|
||||||
|
Mat4f projectionMvmMatrix = new Mat4f(renderEventParam.dhProjectionMatrix);
|
||||||
|
projectionMvmMatrix.multiply(renderEventParam.dhModelViewMatrix);
|
||||||
|
|
||||||
|
|
||||||
|
// upload data //
|
||||||
|
|
||||||
|
this.vertUniformBufferWrapper
|
||||||
|
.putVec3i(
|
||||||
|
LodUtil.getChunkPosFromDouble(boxGroup.getOriginBlockPos().x),
|
||||||
|
LodUtil.getChunkPosFromDouble(boxGroup.getOriginBlockPos().y),
|
||||||
|
LodUtil.getChunkPosFromDouble(boxGroup.getOriginBlockPos().z)
|
||||||
|
) // uOffsetChunk
|
||||||
|
.putVec3f(
|
||||||
|
LodUtil.getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().x),
|
||||||
|
LodUtil.getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().y),
|
||||||
|
LodUtil.getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().z)
|
||||||
|
) // uOffsetSubChunk
|
||||||
|
.putVec3i(
|
||||||
|
LodUtil.getChunkPosFromDouble(camPos.x),
|
||||||
|
LodUtil.getChunkPosFromDouble(camPos.y),
|
||||||
|
LodUtil.getChunkPosFromDouble(camPos.z)
|
||||||
|
) // uCameraPosChunk
|
||||||
|
.putVec3f(
|
||||||
|
LodUtil.getSubChunkPosFromDouble(camPos.x),
|
||||||
|
LodUtil.getSubChunkPosFromDouble(camPos.y),
|
||||||
|
LodUtil.getSubChunkPosFromDouble(camPos.z)
|
||||||
|
) // uCameraPosSubChunk
|
||||||
|
|
||||||
|
.putMat4f(projectionMvmMatrix) // uProjectionMvm
|
||||||
|
.putInt(boxGroup.getSkyLight()) // uSkyLight
|
||||||
|
.putInt(boxGroup.getBlockLight()) // uBlockLight
|
||||||
|
|
||||||
|
.putFloat(shading.north)
|
||||||
|
.putFloat(shading.south)
|
||||||
|
.putFloat(shading.east)
|
||||||
|
.putFloat(shading.west)
|
||||||
|
.putFloat(shading.top)
|
||||||
|
.putFloat(shading.bottom)
|
||||||
|
|
||||||
|
.finishAndUpload()
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// render //
|
||||||
|
|
||||||
|
profiler.popPush("rendering");
|
||||||
|
try (IProfilerWrapper.IProfileBlock namespace_profile = profiler.push(boxGroup.getResourceLocationNamespace());
|
||||||
|
IProfilerWrapper.IProfileBlock location_profile = profiler.push(boxGroup.getResourceLocationPath()))
|
||||||
|
{
|
||||||
|
this.renderBoxGroupInstanced(renderEventParam, boxGroup, profiler);
|
||||||
|
}
|
||||||
|
|
||||||
|
boxGroup.postRender(renderEventParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//==========//
|
||||||
|
// clean up //
|
||||||
|
//==========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
profiler.popPush("cleanup");
|
||||||
|
|
||||||
|
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericRenderCleanupEvent.class, renderEventParam);
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private String getRenderPassName() { return "distantHorizons:GenericObjectRenderer"; }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=====================//
|
||||||
|
// instanced rendering //
|
||||||
|
//=====================//
|
||||||
|
//region
|
||||||
|
|
||||||
|
private void renderBoxGroupInstanced(
|
||||||
|
RenderParams renderEventParam,
|
||||||
|
RenderableBoxGroup boxGroup,
|
||||||
|
IProfilerWrapper profiler)
|
||||||
|
{
|
||||||
|
try (RenderPassWrapper renderPassWrapper = new RenderPassWrapper(
|
||||||
|
this::getRenderPassName,
|
||||||
|
BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper,
|
||||||
|
BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper))
|
||||||
|
{
|
||||||
|
|
||||||
|
// update instance data //
|
||||||
|
|
||||||
|
BlazeGenericObjectVertexContainer container = (BlazeGenericObjectVertexContainer) boxGroup.vertexBufferContainer;
|
||||||
|
|
||||||
|
LightMapWrapper lightMapWrapper = (LightMapWrapper) renderEventParam.lightmap;
|
||||||
|
BlazeTextureViewWrapper lightmapTextureViewWrapper = lightMapWrapper.getTextureViewWrapper();
|
||||||
|
renderPassWrapper.bindTexture("uLightMap", lightmapTextureViewWrapper);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Bind instance data //
|
||||||
|
|
||||||
|
|
||||||
|
renderPassWrapper.setUniform("vertUniformBlock", this.vertUniformBufferWrapper);
|
||||||
|
|
||||||
|
// set pipeline
|
||||||
|
renderPassWrapper.setPipeline(this.pipeline);
|
||||||
|
renderPassWrapper.setIndexBuffer(container.indexGpuBuffer);
|
||||||
|
|
||||||
|
renderPassWrapper.setVertexBuffer(container.vboGpuBuffer);
|
||||||
|
|
||||||
|
// Draw instanced
|
||||||
|
if (container.uploadedBoxCount > 0)
|
||||||
|
{
|
||||||
|
// 36 = 6 faces * 6 verticies per face
|
||||||
|
renderPassWrapper.drawIndexed(container.uploadedBoxCount * 36);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=========//
|
||||||
|
// F3 menu //
|
||||||
|
//=========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public String getVboRenderDebugMenuString()
|
||||||
|
{
|
||||||
|
// get counts
|
||||||
|
int totalGroupCount = this.boxGroupById.size();
|
||||||
|
int totalBoxCount = 0;
|
||||||
|
|
||||||
|
int activeGroupCount = 0;
|
||||||
|
int activeBoxCount = 0;
|
||||||
|
|
||||||
|
for (long key : this.boxGroupById.keySet())
|
||||||
|
{
|
||||||
|
RenderableBoxGroup renderGroup = this.boxGroupById.get(key);
|
||||||
|
if (renderGroup.active)
|
||||||
|
{
|
||||||
|
activeGroupCount++;
|
||||||
|
activeBoxCount += renderGroup.size();
|
||||||
|
}
|
||||||
|
totalBoxCount += renderGroup.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return "Generic Obj #: " + F3Screen.NUMBER_FORMAT.format(activeGroupCount) + "/" + F3Screen.NUMBER_FORMAT.format(totalGroupCount) + ", " +
|
||||||
|
"Cube #: " + F3Screen.NUMBER_FORMAT.format(activeBoxCount) + "/" + F3Screen.NUMBER_FORMAT.format(totalBoxCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// base overrides //
|
||||||
|
//================//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close()
|
||||||
|
{
|
||||||
|
// close is called outside the render thread and buffer closing must be done on the render thread
|
||||||
|
RenderThreadTaskHandler.INSTANCE.queueRunningOnRenderThread("Generic Obj Cleanup", () ->
|
||||||
|
{
|
||||||
|
if (this.vertUniformBufferWrapper != null)
|
||||||
|
{
|
||||||
|
this.vertUniformBufferWrapper.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+122
@@ -0,0 +1,122 @@
|
|||||||
|
package com.seibel.distanthorizons.common.render.blaze;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_21_10
|
||||||
|
public class BlazeDhMetaRenderer {}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.textures.GpuTexture;
|
||||||
|
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiAfterColorDepthTextureCreatedEvent;
|
||||||
|
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiTextureCreatedParam;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.apply.BlazeDhApplyRenderer;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
|
import com.seibel.distanthorizons.core.render.RenderParams;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
|
||||||
|
import com.seibel.distanthorizons.coreapi.util.ColorUtil;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhMetaRenderer;
|
||||||
|
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
public class BlazeDhMetaRenderer implements IDhMetaRenderer
|
||||||
|
{
|
||||||
|
public static final BlazeDhMetaRenderer INSTANCE = new BlazeDhMetaRenderer();
|
||||||
|
|
||||||
|
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
|
||||||
|
|
||||||
|
|
||||||
|
private BlazeDhApplyRenderer applyRenderer;
|
||||||
|
private final float clearDepth;
|
||||||
|
|
||||||
|
public final BlazeTextureWrapper dhDepthTextureWrapper = BlazeTextureWrapper.createDepth("DhDepthTexture");
|
||||||
|
public final BlazeTextureWrapper dhColorTextureWrapper = BlazeTextureWrapper.createColor("DhColorTexture");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
private BlazeDhMetaRenderer()
|
||||||
|
{
|
||||||
|
AbstractDhRenderApiDefinition renderApiDefinition = SingletonInjector.INSTANCE.get(AbstractDhRenderApiDefinition.class);
|
||||||
|
this.clearDepth = renderApiDefinition.getRenderDepth().farDepth;
|
||||||
|
|
||||||
|
this.applyRenderer = new BlazeDhApplyRenderer(
|
||||||
|
"dh_apply_to_mc",
|
||||||
|
null,
|
||||||
|
"apply/blaze/vert", "apply/blaze/frag"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=================//
|
||||||
|
// pre/post render //
|
||||||
|
//=================//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void runRenderPassSetup(RenderParams renderParams)
|
||||||
|
{
|
||||||
|
int oldWidth = this.dhDepthTextureWrapper.getWidth();
|
||||||
|
int oldHeight = this.dhDepthTextureWrapper.getHeight();
|
||||||
|
|
||||||
|
boolean texturesChanged = false;
|
||||||
|
texturesChanged = this.dhDepthTextureWrapper.tryCreateOrResize() | texturesChanged;
|
||||||
|
texturesChanged = this.dhColorTextureWrapper.tryCreateOrResize() | texturesChanged;
|
||||||
|
|
||||||
|
if (texturesChanged)
|
||||||
|
{
|
||||||
|
int newTextureWidth = MC_RENDER.getTargetFramebufferViewportWidth();
|
||||||
|
int newTextureHeight = MC_RENDER.getTargetFramebufferViewportHeight();
|
||||||
|
|
||||||
|
DhApiTextureCreatedParam textureCreatedParam = new DhApiTextureCreatedParam(
|
||||||
|
oldWidth, oldHeight,
|
||||||
|
newTextureWidth, newTextureHeight
|
||||||
|
);
|
||||||
|
ApiEventInjector.INSTANCE.fireAllEvents(DhApiAfterColorDepthTextureCreatedEvent.class, textureCreatedParam);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void runRenderPassCleanup(RenderParams renderParams) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void applyToMcTexture(RenderParams renderParams)
|
||||||
|
{
|
||||||
|
GpuTexture mcColorTexture = MinecraftRenderWrapper.INSTANCE.getRenderTarget().getColorTexture();
|
||||||
|
this.applyRenderer.render(this.dhColorTextureWrapper.texture, this.dhDepthTextureWrapper.texture, mcColorTexture);
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// clear textures //
|
||||||
|
//================//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearDhDepthAndColorTextures(RenderParams renderParams)
|
||||||
|
{
|
||||||
|
this.dhDepthTextureWrapper.clearDepth(this.clearDepth);
|
||||||
|
|
||||||
|
Color color = MC_RENDER.getSkyColor();
|
||||||
|
this.dhColorTextureWrapper.clearColor(ColorUtil.toColorInt(color));
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+115
@@ -0,0 +1,115 @@
|
|||||||
|
package com.seibel.distanthorizons.common.render.blaze;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_21_10
|
||||||
|
public class BlazeDhRenderApiDefinition {}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderingApi;
|
||||||
|
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderingEngine;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.objects.BlazeGenericObjectVertexContainer;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.postProcessing.BlazeDhFarFadeRenderer;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.postProcessing.BlazeDhFogRenderer;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.postProcessing.BlazeDhSsaoRenderer;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.postProcessing.BlazeVanillaFadeRenderer;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.test.BlazeDhTestTriangleRenderer;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.buffer.BlazeVertexBufferWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.uniform.BlazeLodUniformBufferWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.render.EDhRenderDepth;
|
||||||
|
import com.seibel.distanthorizons.core.render.renderer.AbstractDebugWireframeRenderer;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IDhGenericObjectVertexBufferContainer;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.ILodContainerUniformBufferWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IVertexBufferWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.*;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_26_1_2
|
||||||
|
#else
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public class BlazeDhRenderApiDefinition extends AbstractDhRenderApiDefinition
|
||||||
|
{
|
||||||
|
//=========//
|
||||||
|
// getters //
|
||||||
|
//=========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
private final String apiName;
|
||||||
|
public String getApiName() { return this.apiName; }
|
||||||
|
|
||||||
|
public EDhRenderDepth getRenderDepth()
|
||||||
|
{
|
||||||
|
#if MC_VER <= MC_26_1_2
|
||||||
|
return EDhRenderDepth.FORWARD_Z;
|
||||||
|
#else
|
||||||
|
return EDhRenderDepth.REVERSE_Z;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private final EDhApiRenderingApi renderApi;
|
||||||
|
public EDhApiRenderingApi getRenderApi() { return renderApi; }
|
||||||
|
public boolean isNativeRenderer() { return false; }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public BlazeDhRenderApiDefinition()
|
||||||
|
{
|
||||||
|
#if MC_VER <= MC_26_1_2
|
||||||
|
renderApi = EDhApiRenderingApi.OPEN_GL;
|
||||||
|
#else
|
||||||
|
// use the same rendering API as Minecraft
|
||||||
|
this.renderApi = MinecraftRenderWrapper.INSTANCE.getMcRenderingApi();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
this.apiName = "Blaze3D: " + this.getRenderApi();
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//============//
|
||||||
|
// singletons //
|
||||||
|
//============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override public IDhMetaRenderer getMetaRenderer() { return BlazeDhMetaRenderer.INSTANCE; }
|
||||||
|
@Override public IDhTerrainRenderer getTerrainRenderer() { return BlazeDhTerrainRenderer.INSTANCE; }
|
||||||
|
@Override public IDhSsaoRenderer getSsaoRenderer() { return BlazeDhSsaoRenderer.INSTANCE; }
|
||||||
|
@Override public IDhFogRenderer getFogRenderer() { return BlazeDhFogRenderer.INSTANCE; }
|
||||||
|
@Override public IDhFarFadeRenderer getFarFadeRenderer() { return BlazeDhFarFadeRenderer.INSTANCE; }
|
||||||
|
@Override public AbstractDebugWireframeRenderer getDebugWireframeRenderer() { return BlazeDebugWireframeRenderer.INSTANCE; }
|
||||||
|
|
||||||
|
@Override public IDhVanillaFadeRenderer getVanillaFadeRenderer() { return BlazeVanillaFadeRenderer.INSTANCE; }
|
||||||
|
@Override public IDhTestTriangleRenderer getTestTriangleRenderer() { return BlazeDhTestTriangleRenderer.INSTANCE; }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//===========//
|
||||||
|
// factories //
|
||||||
|
//===========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override public IDhGenericRenderer createGenericRenderer() { return new BlazeDhGenericObjectRenderer(); }
|
||||||
|
|
||||||
|
@Override public IVertexBufferWrapper createVboWrapper(String name) { return new BlazeVertexBufferWrapper(name); }
|
||||||
|
@Override public ILodContainerUniformBufferWrapper createLodContainerUniformWrapper() { return new BlazeLodUniformBufferWrapper(); }
|
||||||
|
@Override public IDhGenericObjectVertexBufferContainer createGenericVboContainer() { return new BlazeGenericObjectVertexContainer(); }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+338
@@ -0,0 +1,338 @@
|
|||||||
|
package com.seibel.distanthorizons.common.render.blaze;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_21_10
|
||||||
|
public class BlazeDhTerrainRenderer {}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.pipeline.BlendFunction;
|
||||||
|
import com.mojang.blaze3d.pipeline.RenderPipeline;
|
||||||
|
import com.mojang.blaze3d.systems.CommandEncoder;
|
||||||
|
import com.mojang.blaze3d.systems.GpuDevice;
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||||
|
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeBufferRenderEvent;
|
||||||
|
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeRenderPassEvent;
|
||||||
|
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.util.BlazeDhVertexFormatUtil;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.BlazeVertexFormatBuilder;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPassWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPipelineBuilderWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureViewWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.uniform.BlazeLodUniformBufferWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.buffer.BlazeVertexBufferWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.uniform.BlazeUniformBufferWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.misc.LightMapWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.config.Config;
|
||||||
|
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodBufferContainer;
|
||||||
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import com.seibel.distanthorizons.core.pos.DhSectionPos;
|
||||||
|
import com.seibel.distanthorizons.core.render.EDhRenderDepth;
|
||||||
|
import com.seibel.distanthorizons.core.render.RenderParams;
|
||||||
|
import com.seibel.distanthorizons.core.util.RenderUtil;
|
||||||
|
import com.seibel.distanthorizons.core.util.math.Mat4f;
|
||||||
|
import com.seibel.distanthorizons.core.util.math.Vec3d;
|
||||||
|
import com.seibel.distanthorizons.core.util.math.Vec3f;
|
||||||
|
import com.seibel.distanthorizons.core.util.objects.SortedArraySet;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IProfilerWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhTerrainRenderer;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IVertexBufferWrapper;
|
||||||
|
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
|
||||||
|
|
||||||
|
/** Renders rendering DH's LOD terrain. */
|
||||||
|
public class BlazeDhTerrainRenderer implements IDhTerrainRenderer
|
||||||
|
{
|
||||||
|
public static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
|
|
||||||
|
private static final AbstractDhRenderApiDefinition RENDER_API_DEF = SingletonInjector.INSTANCE.get(AbstractDhRenderApiDefinition.class);
|
||||||
|
|
||||||
|
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
|
||||||
|
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
|
||||||
|
|
||||||
|
public static final BlazeDhTerrainRenderer INSTANCE = new BlazeDhTerrainRenderer();
|
||||||
|
|
||||||
|
private static final Vec3f MODEL_POS = new Vec3f();
|
||||||
|
/** single event object used to reduce GC pressure */
|
||||||
|
private static final DhApiBeforeBufferRenderEvent.EventParam BEFORE_BUFFER_RENDER_EVENT_PARAM = new DhApiBeforeBufferRenderEvent.EventParam();
|
||||||
|
|
||||||
|
|
||||||
|
private RenderPipeline opaquePipeline;
|
||||||
|
private RenderPipeline transparentPipeline;
|
||||||
|
private boolean init = false;
|
||||||
|
|
||||||
|
private final BlazeUniformBufferWrapper fragUniformBufferWrapper = new BlazeUniformBufferWrapper("fragUniformBlock");
|
||||||
|
private final BlazeUniformBufferWrapper vertSharedUniformBufferWrapper = new BlazeUniformBufferWrapper("vertSharedUniformBlock");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
private BlazeDhTerrainRenderer() { }
|
||||||
|
|
||||||
|
private void tryInit()
|
||||||
|
{
|
||||||
|
if (this.init)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
RenderPipelineBuilderWrapper opaquePipelineBuilder = new RenderPipelineBuilderWrapper();
|
||||||
|
RenderPipelineBuilderWrapper translucentPipelineBuilder = new RenderPipelineBuilderWrapper();
|
||||||
|
|
||||||
|
// apply shared options to both pipelines
|
||||||
|
for (int i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
RenderPipelineBuilderWrapper pipelineBuilder = (i == 0)
|
||||||
|
? opaquePipelineBuilder
|
||||||
|
: translucentPipelineBuilder;
|
||||||
|
|
||||||
|
pipelineBuilder.withFaceCulling(true);
|
||||||
|
pipelineBuilder.withDepthWrite(true);
|
||||||
|
if (RENDER_API_DEF.getRenderDepth() == EDhRenderDepth.FORWARD_Z)
|
||||||
|
{
|
||||||
|
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.LESS);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.GREATER);
|
||||||
|
}
|
||||||
|
pipelineBuilder.withColorWrite(true);
|
||||||
|
pipelineBuilder.withPolygonMode(RenderPipelineBuilderWrapper.EDhPolygonMode.FILL);
|
||||||
|
|
||||||
|
pipelineBuilder.withSampler("uLightMap");
|
||||||
|
|
||||||
|
pipelineBuilder.withVertexShader("lod/blaze/vert");
|
||||||
|
pipelineBuilder.withFragmentShader("lod/blaze/frag");
|
||||||
|
|
||||||
|
pipelineBuilder.withUniformBuffer("vertUniqueUniformBlock");
|
||||||
|
pipelineBuilder.withUniformBuffer("vertSharedUniformBlock");
|
||||||
|
pipelineBuilder.withUniformBuffer("fragUniformBlock");
|
||||||
|
|
||||||
|
VertexFormat vertexFormat = new BlazeVertexFormatBuilder()
|
||||||
|
.add("vPosition", BlazeDhVertexFormatUtil.SHORT_XYZ_POS)
|
||||||
|
.add("meta", BlazeDhVertexFormatUtil.META)
|
||||||
|
.add("vColor", BlazeDhVertexFormatUtil.RGBA_UBYTE_COLOR)
|
||||||
|
.add("irisMaterial", BlazeDhVertexFormatUtil.IRIS_MATERIAL)
|
||||||
|
.add("irisNormal", BlazeDhVertexFormatUtil.IRIS_NORMAL)
|
||||||
|
.add("paddingTwo", BlazeDhVertexFormatUtil.BYTE_PAD)
|
||||||
|
.add("paddingThree", BlazeDhVertexFormatUtil.BYTE_PAD) // padding is to make sure the format is a multiple of 4
|
||||||
|
.build();
|
||||||
|
pipelineBuilder.withVertexFormat(vertexFormat);
|
||||||
|
|
||||||
|
pipelineBuilder.withVertexMode(RenderPipelineBuilderWrapper.EDhVertexMode.TRIANGLES);
|
||||||
|
}
|
||||||
|
|
||||||
|
// opaque
|
||||||
|
{
|
||||||
|
opaquePipelineBuilder.withName("opaque_terrain");
|
||||||
|
opaquePipelineBuilder.withoutBlend();
|
||||||
|
this.opaquePipeline = opaquePipelineBuilder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
// transparent
|
||||||
|
{
|
||||||
|
translucentPipelineBuilder.withName("transparent_terrain");
|
||||||
|
// TRANSLUCENT = new BlendFunction(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ONE_MINUS_SRC_ALPHA);
|
||||||
|
translucentPipelineBuilder.withBlend(BlendFunction.TRANSLUCENT);
|
||||||
|
this.transparentPipeline = translucentPipelineBuilder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.init = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//========//
|
||||||
|
// render //
|
||||||
|
//========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(
|
||||||
|
RenderParams renderEventParam,
|
||||||
|
boolean opaquePass,
|
||||||
|
SortedArraySet<LodBufferContainer> bufferContainers,
|
||||||
|
IProfilerWrapper profiler)
|
||||||
|
{
|
||||||
|
this.tryInit();
|
||||||
|
|
||||||
|
try(IProfilerWrapper.IProfileBlock terrain_profile = profiler.push("terrain render"))
|
||||||
|
{
|
||||||
|
profiler.popPush("vert unique uniforms");
|
||||||
|
{
|
||||||
|
// create data //
|
||||||
|
|
||||||
|
for (int lodIndex = 0; lodIndex < bufferContainers.size(); lodIndex++)
|
||||||
|
{
|
||||||
|
LodBufferContainer bufferContainer = bufferContainers.get(lodIndex);
|
||||||
|
bufferContainer.uniformContainer.tryUpload(bufferContainer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
profiler.popPush("vert share uniforms");
|
||||||
|
{
|
||||||
|
Mat4f combinedMatrix = new Mat4f(renderEventParam.dhProjectionMatrix);
|
||||||
|
combinedMatrix.multiply(renderEventParam.dhModelViewMatrix);
|
||||||
|
|
||||||
|
float earthCurveRatio = Config.Client.Advanced.Graphics.Experimental.earthCurveRatio.get();
|
||||||
|
if (earthCurveRatio < -1.0f || earthCurveRatio > 1.0f)
|
||||||
|
{
|
||||||
|
earthCurveRatio = /*6371KM*/ 6371000.0f / earthCurveRatio;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// disable curvature if the config value is between -1 and 1
|
||||||
|
earthCurveRatio = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// upload data //
|
||||||
|
|
||||||
|
int i = Config.Client.Advanced.Debugging.enableWhiteWorld.get() ? 1 : 0;
|
||||||
|
|
||||||
|
this.vertSharedUniformBufferWrapper
|
||||||
|
.putInt(i) // uIsWhiteWorld
|
||||||
|
|
||||||
|
.putFloat((float) renderEventParam.worldYOffset) // uWorldYOffset
|
||||||
|
.putFloat(0.01f) // uMircoOffset // 0.01 block offset
|
||||||
|
.putFloat(earthCurveRatio) // uEarthRadius
|
||||||
|
|
||||||
|
.putVec3f(
|
||||||
|
(float) renderEventParam.exactCameraPosition.x,
|
||||||
|
(float) renderEventParam.exactCameraPosition.y,
|
||||||
|
(float) renderEventParam.exactCameraPosition.z) // uCameraPos
|
||||||
|
.putMat4f(combinedMatrix) // uCombinedMatrix
|
||||||
|
.finishAndUpload();
|
||||||
|
}
|
||||||
|
|
||||||
|
profiler.popPush("set frag uniforms");
|
||||||
|
{
|
||||||
|
// create data //
|
||||||
|
|
||||||
|
float dhNearClipDistance = RenderUtil.getNearClipPlaneInBlocks();
|
||||||
|
if (!Config.Client.Advanced.Debugging.lodOnlyMode.get())
|
||||||
|
{
|
||||||
|
// this added value prevents the near clip plane and discard circle from touching, which looks bad
|
||||||
|
dhNearClipDistance += 16f;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// upload data //
|
||||||
|
this.fragUniformBufferWrapper
|
||||||
|
.putFloat(dhNearClipDistance) // uClipDistance
|
||||||
|
.putFloat(Config.Client.Advanced.Graphics.NoiseTexture.noiseIntensity.get()) // uNoiseIntensity
|
||||||
|
.putInt(Config.Client.Advanced.Graphics.NoiseTexture.noiseSteps.get()) // uNoiseSteps
|
||||||
|
.putInt(Config.Client.Advanced.Graphics.NoiseTexture.noiseDropoff.get()) // uNoiseDropoff
|
||||||
|
.putInt(Config.Client.Advanced.Graphics.Quality.ditherDhFade.get() ? 1 : 0) // uDitherDhRendering
|
||||||
|
.putInt(Config.Client.Advanced.Graphics.NoiseTexture.enableNoiseTexture.get() ? 1 : 0) // uNoiseEnabled
|
||||||
|
.finishAndUpload()
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// render pass setup
|
||||||
|
{
|
||||||
|
profiler.popPush("rendering");
|
||||||
|
|
||||||
|
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeRenderPassEvent.class, renderEventParam.apiCopy);
|
||||||
|
|
||||||
|
// create a render pass
|
||||||
|
try (RenderPassWrapper renderPassWrapper = new RenderPassWrapper(
|
||||||
|
this::getRenderPassName,
|
||||||
|
BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper,
|
||||||
|
BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
LightMapWrapper lightMapWrapper = (LightMapWrapper) renderEventParam.lightmap;
|
||||||
|
BlazeTextureViewWrapper lightmapTextureViewWrapper = lightMapWrapper.getTextureViewWrapper();
|
||||||
|
renderPassWrapper.bindTexture("uLightMap", lightmapTextureViewWrapper);
|
||||||
|
|
||||||
|
// set pipeline
|
||||||
|
renderPassWrapper.setPipeline(opaquePass ? this.opaquePipeline : this.transparentPipeline);
|
||||||
|
|
||||||
|
// shared uniforms
|
||||||
|
renderPassWrapper.setUniform("fragUniformBlock", this.fragUniformBufferWrapper);
|
||||||
|
renderPassWrapper.setUniform("vertSharedUniformBlock", this.vertSharedUniformBufferWrapper);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
for (int lodIndex = 0; lodIndex < bufferContainers.size(); lodIndex++)
|
||||||
|
{
|
||||||
|
LodBufferContainer bufferContainer = bufferContainers.get(lodIndex);
|
||||||
|
BlazeLodUniformBufferWrapper uniformWrapper = (BlazeLodUniformBufferWrapper) bufferContainer.uniformContainer;
|
||||||
|
|
||||||
|
boolean columnBuilderDebugEnabled = Config.Client.Advanced.Debugging.ColumnBuilderDebugging.columnBuilderDebugEnable.get();
|
||||||
|
if (columnBuilderDebugEnabled)
|
||||||
|
{
|
||||||
|
if (DhSectionPos.getDetailLevel(bufferContainer.pos) == Config.Client.Advanced.Debugging.ColumnBuilderDebugging.columnBuilderDebugDetailLevel.get()
|
||||||
|
&& DhSectionPos.getX(bufferContainer.pos) == Config.Client.Advanced.Debugging.ColumnBuilderDebugging.columnBuilderDebugXPos.get()
|
||||||
|
&& DhSectionPos.getZ(bufferContainer.pos) == Config.Client.Advanced.Debugging.ColumnBuilderDebugging.columnBuilderDebugZPos.get())
|
||||||
|
{
|
||||||
|
int breakpoint = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderPassWrapper.setUniform("vertUniqueUniformBlock", uniformWrapper);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// render each buffer
|
||||||
|
IVertexBufferWrapper[] bufferWrapperList = opaquePass ? bufferContainer.vboOpaqueWrappers : bufferContainer.vboTransparentWrappers;
|
||||||
|
for (int i = 0; i < bufferWrapperList.length; i++)
|
||||||
|
{
|
||||||
|
BlazeVertexBufferWrapper bufferWrapper = (BlazeVertexBufferWrapper) bufferWrapperList[i];
|
||||||
|
if (!bufferWrapper.uploaded
|
||||||
|
|| bufferWrapper.vertexCount == 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fire render event
|
||||||
|
{
|
||||||
|
Vec3d camPos = renderEventParam.exactCameraPosition;
|
||||||
|
MODEL_POS.set(
|
||||||
|
(float) (bufferContainer.minCornerBlockPos.getX() - camPos.x),
|
||||||
|
(float) (bufferContainer.minCornerBlockPos.getY() - camPos.y),
|
||||||
|
(float) (bufferContainer.minCornerBlockPos.getZ() - camPos.z));
|
||||||
|
BEFORE_BUFFER_RENDER_EVENT_PARAM.update(renderEventParam, MODEL_POS);
|
||||||
|
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeBufferRenderEvent.class, BEFORE_BUFFER_RENDER_EVENT_PARAM);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderPassWrapper.setIndexBuffer(bufferWrapper.getIndexGpuBuffer());
|
||||||
|
renderPassWrapper.setVertexBuffer(bufferWrapper.vertexGpuBuffer);
|
||||||
|
|
||||||
|
if (!bufferWrapper.vertexGpuBuffer.isClosed())
|
||||||
|
{
|
||||||
|
renderPassWrapper.drawIndexed(bufferWrapper.indexCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private String getIndexBufferName() { return "distantHorizons:LodIndexBuffer"; }
|
||||||
|
private String getRenderPassName() { return "distantHorizons:TerrainRenderer"; }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+284
@@ -0,0 +1,284 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Distant Horizons mod
|
||||||
|
* licensed under the GNU LGPL v3 License.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 James Seibel
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.distanthorizons.common.render.blaze.apply;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_21_10
|
||||||
|
public class BlazeDhApplyRenderer {}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.buffers.GpuBuffer;
|
||||||
|
import com.mojang.blaze3d.pipeline.BlendFunction;
|
||||||
|
import com.mojang.blaze3d.pipeline.RenderPipeline;
|
||||||
|
import com.mojang.blaze3d.systems.CommandEncoder;
|
||||||
|
import com.mojang.blaze3d.systems.GpuDevice;
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
import com.mojang.blaze3d.textures.*;
|
||||||
|
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.util.BlazeDhVertexFormatUtil;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.BlazeVertexFormatBuilder;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPassWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPipelineBuilderWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureViewWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.util.BlazePostProcessUtil;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.uniform.BlazeUniformBufferWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import com.seibel.distanthorizons.core.render.EDhRenderDepth;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
|
||||||
|
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies the given color texture
|
||||||
|
* where the depth (or another attribute) is valid.
|
||||||
|
* Often used to apply post processing effects or
|
||||||
|
* the DH texture to MC's color texture. <br><br>
|
||||||
|
*
|
||||||
|
* @see BlazeDhCopyRenderer
|
||||||
|
*/
|
||||||
|
public class BlazeDhApplyRenderer
|
||||||
|
{
|
||||||
|
public static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
|
|
||||||
|
private static final AbstractDhRenderApiDefinition RENDER_API_DEF = SingletonInjector.INSTANCE.get(AbstractDhRenderApiDefinition.class);
|
||||||
|
|
||||||
|
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
|
||||||
|
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
|
||||||
|
|
||||||
|
private RenderPipeline pipeline;
|
||||||
|
|
||||||
|
private final BlazeUniformBufferWrapper fragUniformBufferWrapper = new BlazeUniformBufferWrapper("baseFragUniformBlock");
|
||||||
|
|
||||||
|
protected GpuBuffer vboGpuBuffer;
|
||||||
|
|
||||||
|
protected final String name;
|
||||||
|
protected final String identifierName;
|
||||||
|
public String getIdentifierName() { return this.identifierName; }
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private final BlendFunction blendFunction;
|
||||||
|
private final String vertexShaderPath;
|
||||||
|
private final String fragmentShaderPath;
|
||||||
|
|
||||||
|
private final BlazeTextureViewWrapper sourceColorTextureViewWrapper = new BlazeTextureViewWrapper();
|
||||||
|
private final BlazeTextureViewWrapper sourceDepthTextureViewWrapper = new BlazeTextureViewWrapper();
|
||||||
|
|
||||||
|
private final BlazeTextureViewWrapper destinationColorTextureViewWrapper = new BlazeTextureViewWrapper();
|
||||||
|
/** We don't want to actually write any depth data, but blaze3D complains if we don't bind a depth texture. */
|
||||||
|
private final BlazeTextureWrapper dummyDepthTextureWrapper = BlazeTextureWrapper.createDepth("apply_dummy_depth");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Can be set for special application shaders that need
|
||||||
|
* extra information. <br><br>
|
||||||
|
*
|
||||||
|
* will be an empty array if unneeded
|
||||||
|
*/
|
||||||
|
private final String[] uniformNames;
|
||||||
|
/** will be an empty array if unneeded */
|
||||||
|
private final BlazeUniformBufferWrapper[] uniformBufferWrappers;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
public BlazeDhApplyRenderer(
|
||||||
|
String name,
|
||||||
|
@Nullable BlendFunction blendFunction,
|
||||||
|
String vertexShaderPath, String fragmentShaderPath
|
||||||
|
)
|
||||||
|
{
|
||||||
|
this(
|
||||||
|
name,
|
||||||
|
blendFunction,
|
||||||
|
vertexShaderPath, fragmentShaderPath,
|
||||||
|
new String[0] // no extra uniforms
|
||||||
|
);
|
||||||
|
}
|
||||||
|
public BlazeDhApplyRenderer(
|
||||||
|
String name,
|
||||||
|
@Nullable BlendFunction blendFunction,
|
||||||
|
String vertexShaderPath, String fragmentShaderPath,
|
||||||
|
String[] uniformNames
|
||||||
|
)
|
||||||
|
{
|
||||||
|
this.name = name;
|
||||||
|
this.identifierName = "distanthorizons:"+this.name;
|
||||||
|
this.blendFunction = blendFunction;
|
||||||
|
|
||||||
|
this.vertexShaderPath = vertexShaderPath;
|
||||||
|
this.fragmentShaderPath = fragmentShaderPath;
|
||||||
|
|
||||||
|
this.uniformNames = uniformNames;
|
||||||
|
this.uniformBufferWrappers = new BlazeUniformBufferWrapper[this.uniformNames.length];
|
||||||
|
}
|
||||||
|
|
||||||
|
private void tryInit(
|
||||||
|
GpuTexture sourceColorTexture,
|
||||||
|
GpuTexture sourceDepthTexture,
|
||||||
|
GpuTexture destinationColorTexture)
|
||||||
|
{
|
||||||
|
// one-time setup
|
||||||
|
if (this.pipeline == null)
|
||||||
|
{
|
||||||
|
this.createPipeline();
|
||||||
|
this.vboGpuBuffer = BlazePostProcessUtil.createAndUploadScreenVertexData(this.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.sourceColorTextureViewWrapper.tryWrap(sourceColorTexture);
|
||||||
|
this.sourceDepthTextureViewWrapper.tryWrap(sourceDepthTexture);
|
||||||
|
|
||||||
|
this.destinationColorTextureViewWrapper.tryWrap(destinationColorTexture);
|
||||||
|
|
||||||
|
}
|
||||||
|
private void createPipeline()
|
||||||
|
{
|
||||||
|
RenderPipelineBuilderWrapper pipelineBuilder = new RenderPipelineBuilderWrapper();
|
||||||
|
{
|
||||||
|
pipelineBuilder.withFaceCulling(false);
|
||||||
|
pipelineBuilder.withDepthWrite(false);
|
||||||
|
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.NONE);
|
||||||
|
pipelineBuilder.withColorWrite(true);
|
||||||
|
|
||||||
|
if (this.blendFunction != null)
|
||||||
|
{
|
||||||
|
pipelineBuilder.withBlend(this.blendFunction);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pipelineBuilder.withoutBlend();
|
||||||
|
}
|
||||||
|
|
||||||
|
pipelineBuilder.withPolygonMode(RenderPipelineBuilderWrapper.EDhPolygonMode.FILL);
|
||||||
|
pipelineBuilder.withName(this.name);
|
||||||
|
|
||||||
|
pipelineBuilder.withVertexShader(this.vertexShaderPath);
|
||||||
|
pipelineBuilder.withFragmentShader(this.fragmentShaderPath);
|
||||||
|
|
||||||
|
for (int i = 0; i < this.uniformNames.length; i++)
|
||||||
|
{
|
||||||
|
String uniformName = this.uniformNames[i];
|
||||||
|
pipelineBuilder.withUniformBuffer(uniformName);
|
||||||
|
}
|
||||||
|
|
||||||
|
pipelineBuilder.withUniformBuffer("baseFragUniformBlock");
|
||||||
|
|
||||||
|
pipelineBuilder.withSampler("uSourceColorTexture");
|
||||||
|
pipelineBuilder.withSampler("uSourceDepthTexture");
|
||||||
|
|
||||||
|
VertexFormat vertexFormat = new BlazeVertexFormatBuilder()
|
||||||
|
.add("vPosition", BlazeDhVertexFormatUtil.SCREEN_POS)
|
||||||
|
.build();
|
||||||
|
pipelineBuilder.withVertexFormat(vertexFormat);
|
||||||
|
pipelineBuilder.withVertexMode(RenderPipelineBuilderWrapper.EDhVertexMode.TRIANGLE_FAN);
|
||||||
|
}
|
||||||
|
this.pipeline = pipelineBuilder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//========//
|
||||||
|
// render //
|
||||||
|
//========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public void setUniform(String uniformName, BlazeUniformBufferWrapper uniformBufferWrapper)
|
||||||
|
{
|
||||||
|
// the uniform array should be short enough (less than 10 items)
|
||||||
|
// where a sequential search should be plenty fast
|
||||||
|
for (int i = 0; i < this.uniformNames.length; i++)
|
||||||
|
{
|
||||||
|
String nameAtIndex = this.uniformNames[i];
|
||||||
|
if (nameAtIndex.equals(uniformName))
|
||||||
|
{
|
||||||
|
this.uniformBufferWrappers[i] = uniformBufferWrapper;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void render(
|
||||||
|
GpuTexture sourceColorTexture,
|
||||||
|
GpuTexture sourceDepthTexture,
|
||||||
|
GpuTexture destinationColorTexture)
|
||||||
|
{
|
||||||
|
this.tryInit(sourceColorTexture, sourceDepthTexture, destinationColorTexture);
|
||||||
|
|
||||||
|
this.dummyDepthTextureWrapper.tryCreateOrResize();
|
||||||
|
|
||||||
|
|
||||||
|
this.fragUniformBufferWrapper
|
||||||
|
.putInt((RENDER_API_DEF.getRenderDepth() == EDhRenderDepth.REVERSE_Z) ? 1 : 0) // uIsReverseZDepth
|
||||||
|
.finishAndUpload();
|
||||||
|
;
|
||||||
|
|
||||||
|
try (RenderPassWrapper renderPassWrapper = new RenderPassWrapper(
|
||||||
|
this::getIdentifierName,
|
||||||
|
this.destinationColorTextureViewWrapper,
|
||||||
|
this.dummyDepthTextureWrapper))
|
||||||
|
{
|
||||||
|
renderPassWrapper.bindTexture("uSourceColorTexture", this.sourceColorTextureViewWrapper);
|
||||||
|
renderPassWrapper.bindTexture("uSourceDepthTexture", this.sourceDepthTextureViewWrapper);
|
||||||
|
|
||||||
|
for (int i = 0; i < this.uniformNames.length; i++)
|
||||||
|
{
|
||||||
|
String uniformName = this.uniformNames[i];
|
||||||
|
BlazeUniformBufferWrapper uniformBuffer = this.uniformBufferWrappers[i];
|
||||||
|
if (uniformBuffer == null)
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("Missing uniform ["+uniformName+"], please set the uniform before rendering.");
|
||||||
|
}
|
||||||
|
|
||||||
|
renderPassWrapper.setUniform(uniformName, uniformBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderPassWrapper.setUniform("baseFragUniformBlock", this.fragUniformBufferWrapper);
|
||||||
|
|
||||||
|
renderPassWrapper.setVertexBuffer(this.vboGpuBuffer);
|
||||||
|
renderPassWrapper.setPipeline(this.pipeline);
|
||||||
|
|
||||||
|
renderPassWrapper.draw(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// clear the uniforms after rendering
|
||||||
|
// so we can check if they're missing during next frame's rendering
|
||||||
|
if (ModInfo.IS_DEV_BUILD)
|
||||||
|
{
|
||||||
|
Arrays.fill(this.uniformBufferWrappers, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+145
@@ -0,0 +1,145 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Distant Horizons mod
|
||||||
|
* licensed under the GNU LGPL v3 License.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 James Seibel
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.distanthorizons.common.render.blaze.apply;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_21_10
|
||||||
|
public class BlazeDhCopyRenderer {}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.buffers.GpuBuffer;
|
||||||
|
import com.mojang.blaze3d.pipeline.RenderPipeline;
|
||||||
|
import com.mojang.blaze3d.systems.CommandEncoder;
|
||||||
|
import com.mojang.blaze3d.systems.GpuDevice;
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPassWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPipelineBuilderWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureViewWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.util.BlazePostProcessUtil;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.IDhBlazeTexture;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blindly copies one texture into another.
|
||||||
|
*
|
||||||
|
* @see BlazeDhApplyRenderer
|
||||||
|
*/
|
||||||
|
public class BlazeDhCopyRenderer
|
||||||
|
{
|
||||||
|
public static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
|
|
||||||
|
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
|
||||||
|
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
|
||||||
|
|
||||||
|
public static final BlazeDhCopyRenderer INSTANCE = new BlazeDhCopyRenderer();
|
||||||
|
|
||||||
|
private RenderPipeline pipeline;
|
||||||
|
private boolean init = false;
|
||||||
|
|
||||||
|
private GpuBuffer vboGpuBuffer;
|
||||||
|
|
||||||
|
private BlazeTextureWrapper dummyDepthTextureWrapper;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
private BlazeDhCopyRenderer() { }
|
||||||
|
|
||||||
|
private void tryInit()
|
||||||
|
{
|
||||||
|
if (this.init)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.init = true;
|
||||||
|
|
||||||
|
|
||||||
|
this.dummyDepthTextureWrapper = BlazeTextureWrapper.createDepth("dh_copy_depth_texture");
|
||||||
|
|
||||||
|
RenderPipelineBuilderWrapper pipelineBuilder = new RenderPipelineBuilderWrapper();
|
||||||
|
{
|
||||||
|
pipelineBuilder.withFaceCulling(false);
|
||||||
|
pipelineBuilder.withDepthWrite(false);
|
||||||
|
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.NONE);
|
||||||
|
pipelineBuilder.withColorWrite(true);
|
||||||
|
pipelineBuilder.withoutBlend();
|
||||||
|
pipelineBuilder.withPolygonMode(RenderPipelineBuilderWrapper.EDhPolygonMode.FILL);
|
||||||
|
pipelineBuilder.withName("copy");
|
||||||
|
|
||||||
|
pipelineBuilder.withVertexShader("copy/blaze/vert");
|
||||||
|
pipelineBuilder.withFragmentShader("copy/blaze/frag");
|
||||||
|
|
||||||
|
pipelineBuilder.withSampler("uCopyTexture");
|
||||||
|
|
||||||
|
pipelineBuilder.withVertexFormat(BlazePostProcessUtil.createVertexFormat());
|
||||||
|
pipelineBuilder.withVertexMode(RenderPipelineBuilderWrapper.EDhVertexMode.TRIANGLE_FAN);
|
||||||
|
}
|
||||||
|
this.pipeline = pipelineBuilder.build();
|
||||||
|
|
||||||
|
|
||||||
|
this.vboGpuBuffer = BlazePostProcessUtil.createAndUploadScreenVertexData("CopyRenderer");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//========//
|
||||||
|
// render //
|
||||||
|
//========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public void render(
|
||||||
|
IDhBlazeTexture sourceColorTextureWrapper,
|
||||||
|
IDhBlazeTexture destinationColorTextureWrapper)
|
||||||
|
{
|
||||||
|
this.tryInit();
|
||||||
|
|
||||||
|
this.dummyDepthTextureWrapper.tryCreateOrResize();
|
||||||
|
|
||||||
|
try (RenderPassWrapper renderPassWrapper = new RenderPassWrapper(
|
||||||
|
this::getRenderPassName,
|
||||||
|
destinationColorTextureWrapper,
|
||||||
|
this.dummyDepthTextureWrapper))
|
||||||
|
{
|
||||||
|
renderPassWrapper.bindTexture("uCopyTexture", sourceColorTextureWrapper);
|
||||||
|
|
||||||
|
renderPassWrapper.setVertexBuffer(this.vboGpuBuffer); // vertex buffer can only be "0" lol
|
||||||
|
|
||||||
|
renderPassWrapper.setPipeline(this.pipeline);
|
||||||
|
renderPassWrapper.draw(4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getRenderPassName() { return "distantHorizons:CopyRenderer"; }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+299
@@ -0,0 +1,299 @@
|
|||||||
|
package com.seibel.distanthorizons.common.render.blaze.objects;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_21_10
|
||||||
|
public class BlazeGenericObjectVertexContainer {}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.buffers.GpuBuffer;
|
||||||
|
import com.mojang.blaze3d.buffers.GpuBufferSlice;
|
||||||
|
import com.mojang.blaze3d.systems.CommandEncoder;
|
||||||
|
import com.mojang.blaze3d.systems.GpuDevice;
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.enums.GLEnums;
|
||||||
|
import com.seibel.distanthorizons.core.render.RenderThreadTaskHandler;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IDhGenericObjectVertexBufferContainer;
|
||||||
|
import com.seibel.distanthorizons.core.render.renderer.RenderableBoxGroup;
|
||||||
|
import com.seibel.distanthorizons.coreapi.util.ColorUtil;
|
||||||
|
import org.lwjgl.opengl.GL32;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For use by {@link RenderableBoxGroup}
|
||||||
|
*
|
||||||
|
* @see RenderableBoxGroup
|
||||||
|
*/
|
||||||
|
public class BlazeGenericObjectVertexContainer implements IDhGenericObjectVertexBufferContainer
|
||||||
|
{
|
||||||
|
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
|
|
||||||
|
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
|
||||||
|
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
|
||||||
|
|
||||||
|
private static final int[] BOX_INDICES = {
|
||||||
|
//region
|
||||||
|
// min X, vertical face
|
||||||
|
2, 1, 0,
|
||||||
|
0, 3, 2,
|
||||||
|
// max X, vertical face
|
||||||
|
6, 5, 4,
|
||||||
|
4, 7, 6,
|
||||||
|
|
||||||
|
// min Z, vertical face
|
||||||
|
10, 9, 8,
|
||||||
|
8, 11, 10,
|
||||||
|
// max Z, vertical face
|
||||||
|
14, 13, 12,
|
||||||
|
12, 15, 14,
|
||||||
|
|
||||||
|
// min Y, horizontal face
|
||||||
|
18, 17, 16,
|
||||||
|
16, 19, 18,
|
||||||
|
// max Y, horizontal face
|
||||||
|
20, 21, 22,
|
||||||
|
22, 23, 20,
|
||||||
|
//endregion
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public GpuBuffer vboGpuBuffer;
|
||||||
|
public GpuBuffer indexGpuBuffer;
|
||||||
|
|
||||||
|
private ByteBuffer vertexBuffer = ByteBuffer.allocateDirect(0);
|
||||||
|
private ByteBuffer indexBuffer = ByteBuffer.allocateDirect(0);
|
||||||
|
|
||||||
|
public int uploadedBoxCount = 0;
|
||||||
|
|
||||||
|
private EState state = EState.NEW;
|
||||||
|
@Override
|
||||||
|
public IDhGenericObjectVertexBufferContainer.EState getState() { return this.state; }
|
||||||
|
@Override
|
||||||
|
public void setState(IDhGenericObjectVertexBufferContainer.EState state) { this.state = state; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//===========================//
|
||||||
|
// render building/uploading //
|
||||||
|
//===========================//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateVertexData(List<DhApiRenderableBox> uploadBoxList)
|
||||||
|
{
|
||||||
|
int boxCount = uploadBoxList.size();
|
||||||
|
|
||||||
|
// recreate the data arrays if their size is different
|
||||||
|
if (this.uploadedBoxCount != boxCount)
|
||||||
|
{
|
||||||
|
this.uploadedBoxCount = boxCount;
|
||||||
|
|
||||||
|
int vertexBufferSize = this.vertexBufferSize();
|
||||||
|
this.vertexBuffer = ByteBuffer.allocateDirect(vertexBufferSize);
|
||||||
|
this.vertexBuffer.order(ByteOrder.nativeOrder());
|
||||||
|
|
||||||
|
int indexBufferSize = this.indexBufferSize();
|
||||||
|
this.indexBuffer = ByteBuffer.allocateDirect(indexBufferSize);
|
||||||
|
this.indexBuffer.order(ByteOrder.nativeOrder());
|
||||||
|
}
|
||||||
|
this.vertexBuffer.position(0);
|
||||||
|
this.indexBuffer.position(0);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
for (int boxIndex = 0; boxIndex < boxCount; boxIndex++)
|
||||||
|
{
|
||||||
|
// index
|
||||||
|
int indexOffset = (boxIndex * 24 /*24 is the number of vertices in a box*/);
|
||||||
|
for (int i = 0; i < BOX_INDICES.length; i++)
|
||||||
|
{
|
||||||
|
this.indexBuffer.putInt(BOX_INDICES[i] + indexOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// vertex
|
||||||
|
DhApiRenderableBox box = uploadBoxList.get(boxIndex);
|
||||||
|
|
||||||
|
final double[] boxVertices =
|
||||||
|
{
|
||||||
|
//region
|
||||||
|
// Pos x y z
|
||||||
|
|
||||||
|
// min X, vertical face
|
||||||
|
box.minPos.x, box.minPos.y, box.minPos.z,
|
||||||
|
box.maxPos.x, box.minPos.y, box.minPos.z,
|
||||||
|
box.maxPos.x, box.maxPos.y, box.minPos.z,
|
||||||
|
box.minPos.x, box.maxPos.y, box.minPos.z,
|
||||||
|
// max X, vertical face
|
||||||
|
box.minPos.x, box.maxPos.y, box.maxPos.z,
|
||||||
|
box.maxPos.x, box.maxPos.y, box.maxPos.z,
|
||||||
|
box.maxPos.x, box.minPos.y, box.maxPos.z,
|
||||||
|
box.minPos.x, box.minPos.y, box.maxPos.z,
|
||||||
|
|
||||||
|
// min Z, vertical face
|
||||||
|
box.minPos.x, box.minPos.y, box.maxPos.z,
|
||||||
|
box.minPos.x, box.minPos.y, box.minPos.z,
|
||||||
|
box.minPos.x, box.maxPos.y, box.minPos.z,
|
||||||
|
box.minPos.x, box.maxPos.y, box.maxPos.z,
|
||||||
|
// max Z, vertical face
|
||||||
|
box.maxPos.x, box.minPos.y, box.maxPos.z,
|
||||||
|
box.maxPos.x, box.maxPos.y, box.maxPos.z,
|
||||||
|
box.maxPos.x, box.maxPos.y, box.minPos.z,
|
||||||
|
box.maxPos.x, box.minPos.y, box.minPos.z,
|
||||||
|
|
||||||
|
// min Y, horizontal face
|
||||||
|
box.minPos.x, box.minPos.y, box.maxPos.z,
|
||||||
|
box.maxPos.x, box.minPos.y, box.maxPos.z,
|
||||||
|
box.maxPos.x, box.minPos.y, box.minPos.z,
|
||||||
|
box.minPos.x, box.minPos.y, box.minPos.z,
|
||||||
|
// max Y, horizontal face
|
||||||
|
box.minPos.x, box.maxPos.y, box.maxPos.z,
|
||||||
|
box.maxPos.x, box.maxPos.y, box.maxPos.z,
|
||||||
|
box.maxPos.x, box.maxPos.y, box.minPos.z,
|
||||||
|
box.minPos.x, box.maxPos.y, box.minPos.z,
|
||||||
|
//endregion
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int vertexIndex = 0; vertexIndex < boxVertices.length; vertexIndex+=3)
|
||||||
|
{
|
||||||
|
this.vertexBuffer.putFloat((float)boxVertices[vertexIndex]); // x
|
||||||
|
this.vertexBuffer.putFloat((float)boxVertices[vertexIndex+1]); // y
|
||||||
|
this.vertexBuffer.putFloat((float)boxVertices[vertexIndex+2]); // z
|
||||||
|
|
||||||
|
int color = ColorUtil.toColorInt(box.color);
|
||||||
|
byte r = (byte) ColorUtil.getRed(color);
|
||||||
|
byte g = (byte) ColorUtil.getGreen(color);
|
||||||
|
byte b = (byte) ColorUtil.getBlue(color);
|
||||||
|
byte a = (byte) ColorUtil.getAlpha(color);
|
||||||
|
this.vertexBuffer.put(r);
|
||||||
|
this.vertexBuffer.put(g);
|
||||||
|
this.vertexBuffer.put(b);
|
||||||
|
this.vertexBuffer.put(a);
|
||||||
|
|
||||||
|
this.vertexBuffer.put(box.material);
|
||||||
|
|
||||||
|
// padding so the vertex format's byte count is a multiple of 4
|
||||||
|
this.vertexBuffer.put((byte)0);
|
||||||
|
this.vertexBuffer.put((byte)0);
|
||||||
|
this.vertexBuffer.put((byte)0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.vertexBuffer.flip();
|
||||||
|
this.indexBuffer.flip();
|
||||||
|
}
|
||||||
|
|
||||||
|
private int vertexBufferSize()
|
||||||
|
{
|
||||||
|
// minimum of 1 box to prevent trying to create a buffer of size 0
|
||||||
|
int boxCount = Math.max(this.uploadedBoxCount, 1);
|
||||||
|
|
||||||
|
int faceCount = boxCount * 6; // 6 faces on a cube
|
||||||
|
int vertexCount = faceCount * 6; // 6 vertices per cube
|
||||||
|
|
||||||
|
int byteSize = vertexCount * 3 * Float.BYTES; // x,y,z
|
||||||
|
byteSize += vertexCount * 4; // r,g,b,a
|
||||||
|
byteSize += 1; // material
|
||||||
|
return byteSize;
|
||||||
|
}
|
||||||
|
private int indexBufferSize()
|
||||||
|
{
|
||||||
|
// minimum of 1 box to prevent trying to create a buffer of size 0
|
||||||
|
int boxCount = Math.max(this.uploadedBoxCount, 1);
|
||||||
|
|
||||||
|
int quadCount = boxCount * 6 * 6; // 6 faces with 6 vertices each
|
||||||
|
int byteSize = quadCount * GLEnums.getTypeSize(GL32.GL_UNSIGNED_INT);
|
||||||
|
return byteSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void uploadDataToGpu()
|
||||||
|
{
|
||||||
|
// vertex
|
||||||
|
{
|
||||||
|
int totalVertexByteSize = this.vertexBufferSize();
|
||||||
|
if (this.vboGpuBuffer == null
|
||||||
|
// recreating if the size changes is always necessary (even if we only need a smaller amount)
|
||||||
|
// due to a bug on Mac where it will attempt to render anything allocated in the buffer
|
||||||
|
|| this.vboGpuBuffer.size() != totalVertexByteSize)
|
||||||
|
{
|
||||||
|
if (this.vboGpuBuffer != null)
|
||||||
|
{
|
||||||
|
this.vboGpuBuffer.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
int usage = GpuBuffer.USAGE_COPY_DST
|
||||||
|
| GpuBuffer.USAGE_VERTEX;
|
||||||
|
this.vboGpuBuffer = GPU_DEVICE.createBuffer(this::getVertexBufferName, usage, totalVertexByteSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.vboGpuBuffer, /*offset*/0, totalVertexByteSize);
|
||||||
|
COMMAND_ENCODER.writeToBuffer(bufferSlice, this.vertexBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// index
|
||||||
|
{
|
||||||
|
int totalVertexByteSize = this.indexBufferSize();
|
||||||
|
if (this.indexGpuBuffer == null
|
||||||
|
// recreating if the size changes is always necessary (even if we only need a smaller amount)
|
||||||
|
// due to a bug on Mac where it will attempt to render anything allocated in the buffer
|
||||||
|
|| this.indexGpuBuffer.size() != totalVertexByteSize)
|
||||||
|
{
|
||||||
|
if (this.indexGpuBuffer != null)
|
||||||
|
{
|
||||||
|
this.indexGpuBuffer.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
int usage = GpuBuffer.USAGE_COPY_DST
|
||||||
|
| GpuBuffer.USAGE_INDEX;
|
||||||
|
this.indexGpuBuffer = GPU_DEVICE.createBuffer(this::getIndexBufferName, usage, totalVertexByteSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
int offset = 0;
|
||||||
|
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.indexGpuBuffer, offset, totalVertexByteSize);
|
||||||
|
|
||||||
|
COMMAND_ENCODER.writeToBuffer(bufferSlice, this.indexBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private String getVertexBufferName() { return "distantHorizons:GenericVertexBuffer"; }
|
||||||
|
private String getIndexBufferName() { return "distantHorizons:GenericIndexBuffer"; }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// base overrides //
|
||||||
|
//================//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close()
|
||||||
|
{
|
||||||
|
RenderThreadTaskHandler.INSTANCE.queueRunningOnRenderThread("BlazeGenericObjectVertexContainer close", () ->
|
||||||
|
{
|
||||||
|
if (this.vboGpuBuffer != null)
|
||||||
|
{
|
||||||
|
this.vboGpuBuffer.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.indexGpuBuffer != null)
|
||||||
|
{
|
||||||
|
this.indexGpuBuffer.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+208
@@ -0,0 +1,208 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Distant Horizons mod
|
||||||
|
* licensed under the GNU LGPL v3 License.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 James Seibel
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.distanthorizons.common.render.blaze.postProcessing;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_21_10
|
||||||
|
public class BlazeDhFarFadeRenderer {}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.buffers.GpuBuffer;
|
||||||
|
import com.mojang.blaze3d.pipeline.RenderPipeline;
|
||||||
|
import com.mojang.blaze3d.systems.CommandEncoder;
|
||||||
|
import com.mojang.blaze3d.systems.GpuDevice;
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.BlazeDhMetaRenderer;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.apply.BlazeDhCopyRenderer;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.util.BlazePostProcessUtil;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPassWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPipelineBuilderWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureViewWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.uniform.BlazeUniformBufferWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import com.seibel.distanthorizons.core.render.EDhRenderDepth;
|
||||||
|
import com.seibel.distanthorizons.core.render.RenderParams;
|
||||||
|
import com.seibel.distanthorizons.core.util.RenderUtil;
|
||||||
|
import com.seibel.distanthorizons.core.util.math.Mat4f;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhFarFadeRenderer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fades out DH's far clip plane
|
||||||
|
*/
|
||||||
|
public class BlazeDhFarFadeRenderer implements IDhFarFadeRenderer
|
||||||
|
{
|
||||||
|
public static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
|
|
||||||
|
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
|
||||||
|
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
|
||||||
|
private static final AbstractDhRenderApiDefinition RENDER_API_DEF = SingletonInjector.INSTANCE.get(AbstractDhRenderApiDefinition.class);
|
||||||
|
|
||||||
|
public static final BlazeDhFarFadeRenderer INSTANCE = new BlazeDhFarFadeRenderer();
|
||||||
|
|
||||||
|
private RenderPipeline pipeline;
|
||||||
|
private boolean init = false;
|
||||||
|
|
||||||
|
private final BlazeUniformBufferWrapper fragUniformBufferWrapper = new BlazeUniformBufferWrapper("fragUniformBlock");
|
||||||
|
|
||||||
|
private GpuBuffer vboGpuBuffer;
|
||||||
|
|
||||||
|
private final BlazeTextureWrapper dhFadeColorTextureWrapper = BlazeTextureWrapper.createColor("dh_far_fade_color_texture");
|
||||||
|
/** We don't want to actually write any depth data, but blaze3D complains if we don't bind a depth texture. */
|
||||||
|
private final BlazeTextureWrapper dhFadeDepthTextureWrapper = BlazeTextureWrapper.createDepth("dh_far_fade_depth_texture");
|
||||||
|
|
||||||
|
private final BlazeTextureViewWrapper mcColorTextureViewWrapper = new BlazeTextureViewWrapper();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
private BlazeDhFarFadeRenderer() { }
|
||||||
|
|
||||||
|
private void tryInit()
|
||||||
|
{
|
||||||
|
if (this.init)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.init = true;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
RenderPipelineBuilderWrapper pipelineBuilder = new RenderPipelineBuilderWrapper();
|
||||||
|
{
|
||||||
|
pipelineBuilder.withFaceCulling(false);
|
||||||
|
pipelineBuilder.withDepthWrite(false);
|
||||||
|
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.NONE);
|
||||||
|
pipelineBuilder.withColorWrite(true);
|
||||||
|
pipelineBuilder.withoutBlend();
|
||||||
|
pipelineBuilder.withPolygonMode(RenderPipelineBuilderWrapper.EDhPolygonMode.FILL);
|
||||||
|
pipelineBuilder.withName("far_fade");
|
||||||
|
|
||||||
|
pipelineBuilder.withVertexShader("fade/blaze/vert");
|
||||||
|
pipelineBuilder.withFragmentShader("fade/blaze/dh_fade");
|
||||||
|
|
||||||
|
pipelineBuilder.withSampler("uMcColorTexture");
|
||||||
|
|
||||||
|
pipelineBuilder.withSampler("uDhDepthTexture");
|
||||||
|
pipelineBuilder.withSampler("uDhColorTexture");
|
||||||
|
|
||||||
|
pipelineBuilder.withUniformBuffer("fragUniformBlock");
|
||||||
|
|
||||||
|
pipelineBuilder.withVertexFormat(BlazePostProcessUtil.createVertexFormat());
|
||||||
|
pipelineBuilder.withVertexMode(RenderPipelineBuilderWrapper.EDhVertexMode.TRIANGLE_FAN);
|
||||||
|
}
|
||||||
|
this.pipeline = pipelineBuilder.build();
|
||||||
|
|
||||||
|
|
||||||
|
this.vboGpuBuffer = BlazePostProcessUtil.createAndUploadScreenVertexData("DhFarFadeRenderer");
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//========//
|
||||||
|
// render //
|
||||||
|
//========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(RenderParams renderParams)
|
||||||
|
{
|
||||||
|
this.tryInit();
|
||||||
|
|
||||||
|
|
||||||
|
if (BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.isEmpty()
|
||||||
|
|| BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.isEmpty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// textures
|
||||||
|
this.dhFadeColorTextureWrapper.tryCreateOrResize();
|
||||||
|
this.mcColorTextureViewWrapper.tryWrap(MinecraftRenderWrapper.INSTANCE.getRenderTarget().getColorTexture());
|
||||||
|
|
||||||
|
this.dhFadeDepthTextureWrapper.tryCreateOrResize();
|
||||||
|
|
||||||
|
{
|
||||||
|
// create data //
|
||||||
|
|
||||||
|
float dhFarClipDistance = RenderUtil.getFarClipPlaneDistanceInBlocks();
|
||||||
|
float fadeStartDistance = dhFarClipDistance * 0.5f;
|
||||||
|
float fadeEndDistance = dhFarClipDistance * 0.9f;
|
||||||
|
|
||||||
|
|
||||||
|
// upload data //
|
||||||
|
fragUniformBufferWrapper
|
||||||
|
.putFloat(fadeStartDistance) // uStartFadeBlockDistance
|
||||||
|
.putFloat(fadeEndDistance) // uEndFadeBlockDistance
|
||||||
|
.putMat4f(renderParams.dhInverseMvmProjectionMatrix) // uDhInvMvmProj
|
||||||
|
.putInt((RENDER_API_DEF.getRenderDepth() == EDhRenderDepth.REVERSE_Z) ? 1 : 0) // uIsReverseZDepth
|
||||||
|
.finishAndUpload()
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
this.renderFadeToTexture();
|
||||||
|
BlazeDhCopyRenderer.INSTANCE.render(this.dhFadeColorTextureWrapper, BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderFadeToTexture()
|
||||||
|
{
|
||||||
|
try (RenderPassWrapper renderPassWrapper = new RenderPassWrapper(
|
||||||
|
this::getRenderPassName,
|
||||||
|
this.dhFadeColorTextureWrapper,
|
||||||
|
this.dhFadeDepthTextureWrapper))
|
||||||
|
{
|
||||||
|
// MC texture
|
||||||
|
renderPassWrapper.bindTexture("uMcColorTexture", this.mcColorTextureViewWrapper);
|
||||||
|
|
||||||
|
// DH textures
|
||||||
|
renderPassWrapper.bindTexture("uDhDepthTexture", BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper);
|
||||||
|
renderPassWrapper.bindTexture("uDhColorTexture", BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper);
|
||||||
|
|
||||||
|
renderPassWrapper.setUniform("fragUniformBlock", this.fragUniformBufferWrapper);
|
||||||
|
|
||||||
|
renderPassWrapper.setVertexBuffer(this.vboGpuBuffer);
|
||||||
|
renderPassWrapper.setPipeline(this.pipeline);
|
||||||
|
|
||||||
|
renderPassWrapper.draw(4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private String getRenderPassName() { return "distantHorizons:DhFarFadeRenderer"; }
|
||||||
|
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+276
@@ -0,0 +1,276 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Distant Horizons mod
|
||||||
|
* licensed under the GNU LGPL v3 License.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 James Seibel
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.distanthorizons.common.render.blaze.postProcessing;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_21_10
|
||||||
|
public class BlazeDhFogRenderer {}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.api.enums.rendering.EDhApiHeightFogMixMode;
|
||||||
|
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiFogRenderParam;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.BlazeDhMetaRenderer;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.apply.BlazeDhApplyRenderer;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPassWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPipelineBuilderWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.util.BlazePostProcessUtil;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.uniform.BlazeUniformBufferWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.config.Config;
|
||||||
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import com.seibel.distanthorizons.core.render.EDhRenderDepth;
|
||||||
|
import com.seibel.distanthorizons.core.render.RenderParams;
|
||||||
|
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||||
|
import com.seibel.distanthorizons.core.util.math.Mat4f;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhFogRenderer;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.buffers.GpuBuffer;
|
||||||
|
import com.mojang.blaze3d.pipeline.BlendFunction;
|
||||||
|
import com.mojang.blaze3d.pipeline.RenderPipeline;
|
||||||
|
import com.mojang.blaze3d.systems.CommandEncoder;
|
||||||
|
import com.mojang.blaze3d.systems.GpuDevice;
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_26_1_2
|
||||||
|
import com.mojang.blaze3d.platform.DestFactor;
|
||||||
|
import com.mojang.blaze3d.platform.SourceFactor;
|
||||||
|
#else
|
||||||
|
import com.mojang.blaze3d.platform.BlendFactor;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders fog onto the LODs.
|
||||||
|
*/
|
||||||
|
public class BlazeDhFogRenderer implements IDhFogRenderer
|
||||||
|
{
|
||||||
|
public static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
|
|
||||||
|
private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
|
||||||
|
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
|
||||||
|
private static final AbstractDhRenderApiDefinition RENDER_API_DEF = SingletonInjector.INSTANCE.get(AbstractDhRenderApiDefinition.class);
|
||||||
|
|
||||||
|
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
|
||||||
|
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
|
||||||
|
|
||||||
|
public static final BlazeDhFogRenderer INSTANCE = new BlazeDhFogRenderer();
|
||||||
|
|
||||||
|
|
||||||
|
private BlazeDhApplyRenderer applyRenderer;
|
||||||
|
|
||||||
|
private RenderPipeline pipeline;
|
||||||
|
private boolean init = false;
|
||||||
|
|
||||||
|
private final BlazeUniformBufferWrapper fragUniformBufferWrapper = new BlazeUniformBufferWrapper("dh_fog_frag_uniform");
|
||||||
|
|
||||||
|
private GpuBuffer vboGpuBuffer;
|
||||||
|
|
||||||
|
private final BlazeTextureWrapper fogColorTextureWrapper = BlazeTextureWrapper.createColor("dh_fog_color_texture");
|
||||||
|
/** We don't want to actually write any depth data, but blaze3D complains if we don't bind a depth texture. */
|
||||||
|
private final BlazeTextureWrapper fogDepthTextureWrapper = BlazeTextureWrapper.createDepth("dh_fog_depth_texture");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
private BlazeDhFogRenderer() { }
|
||||||
|
|
||||||
|
private void tryInit()
|
||||||
|
{
|
||||||
|
if (this.init)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.init = true;
|
||||||
|
|
||||||
|
|
||||||
|
BlendFunction blendFunc;
|
||||||
|
#if MC_VER <= MC_26_1_2
|
||||||
|
blendFunc = new BlendFunction(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ONE_MINUS_SRC_ALPHA);
|
||||||
|
#else
|
||||||
|
blendFunc = new BlendFunction(BlendFactor.SRC_ALPHA, BlendFactor.ONE_MINUS_SRC_ALPHA, BlendFactor.ONE, BlendFactor.ONE_MINUS_SRC_ALPHA);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
this.applyRenderer = new BlazeDhApplyRenderer(
|
||||||
|
"fog_apply_to_dh",
|
||||||
|
blendFunc,
|
||||||
|
"apply/blaze/vert", "apply/blaze/frag"
|
||||||
|
);
|
||||||
|
|
||||||
|
RenderPipelineBuilderWrapper pipelineBuilder = new RenderPipelineBuilderWrapper();
|
||||||
|
{
|
||||||
|
pipelineBuilder.withFaceCulling(false);
|
||||||
|
pipelineBuilder.withDepthWrite(false);
|
||||||
|
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.NONE);
|
||||||
|
pipelineBuilder.withColorWrite(true);
|
||||||
|
pipelineBuilder.withoutBlend();
|
||||||
|
pipelineBuilder.withPolygonMode(RenderPipelineBuilderWrapper.EDhPolygonMode.FILL);
|
||||||
|
pipelineBuilder.withName("fog_render");
|
||||||
|
|
||||||
|
pipelineBuilder.withVertexShader("fog/blaze/vert");
|
||||||
|
pipelineBuilder.withFragmentShader("fog/blaze/frag");
|
||||||
|
|
||||||
|
pipelineBuilder.withSampler("uDhDepthTexture");
|
||||||
|
|
||||||
|
pipelineBuilder.withUniformBuffer("fragUniformBlock");
|
||||||
|
|
||||||
|
pipelineBuilder.withVertexFormat(BlazePostProcessUtil.createVertexFormat());
|
||||||
|
pipelineBuilder.withVertexMode(RenderPipelineBuilderWrapper.EDhVertexMode.TRIANGLE_FAN);
|
||||||
|
}
|
||||||
|
this.pipeline = pipelineBuilder.build();
|
||||||
|
|
||||||
|
|
||||||
|
this.vboGpuBuffer = BlazePostProcessUtil.createAndUploadScreenVertexData("FogRenderer");
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//========//
|
||||||
|
// render //
|
||||||
|
//========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(RenderParams renderParams, DhApiFogRenderParam fogRenderParams)
|
||||||
|
{
|
||||||
|
this.tryInit();
|
||||||
|
|
||||||
|
|
||||||
|
if (BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.isEmpty()
|
||||||
|
|| BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.isEmpty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
this.fogColorTextureWrapper.tryCreateOrResize();
|
||||||
|
this.fogDepthTextureWrapper.tryCreateOrResize();
|
||||||
|
|
||||||
|
{
|
||||||
|
// create data //
|
||||||
|
|
||||||
|
int lodDrawDistance = Config.Client.Advanced.Graphics.Quality.lodChunkRenderDistanceRadius.get() * LodUtil.CHUNK_WIDTH;
|
||||||
|
|
||||||
|
Mat4f inverseMvmProjMatrix = new Mat4f(renderParams.dhMvmProjMatrix);
|
||||||
|
inverseMvmProjMatrix.invert();
|
||||||
|
|
||||||
|
EDhApiHeightFogMixMode heightFogMixingMode = fogRenderParams.getHeightFogMixingMode();
|
||||||
|
boolean heightFogEnabled =
|
||||||
|
heightFogMixingMode != EDhApiHeightFogMixMode.SPHERICAL
|
||||||
|
&& heightFogMixingMode != EDhApiHeightFogMixMode.CYLINDRICAL;
|
||||||
|
boolean useSphericalFog = heightFogMixingMode == EDhApiHeightFogMixMode.SPHERICAL;
|
||||||
|
|
||||||
|
Color fogColor = fogRenderParams.getFogColor();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// upload data //
|
||||||
|
|
||||||
|
this.fragUniformBufferWrapper
|
||||||
|
// fog uniforms
|
||||||
|
.putVec4f(
|
||||||
|
fogColor.getRed() / 255.0f,
|
||||||
|
fogColor.getGreen() / 255.0f,
|
||||||
|
fogColor.getBlue() / 255.0f,
|
||||||
|
fogColor.getAlpha() / 255.0f) // uFogColor
|
||||||
|
.putFloat(1.f / lodDrawDistance) //uFogScale
|
||||||
|
.putFloat(1.f / MC.getWrappedClientLevel().getMaxHeight()) //uFogVerticalScale
|
||||||
|
.putInt(0) //uFogDebugMode // 0 = normal // 1 = render everything with fog color // 7 = use debug rendering
|
||||||
|
.putInt(fogRenderParams.getFarFogFalloff().value) //uFogFalloffType
|
||||||
|
|
||||||
|
// fog config
|
||||||
|
.putFloat(fogRenderParams.getFarFogStartPercent()) // uFarFogStart
|
||||||
|
.putFloat(fogRenderParams.getFarFogEndPercent() - fogRenderParams.getFarFogStartPercent()) // uFarFogLength
|
||||||
|
.putFloat(fogRenderParams.getFarFogMinThickness()) // uFarFogMin
|
||||||
|
.putFloat(fogRenderParams.getFarFogMaxThickness() - fogRenderParams.getFarFogMinThickness()) // uFarFogRange
|
||||||
|
.putFloat(fogRenderParams.getFarFogDensity()) // uFarFogDensity
|
||||||
|
|
||||||
|
// height fog config
|
||||||
|
.putFloat(fogRenderParams.getHeightFogStartPercent()) // uHeightFogStart
|
||||||
|
.putFloat(fogRenderParams.getHeightFogEndPercent() - fogRenderParams.getHeightFogStartPercent()) // uHeightFogLength
|
||||||
|
.putFloat(fogRenderParams.getHeightFogMinThickness()) // uHeightFogMin
|
||||||
|
.putFloat(fogRenderParams.getHeightFogMaxThickness() - fogRenderParams.getHeightFogMinThickness()) // uHeightFogRange
|
||||||
|
.putFloat(fogRenderParams.getHeightFogDensity()) // uHeightFogDensity
|
||||||
|
|
||||||
|
// ??
|
||||||
|
.putInt(heightFogEnabled ? 1 : 0) // uHeightFogEnabled
|
||||||
|
.putInt(fogRenderParams.getHeightFogFalloff().value) // uHeightFogFalloffType
|
||||||
|
.putInt(fogRenderParams.getHeightFogDirection().basedOnCamera ? 1 : 0) // uHeightBasedOnCamera
|
||||||
|
.putFloat(fogRenderParams.getHeightFogBaseHeight()) // uHeightFogBaseHeight
|
||||||
|
.putInt(fogRenderParams.getHeightFogDirection().fogAppliesUp ? 1 : 0) // uHeightFogAppliesUp
|
||||||
|
.putInt(fogRenderParams.getHeightFogDirection().fogAppliesDown ? 1 : 0) // uHeightFogAppliesDown
|
||||||
|
.putInt(useSphericalFog ? 1 : 0) // uUseSphericalFog
|
||||||
|
.putInt(heightFogMixingMode.value) // uHeightFogMixingMode
|
||||||
|
.putFloat((float)MC_RENDER.getCameraExactPosition().y) // uCameraBlockYPos
|
||||||
|
|
||||||
|
.putMat4f(inverseMvmProjMatrix) // uInvMvmProj
|
||||||
|
|
||||||
|
.putInt((RENDER_API_DEF.getRenderDepth() == EDhRenderDepth.REVERSE_Z) ? 1 : 0) // uIsReverseZDepth
|
||||||
|
|
||||||
|
.finishAndUpload()
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
this.renderFogToTexture();
|
||||||
|
this.applyRenderer.render(this.fogColorTextureWrapper.texture, BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.texture, BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.texture);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private void renderFogToTexture()
|
||||||
|
{
|
||||||
|
try (RenderPassWrapper renderPassWrapper = new RenderPassWrapper(
|
||||||
|
this::getRenderPassName,
|
||||||
|
this.fogColorTextureWrapper,
|
||||||
|
this.fogDepthTextureWrapper))
|
||||||
|
{
|
||||||
|
renderPassWrapper.bindTexture("uDhDepthTexture", BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper);
|
||||||
|
|
||||||
|
renderPassWrapper.setUniform("fragUniformBlock", this.fragUniformBufferWrapper);
|
||||||
|
|
||||||
|
renderPassWrapper.setVertexBuffer(this.vboGpuBuffer); // vertex buffer can only be "0" lol
|
||||||
|
renderPassWrapper.setPipeline(this.pipeline);
|
||||||
|
|
||||||
|
renderPassWrapper.draw(/*indexCount*/ 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private String getRenderPassName() { return "distantHorizons:FogRenderer"; }
|
||||||
|
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+253
@@ -0,0 +1,253 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Distant Horizons mod
|
||||||
|
* licensed under the GNU LGPL v3 License.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 James Seibel
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.distanthorizons.common.render.blaze.postProcessing;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_21_10
|
||||||
|
public class BlazeDhSsaoRenderer {}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.BlazeDhMetaRenderer;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.apply.BlazeDhApplyRenderer;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPassWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPipelineBuilderWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.util.BlazePostProcessUtil;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.uniform.BlazeUniformBufferWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import com.seibel.distanthorizons.core.render.EDhRenderDepth;
|
||||||
|
import com.seibel.distanthorizons.core.render.RenderParams;
|
||||||
|
import com.seibel.distanthorizons.core.util.RenderUtil;
|
||||||
|
import com.seibel.distanthorizons.core.util.math.Mat4f;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhSsaoRenderer;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.buffers.GpuBuffer;
|
||||||
|
import com.mojang.blaze3d.pipeline.BlendFunction;
|
||||||
|
import com.mojang.blaze3d.pipeline.RenderPipeline;
|
||||||
|
import com.mojang.blaze3d.systems.CommandEncoder;
|
||||||
|
import com.mojang.blaze3d.systems.GpuDevice;
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_26_1_2
|
||||||
|
import com.mojang.blaze3d.platform.DestFactor;
|
||||||
|
import com.mojang.blaze3d.platform.SourceFactor;
|
||||||
|
#else
|
||||||
|
import com.mojang.blaze3d.platform.BlendFactor;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Renders SSAO to the DH LODs. */
|
||||||
|
public class BlazeDhSsaoRenderer implements IDhSsaoRenderer
|
||||||
|
{
|
||||||
|
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
|
|
||||||
|
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
|
||||||
|
private static final AbstractDhRenderApiDefinition RENDER_API_DEF = SingletonInjector.INSTANCE.get(AbstractDhRenderApiDefinition.class);
|
||||||
|
|
||||||
|
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
|
||||||
|
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
|
||||||
|
|
||||||
|
public static final BlazeDhSsaoRenderer INSTANCE = new BlazeDhSsaoRenderer();
|
||||||
|
|
||||||
|
|
||||||
|
private BlazeDhApplyRenderer applyRenderer;
|
||||||
|
|
||||||
|
private RenderPipeline pipeline;
|
||||||
|
private boolean init = false;
|
||||||
|
|
||||||
|
private final BlazeUniformBufferWrapper fragUniformBufferWrapper = new BlazeUniformBufferWrapper("fragUniformBlock");
|
||||||
|
private final BlazeUniformBufferWrapper applyFragUniformBufferWrapper = new BlazeUniformBufferWrapper("applyFragUniformBlock");
|
||||||
|
|
||||||
|
private GpuBuffer vboGpuBuffer;
|
||||||
|
|
||||||
|
private final BlazeTextureWrapper ssaoColorTextureWrapper = BlazeTextureWrapper.createColor("dh_ssao_color_texture");
|
||||||
|
/** We don't want to actually write any depth data, but blaze3D complains if we don't bind a depth texture. */
|
||||||
|
private final BlazeTextureWrapper ssaoDepthTextureWrapper = BlazeTextureWrapper.createDepth("dh_ssao_depth_texture");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
private BlazeDhSsaoRenderer() { }
|
||||||
|
|
||||||
|
private void tryInit()
|
||||||
|
{
|
||||||
|
if (this.init)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.init = true;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
BlendFunction blendFunc;
|
||||||
|
#if MC_VER <= MC_26_1_2
|
||||||
|
blendFunc = new BlendFunction(SourceFactor.ZERO, DestFactor.SRC_ALPHA, SourceFactor.ZERO, DestFactor.ONE);
|
||||||
|
#else
|
||||||
|
blendFunc = new BlendFunction(BlendFactor.ZERO, BlendFactor.SRC_ALPHA, BlendFactor.ZERO, BlendFactor.ONE);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
this.applyRenderer = new BlazeDhApplyRenderer(
|
||||||
|
"ssao_apply_to_dh",
|
||||||
|
blendFunc,
|
||||||
|
"apply/blaze/vert", "ssao/blaze/apply",
|
||||||
|
/*uniforms*/ new String[] { "applyFragUniformBlock" }
|
||||||
|
);
|
||||||
|
|
||||||
|
RenderPipelineBuilderWrapper pipelineBuilder = new RenderPipelineBuilderWrapper();
|
||||||
|
{
|
||||||
|
pipelineBuilder.withFaceCulling(false);
|
||||||
|
pipelineBuilder.withDepthWrite(false);
|
||||||
|
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.NONE);
|
||||||
|
pipelineBuilder.withColorWrite(true);
|
||||||
|
pipelineBuilder.withoutBlend();
|
||||||
|
pipelineBuilder.withPolygonMode(RenderPipelineBuilderWrapper.EDhPolygonMode.FILL);
|
||||||
|
pipelineBuilder.withName("ssao_render");
|
||||||
|
|
||||||
|
pipelineBuilder.withVertexShader("ssao/blaze/vert");
|
||||||
|
pipelineBuilder.withFragmentShader("ssao/blaze/frag");
|
||||||
|
|
||||||
|
pipelineBuilder.withSampler("uDhDepthTexture");
|
||||||
|
|
||||||
|
pipelineBuilder.withUniformBuffer("fragUniformBlock");
|
||||||
|
|
||||||
|
pipelineBuilder.withVertexFormat(BlazePostProcessUtil.createVertexFormat());
|
||||||
|
pipelineBuilder.withVertexMode(RenderPipelineBuilderWrapper.EDhVertexMode.TRIANGLE_FAN);
|
||||||
|
}
|
||||||
|
this.pipeline = pipelineBuilder.build();
|
||||||
|
|
||||||
|
|
||||||
|
this.vboGpuBuffer = BlazePostProcessUtil.createAndUploadScreenVertexData("McSsao");
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//========//
|
||||||
|
// render //
|
||||||
|
//========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(RenderParams renderParams)
|
||||||
|
{
|
||||||
|
this.tryInit();
|
||||||
|
|
||||||
|
|
||||||
|
if (BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.isEmpty()
|
||||||
|
|| BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.isEmpty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// textures
|
||||||
|
this.ssaoColorTextureWrapper.tryCreateOrResize();
|
||||||
|
this.ssaoDepthTextureWrapper.tryCreateOrResize();
|
||||||
|
|
||||||
|
// frag uniforms
|
||||||
|
{
|
||||||
|
// create data //
|
||||||
|
Mat4f projMatrix = new Mat4f(renderParams.dhProjectionMatrix);
|
||||||
|
Mat4f invertedProjMatrix = new Mat4f(renderParams.dhProjectionMatrix);
|
||||||
|
invertedProjMatrix.invert();
|
||||||
|
|
||||||
|
|
||||||
|
// upload data //
|
||||||
|
this.fragUniformBufferWrapper
|
||||||
|
.putInt(6) // uSampleCount
|
||||||
|
|
||||||
|
.putFloat(4.0f) // uRadius
|
||||||
|
.putFloat(0.2f) // uStrength
|
||||||
|
.putFloat(0.25f) // uMinLight
|
||||||
|
.putFloat(0.02f) // uBias
|
||||||
|
.putFloat(1_600.0f) // uFadeDistanceInBlocks
|
||||||
|
|
||||||
|
.putMat4f(invertedProjMatrix)
|
||||||
|
.putMat4f(projMatrix)
|
||||||
|
|
||||||
|
.putInt((RENDER_API_DEF.getRenderDepth() == EDhRenderDepth.REVERSE_Z) ? 1 : 0) // uIsReverseZDepth
|
||||||
|
.finishAndUpload()
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
// apply frag uniforms
|
||||||
|
{
|
||||||
|
// create data //
|
||||||
|
|
||||||
|
float viewWidth = (float)MC_RENDER.getTargetFramebufferViewportWidth();
|
||||||
|
float viewHeight = (float)MC_RENDER.getTargetFramebufferViewportHeight();
|
||||||
|
|
||||||
|
float nearClipPlane = RenderUtil.getNearClipPlaneInBlocks();
|
||||||
|
float farClipPlane = RenderUtil.getFarClipPlaneDistanceInBlocks();
|
||||||
|
|
||||||
|
|
||||||
|
// upload data //
|
||||||
|
this.applyFragUniformBufferWrapper
|
||||||
|
.putVec2f(viewWidth, viewHeight) // uViewSize
|
||||||
|
.putInt(2) // uBlurRadius
|
||||||
|
.putFloat(nearClipPlane) // uNearClipPlane
|
||||||
|
.putFloat(farClipPlane) // uFarClipPlane
|
||||||
|
.finishAndUpload()
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
this.renderSsaoToTexture();
|
||||||
|
|
||||||
|
this.applyRenderer.setUniform("applyFragUniformBlock", this.applyFragUniformBufferWrapper);
|
||||||
|
this.applyRenderer.render(this.ssaoColorTextureWrapper.texture, BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.texture, BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.texture);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderSsaoToTexture()
|
||||||
|
{
|
||||||
|
try (RenderPassWrapper renderPassWrapper = new RenderPassWrapper(
|
||||||
|
this::getRenderPassName,
|
||||||
|
this.ssaoColorTextureWrapper,
|
||||||
|
this.ssaoDepthTextureWrapper))
|
||||||
|
{
|
||||||
|
renderPassWrapper.bindTexture("uDhDepthTexture", BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper);
|
||||||
|
|
||||||
|
renderPassWrapper.setUniform("fragUniformBlock", this.fragUniformBufferWrapper);
|
||||||
|
|
||||||
|
renderPassWrapper.setVertexBuffer(this.vboGpuBuffer);
|
||||||
|
|
||||||
|
renderPassWrapper.setPipeline(this.pipeline);
|
||||||
|
renderPassWrapper.draw(4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private String getRenderPassName() { return "distantHorizons:SsaoRenderer"; }
|
||||||
|
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+237
@@ -0,0 +1,237 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Distant Horizons mod
|
||||||
|
* licensed under the GNU LGPL v3 License.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 James Seibel
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.distanthorizons.common.render.blaze.postProcessing;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_21_10
|
||||||
|
public class BlazeVanillaFadeRenderer {}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.buffers.GpuBuffer;
|
||||||
|
import com.mojang.blaze3d.pipeline.RenderPipeline;
|
||||||
|
import com.mojang.blaze3d.systems.CommandEncoder;
|
||||||
|
import com.mojang.blaze3d.systems.GpuDevice;
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.BlazeDhMetaRenderer;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.apply.BlazeDhCopyRenderer;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.util.BlazePostProcessUtil;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPassWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPipelineBuilderWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureViewWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.uniform.BlazeUniformBufferWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.config.Config;
|
||||||
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import com.seibel.distanthorizons.core.render.EDhRenderDepth;
|
||||||
|
import com.seibel.distanthorizons.core.render.RenderParams;
|
||||||
|
import com.seibel.distanthorizons.core.util.RenderUtil;
|
||||||
|
import com.seibel.distanthorizons.core.util.math.Mat4f;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhVanillaFadeRenderer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fades the vanilla chunks
|
||||||
|
* into DH's LODs.
|
||||||
|
*/
|
||||||
|
public class BlazeVanillaFadeRenderer implements IDhVanillaFadeRenderer
|
||||||
|
{
|
||||||
|
public static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
|
|
||||||
|
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
|
||||||
|
private static final AbstractDhRenderApiDefinition RENDER_API_DEF = SingletonInjector.INSTANCE.get(AbstractDhRenderApiDefinition.class);
|
||||||
|
|
||||||
|
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
|
||||||
|
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
|
||||||
|
|
||||||
|
public static final BlazeVanillaFadeRenderer INSTANCE = new BlazeVanillaFadeRenderer();
|
||||||
|
|
||||||
|
|
||||||
|
private RenderPipeline pipeline;
|
||||||
|
private boolean init = false;
|
||||||
|
|
||||||
|
private final BlazeUniformBufferWrapper fragUniformBufferWrapper = new BlazeUniformBufferWrapper("fragUniformBlock");
|
||||||
|
|
||||||
|
private GpuBuffer vboGpuBuffer;
|
||||||
|
|
||||||
|
public final BlazeTextureWrapper fadeColorTextureWrapper = BlazeTextureWrapper.createColor("DhVanillaFadeColorTexture");
|
||||||
|
/** We don't want to actually write any depth data, but blaze3D complains if we don't bind a depth texture. */
|
||||||
|
private final BlazeTextureWrapper fadeDepthTextureWrapper = BlazeTextureWrapper.createDepth("DhVanillaFadeDepthTexture");
|
||||||
|
|
||||||
|
|
||||||
|
public final BlazeTextureViewWrapper mcDepthTextureWrapper = new BlazeTextureViewWrapper();
|
||||||
|
public final BlazeTextureViewWrapper mcColorTextureWrapper = new BlazeTextureViewWrapper();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
private BlazeVanillaFadeRenderer() { }
|
||||||
|
|
||||||
|
private void tryInit()
|
||||||
|
{
|
||||||
|
if (this.init)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.init = true;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
RenderPipelineBuilderWrapper pipelineBuilder = new RenderPipelineBuilderWrapper();
|
||||||
|
{
|
||||||
|
pipelineBuilder.withFaceCulling(false);
|
||||||
|
pipelineBuilder.withDepthWrite(false);
|
||||||
|
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.NONE);
|
||||||
|
pipelineBuilder.withColorWrite(true);
|
||||||
|
pipelineBuilder.withoutBlend();
|
||||||
|
pipelineBuilder.withPolygonMode(RenderPipelineBuilderWrapper.EDhPolygonMode.FILL);
|
||||||
|
pipelineBuilder.withName("vanilla_fade");
|
||||||
|
|
||||||
|
pipelineBuilder.withVertexShader("fade/blaze/vert");
|
||||||
|
pipelineBuilder.withFragmentShader("fade/blaze/vanilla_fade");
|
||||||
|
|
||||||
|
pipelineBuilder.withSampler("uMcDepthTexture");
|
||||||
|
pipelineBuilder.withSampler("uCombinedMcDhColorTexture");
|
||||||
|
|
||||||
|
pipelineBuilder.withSampler("uDhDepthTexture");
|
||||||
|
pipelineBuilder.withSampler("uDhColorTexture");
|
||||||
|
|
||||||
|
pipelineBuilder.withUniformBuffer("fragUniformBlock");
|
||||||
|
|
||||||
|
pipelineBuilder.withVertexFormat(BlazePostProcessUtil.createVertexFormat());
|
||||||
|
pipelineBuilder.withVertexMode(RenderPipelineBuilderWrapper.EDhVertexMode.TRIANGLE_FAN);
|
||||||
|
}
|
||||||
|
this.pipeline = pipelineBuilder.build();
|
||||||
|
|
||||||
|
|
||||||
|
this.vboGpuBuffer = BlazePostProcessUtil.createAndUploadScreenVertexData("VanillaFadeRenderer");
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//========//
|
||||||
|
// render //
|
||||||
|
//========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(RenderParams renderParams)
|
||||||
|
{
|
||||||
|
this.tryInit();
|
||||||
|
|
||||||
|
if (BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.isEmpty()
|
||||||
|
|| BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.isEmpty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// textures
|
||||||
|
this.fadeColorTextureWrapper.tryCreateOrResize();
|
||||||
|
this.fadeDepthTextureWrapper.tryCreateOrResize();
|
||||||
|
|
||||||
|
this.mcDepthTextureWrapper.tryWrap(MinecraftRenderWrapper.INSTANCE.getRenderTarget().getDepthTexture());
|
||||||
|
this.mcColorTextureWrapper.tryWrap(MinecraftRenderWrapper.INSTANCE.getRenderTarget().getColorTexture());
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
// create data //
|
||||||
|
|
||||||
|
float dhNearClipDistance = RenderUtil.getNearClipPlaneInBlocks();
|
||||||
|
// this added value prevents the near clip plane and discard circle from touching, which looks bad
|
||||||
|
dhNearClipDistance += 16f;
|
||||||
|
|
||||||
|
// measured in blocks
|
||||||
|
// these multipliers in James' tests should provide a fairly smooth transition
|
||||||
|
// without having underdraw issues
|
||||||
|
float fadeStartDistance = dhNearClipDistance * 1.5f;
|
||||||
|
float fadeEndDistance = dhNearClipDistance * 1.9f;
|
||||||
|
|
||||||
|
|
||||||
|
Mat4f inverseMcModelViewProjectionMatrix = new Mat4f(renderParams.mcProjectionMatrix);
|
||||||
|
inverseMcModelViewProjectionMatrix.multiply(renderParams.mcModelViewMatrix);
|
||||||
|
inverseMcModelViewProjectionMatrix.invert();
|
||||||
|
Mat4f inverseMcMvmProjMatrix = inverseMcModelViewProjectionMatrix;
|
||||||
|
|
||||||
|
|
||||||
|
Mat4f inverseDhModelViewProjectionMatrix = new Mat4f(renderParams.dhProjectionMatrix);
|
||||||
|
inverseDhModelViewProjectionMatrix.multiply(renderParams.dhModelViewMatrix);
|
||||||
|
inverseDhModelViewProjectionMatrix.invert();
|
||||||
|
Mat4f inverseDhMvmProjMatrix = inverseDhModelViewProjectionMatrix;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// upload data //
|
||||||
|
this.fragUniformBufferWrapper
|
||||||
|
.putInt(Config.Client.Advanced.Debugging.lodOnlyMode.get() ? 1 : 0) // uOnlyRenderLods
|
||||||
|
.putFloat(fadeStartDistance) // uStartFadeBlockDistance
|
||||||
|
.putFloat(fadeEndDistance) // uEndFadeBlockDistance
|
||||||
|
.putFloat(renderParams.clientLevelWrapper.getMaxHeight()) // uMaxLevelHeight
|
||||||
|
.putMat4f(inverseDhMvmProjMatrix) // uDhInvMvmProj
|
||||||
|
.putMat4f(inverseMcMvmProjMatrix) // uMcInvMvmProj
|
||||||
|
.putInt((RENDER_API_DEF.getRenderDepth() == EDhRenderDepth.REVERSE_Z) ? 1 : 0) // uIsReverseZDepth
|
||||||
|
.finishAndUpload()
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
this.renderFadeToTexture();
|
||||||
|
BlazeDhCopyRenderer.INSTANCE.render(this.fadeColorTextureWrapper, this.mcColorTextureWrapper);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderFadeToTexture()
|
||||||
|
{
|
||||||
|
try (RenderPassWrapper renderPassWrapper = new RenderPassWrapper(
|
||||||
|
this::getRenderPassName,
|
||||||
|
this.fadeColorTextureWrapper,
|
||||||
|
this.fadeDepthTextureWrapper))
|
||||||
|
{
|
||||||
|
renderPassWrapper.bindTexture("uMcDepthTexture", this.mcDepthTextureWrapper);
|
||||||
|
renderPassWrapper.bindTexture("uCombinedMcDhColorTexture", this.mcColorTextureWrapper);
|
||||||
|
|
||||||
|
renderPassWrapper.bindTexture("uDhDepthTexture", BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper);
|
||||||
|
renderPassWrapper.bindTexture("uDhColorTexture", BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper);
|
||||||
|
|
||||||
|
renderPassWrapper.setUniform("fragUniformBlock", this.fragUniformBufferWrapper);
|
||||||
|
|
||||||
|
renderPassWrapper.setVertexBuffer(this.vboGpuBuffer);
|
||||||
|
|
||||||
|
renderPassWrapper.setPipeline(this.pipeline);
|
||||||
|
renderPassWrapper.draw(/*indexCount*/ 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private String getRenderPassName() { return "distantHorizons:VanillaFadeRenderer"; }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+190
@@ -0,0 +1,190 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Distant Horizons mod
|
||||||
|
* licensed under the GNU LGPL v3 License.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 James Seibel
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.distanthorizons.common.render.blaze.test;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_21_10
|
||||||
|
public class BlazeDhTestTriangleRenderer {}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.buffers.GpuBuffer;
|
||||||
|
import com.mojang.blaze3d.buffers.GpuBufferSlice;
|
||||||
|
import com.mojang.blaze3d.pipeline.RenderPipeline;
|
||||||
|
import com.mojang.blaze3d.platform.PolygonMode;
|
||||||
|
import com.mojang.blaze3d.systems.CommandEncoder;
|
||||||
|
import com.mojang.blaze3d.systems.GpuDevice;
|
||||||
|
import com.mojang.blaze3d.systems.RenderPass;
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
import com.mojang.blaze3d.textures.*;
|
||||||
|
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.util.BlazeDhVertexFormatUtil;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.BlazeVertexFormatBuilder;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPassWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPipelineBuilderWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureViewWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import com.seibel.distanthorizons.core.render.RenderParams;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhTestTriangleRenderer;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.resources.Identifier;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
import java.util.OptionalDouble;
|
||||||
|
import java.util.OptionalInt;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_21_11
|
||||||
|
#else
|
||||||
|
import com.mojang.blaze3d.pipeline.DepthStencilState;
|
||||||
|
import com.mojang.blaze3d.platform.CompareOp;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the OpenGL/Vulkan triangle
|
||||||
|
* to the center of the screen to confirm DH's
|
||||||
|
* apply shader is running correctly
|
||||||
|
*/
|
||||||
|
public class BlazeDhTestTriangleRenderer implements IDhTestTriangleRenderer
|
||||||
|
{
|
||||||
|
public static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
|
|
||||||
|
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
|
||||||
|
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
|
||||||
|
|
||||||
|
public static final BlazeDhTestTriangleRenderer INSTANCE = new BlazeDhTestTriangleRenderer();
|
||||||
|
|
||||||
|
private RenderPipeline pipeline;
|
||||||
|
private boolean init = false;
|
||||||
|
|
||||||
|
public final BlazeTextureViewWrapper mcColorTextureViewWrapper = new BlazeTextureViewWrapper();
|
||||||
|
public final BlazeTextureViewWrapper mcDepthTextureViewWrapper = new BlazeTextureViewWrapper();
|
||||||
|
|
||||||
|
private GpuBuffer vboGpuBuffer;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
private BlazeDhTestTriangleRenderer() { }
|
||||||
|
|
||||||
|
private void tryInit()
|
||||||
|
{
|
||||||
|
if (this.init)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.init = true;
|
||||||
|
|
||||||
|
RenderPipelineBuilderWrapper pipelineBuilder = new RenderPipelineBuilderWrapper();
|
||||||
|
{
|
||||||
|
pipelineBuilder.withFaceCulling(false);
|
||||||
|
pipelineBuilder.withDepthWrite(false);
|
||||||
|
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.NONE);
|
||||||
|
pipelineBuilder.withColorWrite(true);
|
||||||
|
pipelineBuilder.withoutBlend();
|
||||||
|
pipelineBuilder.withName("triangle_test");
|
||||||
|
|
||||||
|
pipelineBuilder.withVertexShader("test/blaze/vert");
|
||||||
|
pipelineBuilder.withFragmentShader("test/blaze/frag");
|
||||||
|
|
||||||
|
VertexFormat vertexFormat = new BlazeVertexFormatBuilder()
|
||||||
|
.add("vPosition", BlazeDhVertexFormatUtil.SCREEN_POS)
|
||||||
|
.add("vColor", BlazeDhVertexFormatUtil.RGBA_FLOAT_COLOR)
|
||||||
|
.build();
|
||||||
|
pipelineBuilder.withVertexFormat(vertexFormat);
|
||||||
|
|
||||||
|
pipelineBuilder.withVertexMode(RenderPipelineBuilderWrapper.EDhVertexMode.TRIANGLES);
|
||||||
|
}
|
||||||
|
this.pipeline = pipelineBuilder.build();
|
||||||
|
|
||||||
|
this.uploadVertexData();
|
||||||
|
}
|
||||||
|
private void uploadVertexData()
|
||||||
|
{
|
||||||
|
// vertices for the OpenGL/Vulkan Triangle
|
||||||
|
float[] vertices = new float[]
|
||||||
|
{
|
||||||
|
// PosX,Y, ColorR,G,B,A
|
||||||
|
-0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f,
|
||||||
|
0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f,
|
||||||
|
0.0f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int usage = GpuBuffer.USAGE_COPY_DST
|
||||||
|
| GpuBuffer.USAGE_VERTEX;
|
||||||
|
int size = vertices.length * Float.BYTES;
|
||||||
|
this.vboGpuBuffer = GPU_DEVICE.createBuffer(this::getRenderPassName, usage, size);
|
||||||
|
|
||||||
|
{
|
||||||
|
int offset = 0;
|
||||||
|
int length = vertices.length * Float.BYTES;
|
||||||
|
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.vboGpuBuffer, offset, length);
|
||||||
|
|
||||||
|
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(vertices.length * Float.BYTES);
|
||||||
|
// Fill buffer with vertices.
|
||||||
|
byteBuffer.order(ByteOrder.nativeOrder());
|
||||||
|
byteBuffer.asFloatBuffer().put(vertices);
|
||||||
|
byteBuffer.rewind();
|
||||||
|
|
||||||
|
COMMAND_ENCODER.writeToBuffer(bufferSlice, byteBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//========//
|
||||||
|
// render //
|
||||||
|
//========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(RenderParams renderParams)
|
||||||
|
{
|
||||||
|
this.tryInit();
|
||||||
|
|
||||||
|
this.mcColorTextureViewWrapper.tryWrap(MinecraftRenderWrapper.INSTANCE.getRenderTarget().getColorTexture());
|
||||||
|
this.mcDepthTextureViewWrapper.tryWrap(MinecraftRenderWrapper.INSTANCE.getRenderTarget().getDepthTexture());
|
||||||
|
|
||||||
|
try (RenderPassWrapper renderPassWrapper = new RenderPassWrapper(
|
||||||
|
this::getRenderPassName,
|
||||||
|
this.mcColorTextureViewWrapper,
|
||||||
|
this.mcDepthTextureViewWrapper))
|
||||||
|
{
|
||||||
|
renderPassWrapper.setVertexBuffer(this.vboGpuBuffer);
|
||||||
|
renderPassWrapper.setPipeline(this.pipeline);
|
||||||
|
renderPassWrapper.draw(3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private String getRenderPassName() { return "distantHorizons:DhTestRenderer"; }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+158
@@ -0,0 +1,158 @@
|
|||||||
|
package com.seibel.distanthorizons.common.render.blaze.util;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_21_10
|
||||||
|
public class BlazeDhVertexFormatUtil {}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.vertex.VertexFormatElement;
|
||||||
|
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderingEngine;
|
||||||
|
import com.seibel.distanthorizons.core.config.Config;
|
||||||
|
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodQuadBuilder;
|
||||||
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_26_1_2
|
||||||
|
#else
|
||||||
|
import com.mojang.blaze3d.GpuFormat;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see LodQuadBuilder
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("DataFlowIssue") // ignore null setter warnings in the static constructor (those will only be null if the render API is GL and in that case we should never use these objects)
|
||||||
|
public class BlazeDhVertexFormatUtil
|
||||||
|
{
|
||||||
|
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
|
|
||||||
|
|
||||||
|
@NotNull public static final VertexFormatElement SCREEN_POS;
|
||||||
|
@NotNull public static final VertexFormatElement RGBA_FLOAT_COLOR;
|
||||||
|
|
||||||
|
@NotNull public static final VertexFormatElement SHORT_XYZ_POS;
|
||||||
|
@NotNull public static final VertexFormatElement BYTE_PAD;
|
||||||
|
/** contains light and micro-offset */
|
||||||
|
@NotNull public static final VertexFormatElement META;
|
||||||
|
@NotNull public static final VertexFormatElement RGBA_UBYTE_COLOR;
|
||||||
|
@NotNull public static final VertexFormatElement IRIS_MATERIAL;
|
||||||
|
@NotNull public static final VertexFormatElement IRIS_NORMAL;
|
||||||
|
|
||||||
|
@NotNull public static final VertexFormatElement FLOAT_XYZ_POS;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static
|
||||||
|
{
|
||||||
|
EDhApiRenderingEngine renderingApi = Config.Client.Advanced.Graphics.Experimental.renderingEngine.get();
|
||||||
|
if (renderingApi == EDhApiRenderingEngine.AUTO)
|
||||||
|
{
|
||||||
|
IVersionConstants versionConstants = SingletonInjector.INSTANCE.get(IVersionConstants.class);
|
||||||
|
renderingApi = versionConstants.getDefaultRenderingEngine();
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean register = (renderingApi == EDhApiRenderingEngine.BLAZE_3D);
|
||||||
|
if (register)
|
||||||
|
{
|
||||||
|
LOGGER.debug("Attempting to register ["+VertexFormatElement.class.getSimpleName()+"]...");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
#if MC_VER <= MC_1_21_11
|
||||||
|
SCREEN_POS = VertexFormatElement.register(/*id*/22, /*index*/0, VertexFormatElement.Type.FLOAT, VertexFormatElement.Usage.POSITION, /*count*/ 2);
|
||||||
|
RGBA_FLOAT_COLOR = VertexFormatElement.register(/*id*/23, /*index*/0, VertexFormatElement.Type.FLOAT, VertexFormatElement.Usage.COLOR, /*count*/ 4);
|
||||||
|
|
||||||
|
SHORT_XYZ_POS = VertexFormatElement.register(/*id*/24, /*index*/0, VertexFormatElement.Type.USHORT, VertexFormatElement.Usage.POSITION, /*count*/ 3);
|
||||||
|
BYTE_PAD = VertexFormatElement.register(/*id*/25, /*index*/0, VertexFormatElement.Type.BYTE, VertexFormatElement.Usage.GENERIC, /*count*/ 1);
|
||||||
|
|
||||||
|
META = VertexFormatElement.register(/*id*/26, /*index*/0, VertexFormatElement.Type.USHORT, VertexFormatElement.Usage.GENERIC, /*count*/ 1);
|
||||||
|
RGBA_UBYTE_COLOR = VertexFormatElement.register(/*id*/27, /*index*/0, VertexFormatElement.Type.UBYTE, VertexFormatElement.Usage.COLOR, /*count*/ 4);
|
||||||
|
IRIS_MATERIAL = VertexFormatElement.register(/*id*/28, /*index*/0, VertexFormatElement.Type.BYTE, VertexFormatElement.Usage.GENERIC, /*count*/ 1);
|
||||||
|
IRIS_NORMAL = VertexFormatElement.register(/*id*/29, /*index*/0, VertexFormatElement.Type.BYTE, VertexFormatElement.Usage.GENERIC, /*count*/ 1);
|
||||||
|
|
||||||
|
FLOAT_XYZ_POS = VertexFormatElement.register(/*id*/30, /*index*/0, VertexFormatElement.Type.FLOAT, VertexFormatElement.Usage.POSITION, /*count*/ 3);
|
||||||
|
#elif MC_VER <= MC_26_1_2
|
||||||
|
SCREEN_POS = VertexFormatElement.register(/*id*/22, /*index*/0, VertexFormatElement.Type.FLOAT, false, /*count*/ 2);
|
||||||
|
RGBA_FLOAT_COLOR = VertexFormatElement.register(/*id*/23, /*index*/0, VertexFormatElement.Type.FLOAT, false, /*count*/ 4);
|
||||||
|
|
||||||
|
SHORT_XYZ_POS = VertexFormatElement.register(/*id*/24, /*index*/0, VertexFormatElement.Type.USHORT, false, /*count*/ 3);
|
||||||
|
BYTE_PAD = VertexFormatElement.register(/*id*/25, /*index*/0, VertexFormatElement.Type.BYTE, false, /*count*/ 1);
|
||||||
|
|
||||||
|
META = VertexFormatElement.register(/*id*/26, /*index*/0, VertexFormatElement.Type.USHORT, false, /*count*/ 1);
|
||||||
|
RGBA_UBYTE_COLOR = VertexFormatElement.register(/*id*/27, /*index*/0, VertexFormatElement.Type.UBYTE, true, /*count*/ 4);
|
||||||
|
IRIS_MATERIAL = VertexFormatElement.register(/*id*/28, /*index*/0, VertexFormatElement.Type.BYTE, false, /*count*/ 1);
|
||||||
|
IRIS_NORMAL = VertexFormatElement.register(/*id*/29, /*index*/0, VertexFormatElement.Type.BYTE, false, /*count*/ 1);
|
||||||
|
|
||||||
|
FLOAT_XYZ_POS = VertexFormatElement.register(/*id*/30, /*index*/0, VertexFormatElement.Type.FLOAT, false, /*count*/ 3);
|
||||||
|
#elif MC_VER <= MC_26_1_2
|
||||||
|
|
||||||
|
SCREEN_POS = VertexFormatElement.register(/*id*/22, /*index*/0, GpuFormat.RG32_FLOAT); // 2 floats
|
||||||
|
RGBA_FLOAT_COLOR = VertexFormatElement.register(/*id*/23, /*index*/0, GpuFormat.RGBA32_FLOAT); // 4 floats
|
||||||
|
|
||||||
|
SHORT_XYZ_POS = VertexFormatElement.register(/*id*/24, /*index*/0, GpuFormat.RGB16_UINT); // 3 ushorts
|
||||||
|
BYTE_PAD = VertexFormatElement.register(/*id*/25, /*index*/0, GpuFormat.R8_UINT); // 1 byte
|
||||||
|
|
||||||
|
META = VertexFormatElement.register(/*id*/26, /*index*/0, GpuFormat.R16_UINT); // 1 ushort
|
||||||
|
RGBA_UBYTE_COLOR = VertexFormatElement.register(/*id*/27, /*index*/0, GpuFormat.RGBA8_UNORM); // 4 ubytes
|
||||||
|
IRIS_MATERIAL = VertexFormatElement.register(/*id*/28, /*index*/0, GpuFormat.R8_UINT); // 1 byte
|
||||||
|
IRIS_NORMAL = VertexFormatElement.register(/*id*/29, /*index*/0, GpuFormat.R8_UINT); // 1 byte
|
||||||
|
|
||||||
|
FLOAT_XYZ_POS = VertexFormatElement.register(/*id*/30, /*index*/0, GpuFormat.RGB32_FLOAT); // 3 floats
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
SCREEN_POS = new VertexFormatElement("Screen Pos", Float.BYTES * 2, GpuFormat.RG32_FLOAT);
|
||||||
|
RGBA_FLOAT_COLOR = new VertexFormatElement("RGBA Float Color", Float.BYTES * 4, GpuFormat.RGBA32_FLOAT);
|
||||||
|
|
||||||
|
SHORT_XYZ_POS = new VertexFormatElement("Short XYZ Pos", Short.BYTES * 3, GpuFormat.RGB16_UINT);
|
||||||
|
BYTE_PAD = new VertexFormatElement("Byte Pad", 1, GpuFormat.R8_UINT);
|
||||||
|
|
||||||
|
META = new VertexFormatElement("DH Meta", Short.BYTES, GpuFormat.R16_UINT);
|
||||||
|
RGBA_UBYTE_COLOR = new VertexFormatElement("Rgba Ubyte Color", 4, GpuFormat.RGBA8_UNORM);
|
||||||
|
IRIS_MATERIAL = new VertexFormatElement("Iris Material", 1, GpuFormat.R8_UINT);
|
||||||
|
IRIS_NORMAL = new VertexFormatElement("Iris Normal", 1, GpuFormat.R8_UINT);
|
||||||
|
|
||||||
|
FLOAT_XYZ_POS = new VertexFormatElement("Float XYZ Pos", Float.BYTES * 3, GpuFormat.RGB32_FLOAT);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
String message = "Unable to register one or more ["+VertexFormatElement.class.getSimpleName()+"] this is likely caused by another mod registering their own custom ["+VertexFormatElement.class.getSimpleName()+"]'s. This should be fixed in the next major Minecraft version.";
|
||||||
|
|
||||||
|
IMinecraftClientWrapper mc = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
|
||||||
|
mc.crashMinecraft(message, new Exception(message, e));
|
||||||
|
|
||||||
|
// here to make the compiler happy, the process should shut down before this
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGGER.debug("Successfully registered ["+VertexFormatElement.class.getSimpleName()+"].");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// set to null so we can fail fast with a null pointer if we ever attempt to incorrectly use these
|
||||||
|
SCREEN_POS = null;
|
||||||
|
RGBA_FLOAT_COLOR = null;
|
||||||
|
|
||||||
|
SHORT_XYZ_POS = null;
|
||||||
|
BYTE_PAD = null;
|
||||||
|
|
||||||
|
META = null;
|
||||||
|
RGBA_UBYTE_COLOR = null;
|
||||||
|
IRIS_MATERIAL = null;
|
||||||
|
IRIS_NORMAL = null;
|
||||||
|
|
||||||
|
FLOAT_XYZ_POS = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+82
@@ -0,0 +1,82 @@
|
|||||||
|
package com.seibel.distanthorizons.common.render.blaze.util;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_21_10
|
||||||
|
public class BlazePostProcessUtil {}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.buffers.GpuBuffer;
|
||||||
|
import com.mojang.blaze3d.buffers.GpuBufferSlice;
|
||||||
|
import com.mojang.blaze3d.systems.CommandEncoder;
|
||||||
|
import com.mojang.blaze3d.systems.GpuDevice;
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.BlazeVertexFormatBuilder;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
/** Contains code that's used by all post-processing effects. */
|
||||||
|
public class BlazePostProcessUtil
|
||||||
|
{
|
||||||
|
|
||||||
|
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
|
||||||
|
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
|
||||||
|
|
||||||
|
// vertices for a full-screen quad
|
||||||
|
private static final float[] VERTICES = new float[]
|
||||||
|
{
|
||||||
|
// PosX,Y,
|
||||||
|
-1f, -1f,
|
||||||
|
1f, -1f,
|
||||||
|
1f, 1f,
|
||||||
|
-1f, 1f,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=========//
|
||||||
|
// methods //
|
||||||
|
//=========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public static GpuBuffer createAndUploadScreenVertexData(String name)
|
||||||
|
{
|
||||||
|
Supplier<String> labelSupplier = () -> "distantHorizons:"+name;
|
||||||
|
|
||||||
|
int usage = GpuBuffer.USAGE_COPY_DST
|
||||||
|
| GpuBuffer.USAGE_VERTEX;
|
||||||
|
int size = VERTICES.length * Float.BYTES;
|
||||||
|
GpuBuffer vboGpuBuffer = GPU_DEVICE.createBuffer(labelSupplier, usage, size);
|
||||||
|
|
||||||
|
{
|
||||||
|
int length = VERTICES.length * Float.BYTES;
|
||||||
|
GpuBufferSlice bufferSlice = new GpuBufferSlice(vboGpuBuffer, /*offset*/ 0, length);
|
||||||
|
|
||||||
|
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(VERTICES.length * Float.BYTES);
|
||||||
|
// Fill buffer with vertices.
|
||||||
|
byteBuffer.order(ByteOrder.nativeOrder());
|
||||||
|
byteBuffer.asFloatBuffer().put(VERTICES);
|
||||||
|
byteBuffer.rewind();
|
||||||
|
|
||||||
|
COMMAND_ENCODER.writeToBuffer(bufferSlice, byteBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return vboGpuBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static VertexFormat createVertexFormat()
|
||||||
|
{
|
||||||
|
VertexFormat vertexFormat = new BlazeVertexFormatBuilder()
|
||||||
|
.add("vPosition", BlazeDhVertexFormatUtil.SCREEN_POS)
|
||||||
|
.build();
|
||||||
|
return vertexFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+46
@@ -0,0 +1,46 @@
|
|||||||
|
package com.seibel.distanthorizons.common.render.blaze.util;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_21_10
|
||||||
|
public class BlazeUniformUtil {}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.buffers.GpuBuffer;
|
||||||
|
import com.mojang.blaze3d.systems.CommandEncoder;
|
||||||
|
import com.mojang.blaze3d.systems.GpuDevice;
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
|
||||||
|
public class BlazeUniformUtil
|
||||||
|
{
|
||||||
|
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
|
|
||||||
|
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
|
||||||
|
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
|
||||||
|
|
||||||
|
|
||||||
|
public static GpuBuffer createBuffer(String uniformName, int size, GpuBuffer vboGpuBuffer)
|
||||||
|
{
|
||||||
|
// create VBO if needed
|
||||||
|
if (vboGpuBuffer == null
|
||||||
|
|| vboGpuBuffer.size() < size)
|
||||||
|
{
|
||||||
|
if (vboGpuBuffer != null)
|
||||||
|
{
|
||||||
|
vboGpuBuffer.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
int usage = GpuBuffer.USAGE_COPY_DST
|
||||||
|
| GpuBuffer.USAGE_VERTEX
|
||||||
|
| GpuBuffer.USAGE_UNIFORM;
|
||||||
|
vboGpuBuffer = GPU_DEVICE.createBuffer(() -> uniformName, usage, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return vboGpuBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+58
@@ -0,0 +1,58 @@
|
|||||||
|
package com.seibel.distanthorizons.common.render.blaze.wrappers;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_21_10
|
||||||
|
public class BlazeVertexFormatBuilder {}
|
||||||
|
#else
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||||
|
import com.mojang.blaze3d.vertex.VertexFormatElement;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.util.BlazeDhVertexFormatUtil;
|
||||||
|
|
||||||
|
public class BlazeVertexFormatBuilder
|
||||||
|
{
|
||||||
|
private final VertexFormat.Builder builder;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public BlazeVertexFormatBuilder()
|
||||||
|
{
|
||||||
|
#if MC_VER <= MC_26_1_2
|
||||||
|
this.builder = VertexFormat.builder();
|
||||||
|
#else
|
||||||
|
this.builder = VertexFormat.builder(0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//==========//
|
||||||
|
// building //
|
||||||
|
//==========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public BlazeVertexFormatBuilder add(String name, VertexFormatElement element)
|
||||||
|
{
|
||||||
|
#if MC_VER <= MC_26_1_2
|
||||||
|
this.builder.add(name, element);
|
||||||
|
#else
|
||||||
|
this.builder.addAttribute(name, element.format());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VertexFormat build() { return this.builder.build(); }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+162
@@ -0,0 +1,162 @@
|
|||||||
|
package com.seibel.distanthorizons.common.render.blaze.wrappers;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_21_10
|
||||||
|
public class RenderPassWrapper {}
|
||||||
|
#else
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.buffers.GpuBuffer;
|
||||||
|
import com.mojang.blaze3d.pipeline.RenderPipeline;
|
||||||
|
import com.mojang.blaze3d.systems.CommandEncoder;
|
||||||
|
import com.mojang.blaze3d.systems.GpuDevice;
|
||||||
|
import com.mojang.blaze3d.systems.RenderPass;
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.IDhBlazeTexture;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.uniform.BlazeUniformBufferWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
|
||||||
|
import java.util.OptionalDouble;
|
||||||
|
import java.util.OptionalInt;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_26_1_2
|
||||||
|
#else
|
||||||
|
import com.mojang.blaze3d.IndexType;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public class RenderPassWrapper implements AutoCloseable
|
||||||
|
{
|
||||||
|
public static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
|
|
||||||
|
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
|
||||||
|
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
|
||||||
|
|
||||||
|
|
||||||
|
private final RenderPass renderPass;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public RenderPassWrapper(
|
||||||
|
final Supplier<String> nameGetterFunc,
|
||||||
|
final IDhBlazeTexture colorTexture,
|
||||||
|
final IDhBlazeTexture depthTexture)
|
||||||
|
{
|
||||||
|
#if MC_VER <= MC_26_1_2
|
||||||
|
this.renderPass = COMMAND_ENCODER.createRenderPass(
|
||||||
|
nameGetterFunc,
|
||||||
|
colorTexture.getTextureView(),
|
||||||
|
/*optionalClearColorAsInt*/ OptionalInt.empty(),
|
||||||
|
depthTexture.getTextureView(),
|
||||||
|
/*optionalDepthValueAsDouble*/ OptionalDouble.empty());
|
||||||
|
#else
|
||||||
|
this.renderPass = COMMAND_ENCODER.createRenderPass(
|
||||||
|
nameGetterFunc,
|
||||||
|
colorTexture.getTextureView(),
|
||||||
|
/*clearColor*/ Optional.empty(),
|
||||||
|
depthTexture.getTextureView(),
|
||||||
|
/*clearDepth*/ OptionalDouble.empty());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=======//
|
||||||
|
// setup //
|
||||||
|
//=======//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public void bindTexture(
|
||||||
|
final String name,
|
||||||
|
final IDhBlazeTexture textureView)
|
||||||
|
{
|
||||||
|
this.renderPass.bindTexture(
|
||||||
|
name,
|
||||||
|
textureView.getTextureView(),
|
||||||
|
textureView.getTextureSampler());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVertexBuffer(GpuBuffer buffer)
|
||||||
|
{
|
||||||
|
#if MC_VER <= MC_26_1_2
|
||||||
|
this.renderPass.setVertexBuffer(/*slot*/0, buffer);
|
||||||
|
#else
|
||||||
|
this.renderPass.setVertexBuffer(/*slot*/0, buffer.slice());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIndexBuffer(GpuBuffer buffer)
|
||||||
|
{
|
||||||
|
#if MC_VER <= MC_26_1_2
|
||||||
|
this.renderPass.setIndexBuffer(buffer, VertexFormat.IndexType.INT);
|
||||||
|
#else
|
||||||
|
this.renderPass.setIndexBuffer(buffer, IndexType.INT);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUniform(String uniformName, BlazeUniformBufferWrapper uniformBuffer) { this.renderPass.setUniform(uniformName, uniformBuffer.getGpuBuffer()); }
|
||||||
|
|
||||||
|
public void setPipeline(RenderPipeline pipeline) { this.renderPass.setPipeline(pipeline); }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//===========//
|
||||||
|
// rendering //
|
||||||
|
//===========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public void draw(int vertexCount)
|
||||||
|
{
|
||||||
|
#if MC_VER <= MC_26_1_2
|
||||||
|
this.renderPass.draw(0, vertexCount);
|
||||||
|
#else
|
||||||
|
this.renderPass.draw(vertexCount, /*instanceCount*/1, /*firstVertex*/0, /*firstInstance*/0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawIndexed(int indexCount)
|
||||||
|
{
|
||||||
|
#if MC_VER <= MC_26_1_2
|
||||||
|
this.renderPass.drawIndexed(
|
||||||
|
/*indexStart*/ 0,
|
||||||
|
/*firstIndex*/0,
|
||||||
|
indexCount,
|
||||||
|
/*instanceCount*/1);
|
||||||
|
#else
|
||||||
|
this.renderPass.drawIndexed(
|
||||||
|
indexCount,
|
||||||
|
/*instanceCount*/1,
|
||||||
|
/*firstVertex*/0,
|
||||||
|
/*vertexOffset*/0,
|
||||||
|
/*firstInstance*/0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// base overrides //
|
||||||
|
//================//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() { this.renderPass.close(); }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+445
@@ -0,0 +1,445 @@
|
|||||||
|
package com.seibel.distanthorizons.common.render.blaze.wrappers;
|
||||||
|
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_21_10
|
||||||
|
public class RenderPipelineBuilderWrapper {}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.pipeline.*;
|
||||||
|
import com.mojang.blaze3d.platform.PolygonMode;
|
||||||
|
import com.mojang.blaze3d.shaders.UniformType;
|
||||||
|
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||||
|
import net.minecraft.resources.Identifier;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_21_11
|
||||||
|
import com.mojang.blaze3d.platform.DepthTestFunction;
|
||||||
|
#elif MC_VER <= MC_26_1_2
|
||||||
|
import com.mojang.blaze3d.platform.CompareOp;
|
||||||
|
#else
|
||||||
|
import com.mojang.blaze3d.platform.CompareOp;
|
||||||
|
import com.mojang.blaze3d.GpuFormat;
|
||||||
|
import com.mojang.blaze3d.PrimitiveTopology;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public class RenderPipelineBuilderWrapper
|
||||||
|
{
|
||||||
|
public static final String NAME_PREFIX = "distanthorizons:";
|
||||||
|
|
||||||
|
private static final String SHADER_RESOURCE_FOLDER = "assets/distanthorizons/shaders/";
|
||||||
|
|
||||||
|
private static final ClassLoader CLASS_LOADER = RenderPipelineBuilderWrapper.class.getClassLoader();
|
||||||
|
|
||||||
|
|
||||||
|
private final RenderPipeline.Builder blazePipelineBuilder;
|
||||||
|
|
||||||
|
// variables for specific builder options should be put next to their builder methods for simpler organization
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public RenderPipelineBuilderWrapper()
|
||||||
|
{
|
||||||
|
this.blazePipelineBuilder = RenderPipeline.builder();
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//==========//
|
||||||
|
// building //
|
||||||
|
//==========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
private boolean writeDepth = false;
|
||||||
|
public RenderPipelineBuilderWrapper withDepthWrite(boolean write)
|
||||||
|
{
|
||||||
|
this.writeDepth = write;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean writeColor = false;
|
||||||
|
public RenderPipelineBuilderWrapper withColorWrite(boolean write)
|
||||||
|
{
|
||||||
|
this.writeColor = write;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private BlendFunction blendFunction = null;
|
||||||
|
public RenderPipelineBuilderWrapper withBlend(BlendFunction blendFunction)
|
||||||
|
{
|
||||||
|
this.blendFunction = blendFunction;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public RenderPipelineBuilderWrapper withoutBlend()
|
||||||
|
{
|
||||||
|
this.blendFunction = null;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private EDhDepthTest depthTest;
|
||||||
|
public RenderPipelineBuilderWrapper withDepthTest(EDhDepthTest depthTest)
|
||||||
|
{
|
||||||
|
this.depthTest = depthTest;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RenderPipelineBuilderWrapper withFaceCulling(boolean culling)
|
||||||
|
{
|
||||||
|
this.blazePipelineBuilder.withCull(culling);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RenderPipelineBuilderWrapper withPolygonMode(EDhPolygonMode dhMode)
|
||||||
|
{
|
||||||
|
PolygonMode blazeMode;
|
||||||
|
switch (dhMode)
|
||||||
|
{
|
||||||
|
case FILL:
|
||||||
|
blazeMode = PolygonMode.FILL;
|
||||||
|
break;
|
||||||
|
case WIREFRAME:
|
||||||
|
blazeMode = PolygonMode.WIREFRAME;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new UnsupportedOperationException("No polygonMode defined for type ["+dhMode+"].");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.blazePipelineBuilder.withPolygonMode(blazeMode);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RenderPipelineBuilderWrapper withName(String name) throws IllegalArgumentException
|
||||||
|
{
|
||||||
|
// Identifiers must be of a specific format
|
||||||
|
if (!isValidIdentifier(name))
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("Non [a-z0-9/._-] character in name: ["+name+"].");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.blazePipelineBuilder.withLocation(Identifier.parse(NAME_PREFIX + name));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final ArrayList<String> samplerNames = new ArrayList<>();
|
||||||
|
public RenderPipelineBuilderWrapper withSampler(String name) throws IllegalArgumentException
|
||||||
|
{
|
||||||
|
#if MC_VER <= MC_26_1_2
|
||||||
|
this.blazePipelineBuilder.withSampler(name);
|
||||||
|
#else
|
||||||
|
samplerNames.add(name);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final ArrayList<String> uniformBufferNames = new ArrayList<>();
|
||||||
|
public RenderPipelineBuilderWrapper withUniformBuffer(String name) throws IllegalArgumentException
|
||||||
|
{
|
||||||
|
#if MC_VER <= MC_26_1_2
|
||||||
|
this.blazePipelineBuilder.withUniform(name, UniformType.UNIFORM_BUFFER);
|
||||||
|
#else
|
||||||
|
uniformBufferNames.add(name);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private VertexFormat vertexFormat = null;
|
||||||
|
public RenderPipelineBuilderWrapper withVertexFormat(VertexFormat vertexFormat)
|
||||||
|
{
|
||||||
|
this.vertexFormat = vertexFormat;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private EDhVertexMode vertexMode = null;
|
||||||
|
public RenderPipelineBuilderWrapper withVertexMode(EDhVertexMode vertexMode)
|
||||||
|
{
|
||||||
|
this.vertexMode = vertexMode;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RenderPipelineBuilderWrapper withVertexShader(String scriptResourcePath) { return this.withShader(EDhShaderType.VERTEX, scriptResourcePath); }
|
||||||
|
public RenderPipelineBuilderWrapper withFragmentShader(String scriptResourcePath) { return this.withShader(EDhShaderType.FRAGMENT, scriptResourcePath); }
|
||||||
|
private RenderPipelineBuilderWrapper withShader(EDhShaderType shaderType, String scriptResourcePath)
|
||||||
|
{
|
||||||
|
String fullShaderResourcePath = SHADER_RESOURCE_FOLDER + scriptResourcePath + shaderType.fileExtension;
|
||||||
|
|
||||||
|
// confirm the shader file exists
|
||||||
|
try (InputStream scriptListInputStream = CLASS_LOADER.getResourceAsStream(fullShaderResourcePath))
|
||||||
|
{
|
||||||
|
if (scriptListInputStream == null)
|
||||||
|
{
|
||||||
|
throw new NullPointerException("Failed to find the SQL Script list file [" + fullShaderResourcePath + "], no auto update scripts can be run.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
// shouldn't happen, but just in case
|
||||||
|
throw new RuntimeException("Unexpected issue closing resource stream for shader type: ["+shaderType+"] at: ["+fullShaderResourcePath+"], error: ["+e.getMessage()+"].", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (shaderType == EDhShaderType.VERTEX)
|
||||||
|
{
|
||||||
|
this.blazePipelineBuilder.withVertexShader(Identifier.parse(NAME_PREFIX + scriptResourcePath));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.blazePipelineBuilder.withFragmentShader(Identifier.parse(NAME_PREFIX + scriptResourcePath));
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=====//
|
||||||
|
// end //
|
||||||
|
//=====//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public RenderPipeline build() throws UnsupportedOperationException
|
||||||
|
{
|
||||||
|
// depth/color
|
||||||
|
{
|
||||||
|
#if MC_VER <= MC_1_21_11
|
||||||
|
|
||||||
|
this.blazePipelineBuilder.withDepthWrite(this.writeDepth);
|
||||||
|
this.blazePipelineBuilder.withColorWrite(this.writeColor);
|
||||||
|
|
||||||
|
if (this.blendFunction != null)
|
||||||
|
{
|
||||||
|
this.blazePipelineBuilder.withBlend(this.blendFunction);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.blazePipelineBuilder.withoutBlend();
|
||||||
|
}
|
||||||
|
|
||||||
|
DepthTestFunction depthTestFunction;
|
||||||
|
switch (this.depthTest)
|
||||||
|
{
|
||||||
|
case NONE:
|
||||||
|
depthTestFunction = DepthTestFunction.NO_DEPTH_TEST;
|
||||||
|
break;
|
||||||
|
case LESS:
|
||||||
|
depthTestFunction = DepthTestFunction.LESS_DEPTH_TEST;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new UnsupportedOperationException("No depth test defined for type ["+this.depthTest+"].");
|
||||||
|
}
|
||||||
|
this.blazePipelineBuilder.withDepthTestFunction(depthTestFunction);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
CompareOp compareOp;
|
||||||
|
switch (this.depthTest)
|
||||||
|
{
|
||||||
|
case NONE:
|
||||||
|
compareOp = CompareOp.ALWAYS_PASS;
|
||||||
|
break;
|
||||||
|
case LESS:
|
||||||
|
compareOp = CompareOp.LESS_THAN;
|
||||||
|
break;
|
||||||
|
case GREATER:
|
||||||
|
compareOp = CompareOp.GREATER_THAN;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new UnsupportedOperationException("No depth test defined for type ["+this.depthTest+"].");
|
||||||
|
}
|
||||||
|
this.blazePipelineBuilder.withDepthStencilState(new DepthStencilState(compareOp, this.writeDepth));
|
||||||
|
|
||||||
|
#if MC_VER <= MC_26_1_2
|
||||||
|
this.blazePipelineBuilder.withColorTargetState(
|
||||||
|
new ColorTargetState(
|
||||||
|
Optional.ofNullable(this.blendFunction),
|
||||||
|
this.writeColor ? ColorTargetState.WRITE_ALL : ColorTargetState.WRITE_NONE
|
||||||
|
)
|
||||||
|
);
|
||||||
|
#else
|
||||||
|
this.blazePipelineBuilder.withColorTargetState(
|
||||||
|
new ColorTargetState(
|
||||||
|
Optional.ofNullable(this.blendFunction),
|
||||||
|
GpuFormat.RGBA8_UNORM,
|
||||||
|
this.writeColor ? ColorTargetState.WRITE_ALL : ColorTargetState.WRITE_NONE
|
||||||
|
)
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// vertex format
|
||||||
|
{
|
||||||
|
#if MC_VER <= MC_26_1_2
|
||||||
|
VertexFormat.Mode blazeVertexMode;
|
||||||
|
switch (this.vertexMode)
|
||||||
|
{
|
||||||
|
case TRIANGLES:
|
||||||
|
blazeVertexMode = VertexFormat.Mode.TRIANGLES;
|
||||||
|
break;
|
||||||
|
case TRIANGLE_FAN:
|
||||||
|
blazeVertexMode = VertexFormat.Mode.TRIANGLE_FAN;
|
||||||
|
break;
|
||||||
|
case LINES:
|
||||||
|
blazeVertexMode = VertexFormat.Mode.DEBUG_LINES;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new UnsupportedOperationException("No vertex mode defined for type ["+this.vertexMode+"].");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.blazePipelineBuilder.withVertexFormat(vertexFormat, blazeVertexMode);
|
||||||
|
#else
|
||||||
|
|
||||||
|
PrimitiveTopology primitiveTopology;
|
||||||
|
switch (this.vertexMode)
|
||||||
|
{
|
||||||
|
case TRIANGLES:
|
||||||
|
primitiveTopology = PrimitiveTopology.TRIANGLES;
|
||||||
|
break;
|
||||||
|
case TRIANGLE_FAN:
|
||||||
|
primitiveTopology = PrimitiveTopology.TRIANGLE_FAN;
|
||||||
|
break;
|
||||||
|
case LINES:
|
||||||
|
primitiveTopology = PrimitiveTopology.DEBUG_LINES;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new UnsupportedOperationException("No PrimitiveTopology defined for type ["+this.vertexMode+"].");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.blazePipelineBuilder.withVertexBinding(0, vertexFormat);
|
||||||
|
this.blazePipelineBuilder.withPrimitiveTopology(primitiveTopology);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// uniform buffers
|
||||||
|
{
|
||||||
|
#if MC_VER <= MC_26_1_2
|
||||||
|
// handled before this point
|
||||||
|
#else
|
||||||
|
|
||||||
|
BindGroupLayout.Builder bindGroupBuilder = BindGroupLayout.builder();
|
||||||
|
|
||||||
|
for (String name : this.samplerNames)
|
||||||
|
{
|
||||||
|
bindGroupBuilder.withSampler(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String name : this.uniformBufferNames)
|
||||||
|
{
|
||||||
|
bindGroupBuilder.withUniform(name, UniformType.UNIFORM_BUFFER);
|
||||||
|
}
|
||||||
|
|
||||||
|
BindGroupLayout bindGroup = bindGroupBuilder.build();
|
||||||
|
this.blazePipelineBuilder.withBindGroupLayout(bindGroup);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return this.blazePipelineBuilder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// helper methods //
|
||||||
|
//================//
|
||||||
|
//region
|
||||||
|
|
||||||
|
private static boolean isValidIdentifier(String identifier)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < identifier.length(); i++)
|
||||||
|
{
|
||||||
|
char ch = identifier.charAt(i);
|
||||||
|
if (!isValidNamespaceChar(ch))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
private static boolean isValidNamespaceChar(final char ch)
|
||||||
|
{
|
||||||
|
return ch == '_'
|
||||||
|
|| ch == '-'
|
||||||
|
// only lower case characters
|
||||||
|
|| (ch >= 'a' && ch <= 'z')
|
||||||
|
|| (ch >= '0' && ch <= '9')
|
||||||
|
|| ch == '.';
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// helper classes //
|
||||||
|
//================//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public enum EDhPolygonMode
|
||||||
|
{
|
||||||
|
FILL,
|
||||||
|
WIREFRAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum EDhVertexMode
|
||||||
|
{
|
||||||
|
TRIANGLES,
|
||||||
|
TRIANGLE_FAN,
|
||||||
|
LINES;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum EDhDepthTest
|
||||||
|
{
|
||||||
|
NONE,
|
||||||
|
GREATER,
|
||||||
|
LESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum EDhShaderType
|
||||||
|
{
|
||||||
|
FRAGMENT(".fsh"),
|
||||||
|
VERTEX(".vsh");
|
||||||
|
|
||||||
|
|
||||||
|
public final String fileExtension;
|
||||||
|
|
||||||
|
EDhShaderType(String fileExtension)
|
||||||
|
{
|
||||||
|
this.fileExtension = fileExtension;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+214
@@ -0,0 +1,214 @@
|
|||||||
|
package com.seibel.distanthorizons.common.render.blaze.wrappers.buffer;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_21_10
|
||||||
|
public class BlazeVertexBufferWrapper {}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.buffers.GpuBuffer;
|
||||||
|
import com.mojang.blaze3d.buffers.GpuBufferSlice;
|
||||||
|
import com.mojang.blaze3d.systems.CommandEncoder;
|
||||||
|
import com.mojang.blaze3d.systems.GpuDevice;
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.IndexBufferBuilder;
|
||||||
|
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodQuadBuilder;
|
||||||
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import com.seibel.distanthorizons.core.render.RenderThreadTaskHandler;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IVertexBufferWrapper;
|
||||||
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
public class BlazeVertexBufferWrapper implements IVertexBufferWrapper
|
||||||
|
{
|
||||||
|
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
|
|
||||||
|
private static final AbstractDhRenderApiDefinition RENDER_DEF = SingletonInjector.INSTANCE.get(AbstractDhRenderApiDefinition.class);
|
||||||
|
|
||||||
|
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
|
||||||
|
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
|
||||||
|
|
||||||
|
private static final AtomicInteger BUFFER_COUNT_REF = new AtomicInteger(0);
|
||||||
|
|
||||||
|
|
||||||
|
public final String name;
|
||||||
|
public String getName() { return this.name; }
|
||||||
|
|
||||||
|
public GpuBuffer vertexGpuBuffer = null;
|
||||||
|
|
||||||
|
public int vertexCount = -1;
|
||||||
|
public int indexCount = -1;
|
||||||
|
public boolean uploaded = false;
|
||||||
|
|
||||||
|
|
||||||
|
private GpuBuffer indexGpuBuffer = null;
|
||||||
|
private static GpuBuffer GLOBAL_INDEX_GPU_BUFFER = null;
|
||||||
|
public GpuBuffer getIndexGpuBuffer()
|
||||||
|
{
|
||||||
|
if (RENDER_DEF.useSingleIbo())
|
||||||
|
{
|
||||||
|
return GLOBAL_INDEX_GPU_BUFFER;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return this.indexGpuBuffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
static
|
||||||
|
{
|
||||||
|
if (RENDER_DEF.useSingleIbo())
|
||||||
|
{
|
||||||
|
RenderThreadTaskHandler.INSTANCE.queueRunningOnRenderThread("Global IBO Creation", () ->
|
||||||
|
{
|
||||||
|
int maxSize = LodQuadBuilder.getMaxBufferByteSize();
|
||||||
|
int maxVertexCount = maxSize / LodQuadBuilder.BYTES_PER_VERTEX;
|
||||||
|
int maxQuadCount = (maxVertexCount / 4);
|
||||||
|
ByteBuffer indexBuffer = IndexBufferBuilder.createBuffer(maxQuadCount);
|
||||||
|
|
||||||
|
int usage = GpuBuffer.USAGE_COPY_DST
|
||||||
|
| GpuBuffer.USAGE_INDEX;
|
||||||
|
GLOBAL_INDEX_GPU_BUFFER = GPU_DEVICE.createBuffer(BlazeVertexBufferWrapper::getIndexBufferName, usage, indexBuffer.capacity());
|
||||||
|
|
||||||
|
GpuBufferSlice bufferSlice = new GpuBufferSlice(GLOBAL_INDEX_GPU_BUFFER, /*offset*/ 0, indexBuffer.capacity());
|
||||||
|
COMMAND_ENCODER.writeToBuffer(bufferSlice, indexBuffer);
|
||||||
|
|
||||||
|
MemoryUtil.memFree(indexBuffer);
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlazeVertexBufferWrapper(String name) { this.name = name; }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//========//
|
||||||
|
// upload //
|
||||||
|
//========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void uploadVertexBuffer(ByteBuffer vertexBuffer, int vertexCount)
|
||||||
|
{
|
||||||
|
int oldVertexCount = this.vertexCount;
|
||||||
|
|
||||||
|
this.vertexCount = vertexCount;
|
||||||
|
// 4 vertices per face, but 6 indices (IE 2 triangles) per face, aka need to multiply by 1.5
|
||||||
|
this.indexCount = (int)(vertexCount * 1.5);
|
||||||
|
this.uploaded = true;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (this.vertexGpuBuffer == null
|
||||||
|
// recreating if the size changes is always necessary (even if we only need a smaller amount)
|
||||||
|
// due to a bug on Mac where it will attempt to render anything allocated in the buffer
|
||||||
|
|| oldVertexCount != vertexCount)
|
||||||
|
{
|
||||||
|
if (this.vertexGpuBuffer == null)
|
||||||
|
{
|
||||||
|
BUFFER_COUNT_REF.incrementAndGet();
|
||||||
|
//LOGGER.info("Create, count: ["+BUFFER_COUNT_REF.get()+"]");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.vertexGpuBuffer != null)
|
||||||
|
{
|
||||||
|
this.vertexGpuBuffer.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
int usage = GpuBuffer.USAGE_COPY_DST
|
||||||
|
| GpuBuffer.USAGE_VERTEX;
|
||||||
|
int byteSize = (vertexBuffer.limit() - vertexBuffer.position());
|
||||||
|
this.vertexGpuBuffer = GPU_DEVICE.createBuffer(this::getName, usage, byteSize);
|
||||||
|
|
||||||
|
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.vertexGpuBuffer, /*offset*/0, byteSize);
|
||||||
|
COMMAND_ENCODER.writeToBuffer(bufferSlice, vertexBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void uploadIndexBuffer(ByteBuffer indexBuffer, int vertexCount)
|
||||||
|
{
|
||||||
|
int oldIndexCount = this.indexCount;
|
||||||
|
// 4 vertices per face, but 6 indices (IE 2 triangles) per face, aka need to multiply by 1.5
|
||||||
|
this.indexCount = (int)(vertexCount * 1.5);
|
||||||
|
|
||||||
|
if (RENDER_DEF.useSingleIbo())
|
||||||
|
{
|
||||||
|
// ignore index uploading when running a single IBO
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// recreating if the size changes is always necessary (even if we only need a smaller amount)
|
||||||
|
// due to a bug on Mac where it will attempt to render anything allocated in the buffer
|
||||||
|
if (this.indexGpuBuffer == null
|
||||||
|
|| oldIndexCount != this.indexCount)
|
||||||
|
{
|
||||||
|
if (this.indexGpuBuffer == null)
|
||||||
|
{
|
||||||
|
BUFFER_COUNT_REF.incrementAndGet();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.indexGpuBuffer != null)
|
||||||
|
{
|
||||||
|
this.indexGpuBuffer.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
int usage = GpuBuffer.USAGE_COPY_DST
|
||||||
|
| GpuBuffer.USAGE_INDEX;
|
||||||
|
this.indexGpuBuffer = GPU_DEVICE.createBuffer(BlazeVertexBufferWrapper::getIndexBufferName, usage, indexBuffer.capacity());
|
||||||
|
|
||||||
|
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.indexGpuBuffer, /*offset*/ 0, indexBuffer.capacity());
|
||||||
|
COMMAND_ENCODER.writeToBuffer(bufferSlice, indexBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private static String getIndexBufferName() { return "distantHorizons:LodIndexBuffer"; }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// base overrides //
|
||||||
|
//================//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close()
|
||||||
|
{
|
||||||
|
if (this.vertexGpuBuffer != null)
|
||||||
|
{
|
||||||
|
BUFFER_COUNT_REF.decrementAndGet();
|
||||||
|
this.vertexGpuBuffer.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.indexGpuBuffer != null)
|
||||||
|
{
|
||||||
|
BUFFER_COUNT_REF.decrementAndGet();
|
||||||
|
this.indexGpuBuffer.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
//LOGGER.info("Close, count: ["+BUFFER_COUNT_REF.get()+"]");
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+75
@@ -0,0 +1,75 @@
|
|||||||
|
package com.seibel.distanthorizons.common.render.blaze.wrappers.texture;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_21_10
|
||||||
|
public class BlazeTextureViewWrapper {}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.systems.CommandEncoder;
|
||||||
|
import com.mojang.blaze3d.systems.GpuDevice;
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
import com.mojang.blaze3d.textures.*;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
|
||||||
|
import java.util.OptionalDouble;
|
||||||
|
|
||||||
|
public class BlazeTextureViewWrapper implements IDhBlazeTexture
|
||||||
|
{
|
||||||
|
public static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
|
|
||||||
|
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
|
||||||
|
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
|
||||||
|
|
||||||
|
|
||||||
|
private GpuTextureView textureView = null;
|
||||||
|
public GpuTextureView getTextureView() { return this.textureView; }
|
||||||
|
|
||||||
|
private GpuSampler textureSampler = null;
|
||||||
|
public GpuSampler getTextureSampler() { return this.textureSampler; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=======//
|
||||||
|
// setup //
|
||||||
|
//=======//
|
||||||
|
//region
|
||||||
|
|
||||||
|
/** does nothing if the texture is already wrapped */
|
||||||
|
public void tryWrap(GpuTexture texture)
|
||||||
|
{
|
||||||
|
this.tryRecreateTextureView(texture);
|
||||||
|
this.tryCreateSampler();
|
||||||
|
}
|
||||||
|
private void tryRecreateTextureView(GpuTexture texture)
|
||||||
|
{
|
||||||
|
if (this.textureView == null
|
||||||
|
|| this.textureView.texture() != texture)
|
||||||
|
{
|
||||||
|
if (this.textureView != null)
|
||||||
|
{
|
||||||
|
this.textureView.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.textureView = GPU_DEVICE.createTextureView(texture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void tryCreateSampler()
|
||||||
|
{
|
||||||
|
if (this.textureSampler == null)
|
||||||
|
{
|
||||||
|
this.textureSampler = GPU_DEVICE.createSampler(
|
||||||
|
AddressMode.CLAMP_TO_EDGE, AddressMode.CLAMP_TO_EDGE, // U,V
|
||||||
|
FilterMode.LINEAR, FilterMode.LINEAR, // minFilter, magFilter
|
||||||
|
1, // maxAnisotropy
|
||||||
|
OptionalDouble.empty() // maxLod
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+223
@@ -0,0 +1,223 @@
|
|||||||
|
package com.seibel.distanthorizons.common.render.blaze.wrappers.texture;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_21_10
|
||||||
|
public class BlazeTextureWrapper {}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import com.seibel.distanthorizons.coreapi.util.ColorUtil;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||||
|
|
||||||
|
import java.util.OptionalDouble;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.systems.CommandEncoder;
|
||||||
|
import com.mojang.blaze3d.systems.GpuDevice;
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
import com.mojang.blaze3d.textures.*;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_26_1_2
|
||||||
|
|
||||||
|
#else
|
||||||
|
import com.mojang.blaze3d.GpuFormat;
|
||||||
|
import org.joml.Vector4f;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public class BlazeTextureWrapper implements IDhBlazeTexture
|
||||||
|
{
|
||||||
|
public static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
|
|
||||||
|
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
|
||||||
|
|
||||||
|
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
|
||||||
|
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
|
||||||
|
|
||||||
|
|
||||||
|
public final String name;
|
||||||
|
#if MC_VER <= MC_26_1_2
|
||||||
|
public final TextureFormat textureFormat;
|
||||||
|
#else
|
||||||
|
public final GpuFormat textureFormat;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public GpuTexture texture = null;
|
||||||
|
|
||||||
|
private GpuTextureView textureView = null;
|
||||||
|
public GpuTextureView getTextureView() { return this.textureView; }
|
||||||
|
|
||||||
|
private GpuSampler textureSampler = null;
|
||||||
|
public GpuSampler getTextureSampler() { return this.textureSampler; }
|
||||||
|
|
||||||
|
|
||||||
|
private int width = -1;
|
||||||
|
private int height = -1;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//==============//
|
||||||
|
// constructors //
|
||||||
|
//==============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public static BlazeTextureWrapper createDepth(String name)
|
||||||
|
{
|
||||||
|
#if MC_VER <= MC_26_1_2
|
||||||
|
return new BlazeTextureWrapper(name, TextureFormat.DEPTH32);
|
||||||
|
#else
|
||||||
|
return new BlazeTextureWrapper(name, GpuFormat.D32_FLOAT);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
public static BlazeTextureWrapper createColor(String name)
|
||||||
|
{
|
||||||
|
#if MC_VER <= MC_26_1_2
|
||||||
|
return new BlazeTextureWrapper(name, TextureFormat.RGBA8);
|
||||||
|
#else
|
||||||
|
return new BlazeTextureWrapper(name, GpuFormat.RGBA8_UNORM);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private BlazeTextureWrapper(
|
||||||
|
String name,
|
||||||
|
#if MC_VER <= MC_26_1_2 TextureFormat #else GpuFormat #endif textureFormat
|
||||||
|
)
|
||||||
|
{
|
||||||
|
this.name = name;
|
||||||
|
this.textureFormat = textureFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=========//
|
||||||
|
// getters //
|
||||||
|
//=========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public boolean isEmpty() { return this.texture == null; }
|
||||||
|
|
||||||
|
/** @return -1 if the texture is null */
|
||||||
|
public int getWidth() { return this.width; }
|
||||||
|
/** @return -1 if the texture is null */
|
||||||
|
public int getHeight() { return this.height; }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=======//
|
||||||
|
// setup //
|
||||||
|
//=======//
|
||||||
|
//region
|
||||||
|
|
||||||
|
/**
|
||||||
|
* does nothing if the texture is already created and the correct size
|
||||||
|
* @return true if the texture was (re)created
|
||||||
|
*/
|
||||||
|
public boolean tryCreateOrResize()
|
||||||
|
{
|
||||||
|
boolean textureChanged = this.tryCreateTexture();
|
||||||
|
this.tryCreateSampler();
|
||||||
|
return textureChanged;
|
||||||
|
}
|
||||||
|
private boolean tryCreateTexture()
|
||||||
|
{
|
||||||
|
int viewWidth = MC_RENDER.getTargetFramebufferViewportWidth();
|
||||||
|
int viewHeight = MC_RENDER.getTargetFramebufferViewportHeight();
|
||||||
|
|
||||||
|
if (this.texture != null
|
||||||
|
&& this.width == viewWidth
|
||||||
|
&& this.height == viewHeight)
|
||||||
|
{
|
||||||
|
// no changes needed
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (this.texture != null)
|
||||||
|
{
|
||||||
|
this.texture.close();
|
||||||
|
this.textureView.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.width = viewWidth;
|
||||||
|
this.height = viewHeight;
|
||||||
|
|
||||||
|
int usage = GpuTexture.USAGE_COPY_DST
|
||||||
|
| GpuTexture.USAGE_TEXTURE_BINDING
|
||||||
|
| GpuTexture.USAGE_COPY_SRC
|
||||||
|
| GpuTexture.USAGE_RENDER_ATTACHMENT;
|
||||||
|
|
||||||
|
this.texture = GPU_DEVICE.createTexture(
|
||||||
|
this.name,
|
||||||
|
usage,
|
||||||
|
this.textureFormat,
|
||||||
|
viewWidth, viewHeight,
|
||||||
|
/*depthOrLayers*/ 1, /*mipLevels*/ 1
|
||||||
|
);
|
||||||
|
this.textureView = GPU_DEVICE.createTextureView(this.texture);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
private void tryCreateSampler()
|
||||||
|
{
|
||||||
|
if (this.textureSampler == null)
|
||||||
|
{
|
||||||
|
this.textureSampler = GPU_DEVICE.createSampler(
|
||||||
|
AddressMode.CLAMP_TO_EDGE, AddressMode.CLAMP_TO_EDGE, // U,V
|
||||||
|
FilterMode.LINEAR, FilterMode.LINEAR, // minFilter, magFilter
|
||||||
|
1, // maxAnisotropy
|
||||||
|
OptionalDouble.empty() // maxLod
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//==========//
|
||||||
|
// clearing //
|
||||||
|
//==========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will throw an exception if not a color texture.
|
||||||
|
* @see ColorUtil#argbToInt
|
||||||
|
*/
|
||||||
|
public void clearColor(int clearArgbColor)
|
||||||
|
{
|
||||||
|
if (this.texture != null)
|
||||||
|
{
|
||||||
|
#if MC_VER <= MC_26_1_2
|
||||||
|
COMMAND_ENCODER.clearColorTexture(this.texture, clearArgbColor);
|
||||||
|
#else
|
||||||
|
Vector4f clearColor = new Vector4f(
|
||||||
|
// color values should be between 0.0 and 1.0
|
||||||
|
ColorUtil.getRed(clearArgbColor) / 255.0f,
|
||||||
|
ColorUtil.getGreen(clearArgbColor) / 255.0f,
|
||||||
|
ColorUtil.getBlue(clearArgbColor) / 255.0f,
|
||||||
|
ColorUtil.getAlpha(clearArgbColor) / 255.0f
|
||||||
|
);
|
||||||
|
COMMAND_ENCODER.clearColorTexture(this.texture, clearColor);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Will throw an exception if not a depth texture. */
|
||||||
|
public void clearDepth(float depth)
|
||||||
|
{
|
||||||
|
if (this.texture != null)
|
||||||
|
{
|
||||||
|
COMMAND_ENCODER.clearDepthTexture(this.texture, depth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
package com.seibel.distanthorizons.common.render.blaze.wrappers.texture;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_21_10
|
||||||
|
public interface IDhBlazeTexture {}
|
||||||
|
#else
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.textures.GpuSampler;
|
||||||
|
import com.mojang.blaze3d.textures.GpuTextureView;
|
||||||
|
|
||||||
|
public interface IDhBlazeTexture
|
||||||
|
{
|
||||||
|
|
||||||
|
GpuTextureView getTextureView();
|
||||||
|
GpuSampler getTextureSampler();
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+61
@@ -0,0 +1,61 @@
|
|||||||
|
package com.seibel.distanthorizons.common.render.blaze.wrappers.uniform;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_21_10
|
||||||
|
public class BlazeLodUniformBufferWrapper {}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodBufferContainer;
|
||||||
|
import com.seibel.distanthorizons.core.util.math.Vec3f;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.ILodContainerUniformBufferWrapper;
|
||||||
|
|
||||||
|
public class BlazeLodUniformBufferWrapper extends BlazeUniformBufferWrapper implements ILodContainerUniformBufferWrapper
|
||||||
|
{
|
||||||
|
|
||||||
|
private boolean uploaded = false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public BlazeLodUniformBufferWrapper() { super(BlazeLodUniformBufferWrapper.class.getName()); }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//========//
|
||||||
|
// upload //
|
||||||
|
//========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tryUpload(LodBufferContainer bufferContainer)
|
||||||
|
{
|
||||||
|
if (this.uploaded)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3f modelOffset = new Vec3f(
|
||||||
|
(float) (bufferContainer.minCornerBlockPos.getX()),
|
||||||
|
(float) (bufferContainer.minCornerBlockPos.getY()),
|
||||||
|
(float) (bufferContainer.minCornerBlockPos.getZ()));
|
||||||
|
|
||||||
|
// upload data //
|
||||||
|
this
|
||||||
|
.putVec3f(modelOffset.x, modelOffset.y, modelOffset.z) // uModelOffset
|
||||||
|
.finishAndUpload();
|
||||||
|
|
||||||
|
this.uploaded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+244
@@ -0,0 +1,244 @@
|
|||||||
|
package com.seibel.distanthorizons.common.render.blaze.wrappers.uniform;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_21_10
|
||||||
|
public class BlazeUniformBufferWrapper {}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.buffers.GpuBuffer;
|
||||||
|
import com.mojang.blaze3d.buffers.GpuBufferSlice;
|
||||||
|
import com.mojang.blaze3d.buffers.Std140Builder;
|
||||||
|
import com.mojang.blaze3d.buffers.Std140SizeCalculator;
|
||||||
|
import com.mojang.blaze3d.systems.CommandEncoder;
|
||||||
|
import com.mojang.blaze3d.systems.GpuDevice;
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
import com.seibel.distanthorizons.api.objects.math.DhApiMat4f;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.util.BlazeUniformUtil;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import com.seibel.distanthorizons.core.util.math.Mat4f;
|
||||||
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class BlazeUniformBufferWrapper implements AutoCloseable
|
||||||
|
{
|
||||||
|
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
|
|
||||||
|
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
|
||||||
|
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
|
||||||
|
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
/** measured in bytes */
|
||||||
|
private int bufferSize = 0;
|
||||||
|
|
||||||
|
private ByteBuffer cpuBuffer = null;
|
||||||
|
|
||||||
|
private GpuBuffer gpuBuffer = null;
|
||||||
|
public GpuBuffer getGpuBuffer() { return this.gpuBuffer; }
|
||||||
|
private GpuBufferSlice bufferSlice = null;
|
||||||
|
|
||||||
|
/** the element count the current CPU Buffer is sized for */
|
||||||
|
private int previousElementCount = 0;
|
||||||
|
/** how many elements are currently in flight (ie being added to the buffer right now) */
|
||||||
|
private int elementCount = 0;
|
||||||
|
/** used to resize the buffers dur first-time setup */
|
||||||
|
private final ArrayList<EUniformElement> uniformElementTypes = new ArrayList<>(0);
|
||||||
|
private Std140Builder uniformBufferBuilder = null;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public BlazeUniformBufferWrapper(String name) { this.name = name; }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=================//
|
||||||
|
// element builder //
|
||||||
|
//=================//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public BlazeUniformBufferWrapper putVec2f(float x, float y)
|
||||||
|
{
|
||||||
|
this.putElement(EUniformElement.VEC2f);
|
||||||
|
this.uniformBufferBuilder.putVec2(x,y);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public BlazeUniformBufferWrapper putVec3i(int x, int y, int z)
|
||||||
|
{
|
||||||
|
this.putElement(EUniformElement.VEC3i);
|
||||||
|
this.uniformBufferBuilder.putIVec3(x,y,z);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public BlazeUniformBufferWrapper putVec3f(float x, float y, float z)
|
||||||
|
{
|
||||||
|
this.putElement(EUniformElement.VEC3f);
|
||||||
|
this.uniformBufferBuilder.putVec3(x,y,z);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public BlazeUniformBufferWrapper putVec4f(float x, float y, float z, float w)
|
||||||
|
{
|
||||||
|
this.putElement(EUniformElement.VEC4f);
|
||||||
|
this.uniformBufferBuilder.putVec4(x,y,z,w);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public BlazeUniformBufferWrapper putMat4f(DhApiMat4f matrix)
|
||||||
|
{
|
||||||
|
this.putElement(EUniformElement.MAT4f);
|
||||||
|
this.uniformBufferBuilder.putMat4f(Mat4f.createJomlMatrix(matrix));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public BlazeUniformBufferWrapper putFloat(float f)
|
||||||
|
{
|
||||||
|
this.putElement(EUniformElement.FLOAT);
|
||||||
|
this.uniformBufferBuilder.putFloat(f);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public BlazeUniformBufferWrapper putInt(int i)
|
||||||
|
{
|
||||||
|
this.putElement(EUniformElement.INT);
|
||||||
|
this.uniformBufferBuilder.putInt(i);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
private void putElement(EUniformElement elementTypeEnum)
|
||||||
|
{
|
||||||
|
this.uniformElementTypes.add(elementTypeEnum);
|
||||||
|
|
||||||
|
boolean createNewBuilder = (this.elementCount == 0);
|
||||||
|
this.elementCount++;
|
||||||
|
if (this.elementCount > this.previousElementCount)
|
||||||
|
{
|
||||||
|
this.recreateCpuBuffer();
|
||||||
|
createNewBuilder = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (createNewBuilder)
|
||||||
|
{
|
||||||
|
this.uniformBufferBuilder = Std140Builder.intoBuffer(this.cpuBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void recreateCpuBuffer()
|
||||||
|
{
|
||||||
|
ByteBuffer oldBuffer = this.cpuBuffer;
|
||||||
|
|
||||||
|
int size = calcBufferSize(this.uniformElementTypes);
|
||||||
|
this.cpuBuffer = MemoryUtil.memAlloc(size);
|
||||||
|
this.cpuBuffer.order(ByteOrder.nativeOrder());
|
||||||
|
|
||||||
|
if (oldBuffer != null)
|
||||||
|
{
|
||||||
|
oldBuffer.position(0);
|
||||||
|
this.cpuBuffer.put(oldBuffer);
|
||||||
|
MemoryUtil.memFree(oldBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.bufferSize = size;
|
||||||
|
this.previousElementCount = this.elementCount;
|
||||||
|
}
|
||||||
|
private static int calcBufferSize(ArrayList<EUniformElement> uniformElements)
|
||||||
|
{
|
||||||
|
Std140SizeCalculator calculator = new Std140SizeCalculator();
|
||||||
|
|
||||||
|
for (int i = 0; i < uniformElements.size(); i++)
|
||||||
|
{
|
||||||
|
EUniformElement element = uniformElements.get(i);
|
||||||
|
switch (element)
|
||||||
|
{
|
||||||
|
case VEC2f -> calculator.putVec2();
|
||||||
|
case VEC3i -> calculator.putIVec3();
|
||||||
|
case VEC3f -> calculator.putVec3();
|
||||||
|
case VEC4f -> calculator.putVec4();
|
||||||
|
case MAT4f -> calculator.putMat4f();
|
||||||
|
case INT -> calculator.putInt();
|
||||||
|
case FLOAT -> calculator.putFloat();
|
||||||
|
|
||||||
|
default -> throw new UnsupportedOperationException("No definition for element type ["+element.name()+"]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return calculator.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public void finishAndUpload()
|
||||||
|
{
|
||||||
|
// re-create the GPU buffer if needed
|
||||||
|
GpuBuffer oldGpuBuffer = this.gpuBuffer;
|
||||||
|
this.gpuBuffer = BlazeUniformUtil.createBuffer(this.name, this.bufferSize, this.gpuBuffer);
|
||||||
|
|
||||||
|
boolean createNewBufferSlice = (this.bufferSlice == null || this.gpuBuffer != oldGpuBuffer);
|
||||||
|
if (createNewBufferSlice)
|
||||||
|
{
|
||||||
|
this.bufferSlice = new GpuBufferSlice(this.gpuBuffer, 0, this.bufferSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
// upload to GPU
|
||||||
|
this.cpuBuffer.position(0);
|
||||||
|
COMMAND_ENCODER.writeToBuffer(this.bufferSlice, this.cpuBuffer);
|
||||||
|
|
||||||
|
|
||||||
|
// clear the element tracking for next time
|
||||||
|
this.elementCount = 0;
|
||||||
|
this.uniformElementTypes.clear();
|
||||||
|
this.uniformBufferBuilder = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// base overrides //
|
||||||
|
//================//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close()
|
||||||
|
{
|
||||||
|
if (this.gpuBuffer != null)
|
||||||
|
{
|
||||||
|
this.gpuBuffer.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.cpuBuffer != null)
|
||||||
|
{
|
||||||
|
MemoryUtil.memFree(this.cpuBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// helper classes //
|
||||||
|
//================//
|
||||||
|
//region
|
||||||
|
|
||||||
|
private enum EUniformElement
|
||||||
|
{
|
||||||
|
VEC2f,
|
||||||
|
VEC3f,
|
||||||
|
VEC3i,
|
||||||
|
VEC4f,
|
||||||
|
MAT4f,
|
||||||
|
INT,
|
||||||
|
FLOAT,
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+197
@@ -0,0 +1,197 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Distant Horizons mod
|
||||||
|
* licensed under the GNU LGPL v3 License.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 James Seibel
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.distanthorizons.common.render.openGl;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.buffer.GLIndexBuffer;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.buffer.GLVertexBuffer;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.shader.GlShaderProgram;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.vertexAttribute.GlAbstractVertexAttribute;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.vertexAttribute.GlVertexPointer;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import com.seibel.distanthorizons.core.render.RenderParams;
|
||||||
|
import com.seibel.distanthorizons.core.render.renderer.AbstractDebugWireframeRenderer;
|
||||||
|
import com.seibel.distanthorizons.core.util.math.Mat4f;
|
||||||
|
import org.lwjgl.opengl.GL32;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles rendering the wireframe particles
|
||||||
|
* that are used for seeing what the system's doing.
|
||||||
|
*/
|
||||||
|
public class GlDhDebugWireframeRenderer extends AbstractDebugWireframeRenderer
|
||||||
|
{
|
||||||
|
public static GlDhDebugWireframeRenderer INSTANCE = new GlDhDebugWireframeRenderer();
|
||||||
|
|
||||||
|
public static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
|
|
||||||
|
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// rendering setup
|
||||||
|
private GlShaderProgram basicShader;
|
||||||
|
private GLVertexBuffer vertexBuffer;
|
||||||
|
private GLIndexBuffer indexBuffer;
|
||||||
|
private GlAbstractVertexAttribute va;
|
||||||
|
private boolean init = false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** A box from 0,0,0 to 1,1,1 */
|
||||||
|
private static final float[] BOX_VERTICES = {
|
||||||
|
//region
|
||||||
|
// Pos x y z
|
||||||
|
0, 0, 0,
|
||||||
|
1, 0, 0,
|
||||||
|
1, 1, 0,
|
||||||
|
0, 1, 0,
|
||||||
|
0, 0, 1,
|
||||||
|
1, 0, 1,
|
||||||
|
1, 1, 1,
|
||||||
|
0, 1, 1,
|
||||||
|
//endregion
|
||||||
|
};
|
||||||
|
|
||||||
|
private static final int[] BOX_OUTLINE_INDICES = {
|
||||||
|
//region
|
||||||
|
0, 1,
|
||||||
|
1, 2,
|
||||||
|
2, 3,
|
||||||
|
3, 0,
|
||||||
|
|
||||||
|
4, 5,
|
||||||
|
5, 6,
|
||||||
|
6, 7,
|
||||||
|
7, 4,
|
||||||
|
|
||||||
|
0, 4,
|
||||||
|
1, 5,
|
||||||
|
2, 6,
|
||||||
|
3, 7,
|
||||||
|
//endregion
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
private GlDhDebugWireframeRenderer() { }
|
||||||
|
|
||||||
|
public void init()
|
||||||
|
{
|
||||||
|
if (this.init)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.init = true;
|
||||||
|
|
||||||
|
this.va = GlAbstractVertexAttribute.create();
|
||||||
|
this.va.bind();
|
||||||
|
// Pos
|
||||||
|
this.va.setVertexAttribute(0, 0, GlVertexPointer.addVec3Pointer(false));
|
||||||
|
this.va.completeAndCheck(Float.BYTES * 3);
|
||||||
|
this.basicShader = new GlShaderProgram(
|
||||||
|
"assets/distanthorizons/shaders/debug/gl/vert.vert",
|
||||||
|
"assets/distanthorizons/shaders/debug/gl/frag.frag",
|
||||||
|
"vPosition"
|
||||||
|
);
|
||||||
|
this.createBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createBuffer()
|
||||||
|
{
|
||||||
|
// box vertices
|
||||||
|
ByteBuffer boxVerticesBuffer = ByteBuffer.allocateDirect(BOX_VERTICES.length * Float.BYTES);
|
||||||
|
boxVerticesBuffer.order(ByteOrder.nativeOrder());
|
||||||
|
boxVerticesBuffer.asFloatBuffer().put(BOX_VERTICES);
|
||||||
|
boxVerticesBuffer.rewind();
|
||||||
|
this.vertexBuffer = new GLVertexBuffer(false);
|
||||||
|
this.vertexBuffer.bind();
|
||||||
|
this.vertexBuffer.uploadBuffer(boxVerticesBuffer, 8, EDhApiGpuUploadMethod.DATA, BOX_VERTICES.length * Float.BYTES);
|
||||||
|
|
||||||
|
|
||||||
|
// outline vertex indexes
|
||||||
|
ByteBuffer boxOutlineBuffer = ByteBuffer.allocateDirect(BOX_OUTLINE_INDICES.length * Integer.BYTES);
|
||||||
|
boxOutlineBuffer.order(ByteOrder.nativeOrder());
|
||||||
|
boxOutlineBuffer.asIntBuffer().put(BOX_OUTLINE_INDICES);
|
||||||
|
boxOutlineBuffer.rewind();
|
||||||
|
this.indexBuffer = new GLIndexBuffer(false);
|
||||||
|
this.indexBuffer.uploadBuffer(boxOutlineBuffer, EDhApiGpuUploadMethod.DATA, BOX_OUTLINE_INDICES.length * Integer.BYTES, GL32.GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//===========//
|
||||||
|
// rendering //
|
||||||
|
//===========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(RenderParams renderParams)
|
||||||
|
{
|
||||||
|
this.init();
|
||||||
|
|
||||||
|
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_LINE);
|
||||||
|
GLMC.enableDepthTest();
|
||||||
|
|
||||||
|
this.basicShader.bind();
|
||||||
|
this.va.bind();
|
||||||
|
this.va.bindBufferToAllBindingPoints(this.vertexBuffer.getId());
|
||||||
|
|
||||||
|
this.indexBuffer.bind();
|
||||||
|
|
||||||
|
super.render(renderParams);
|
||||||
|
|
||||||
|
// revert to prevent issues with the following passes
|
||||||
|
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_FILL);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderBox(Box box)
|
||||||
|
{
|
||||||
|
Mat4f boxTransform = Mat4f.createTranslateMatrix(box.minPos.x - this.camPosFloatThisFrame.x, box.minPos.y - this.camPosFloatThisFrame.y, box.minPos.z - this.camPosFloatThisFrame.z);
|
||||||
|
boxTransform.multiply(Mat4f.createScaleMatrix(box.maxPos.x - box.minPos.x, box.maxPos.y - box.minPos.y, box.maxPos.z - box.minPos.z));
|
||||||
|
|
||||||
|
Mat4f transformMatrix = this.dhMvmProjMatrixThisFrame.copy();
|
||||||
|
transformMatrix.multiply(boxTransform);
|
||||||
|
this.basicShader.setUniform(this.basicShader.getUniformLocation("uTransform"), transformMatrix);
|
||||||
|
|
||||||
|
this.basicShader.setUniform(this.basicShader.getUniformLocation("uColor"), box.color);
|
||||||
|
|
||||||
|
GL32.glDrawElements(GL32.GL_LINES, BOX_OUTLINE_INDICES.length, GL32.GL_UNSIGNED_INT, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+465
@@ -0,0 +1,465 @@
|
|||||||
|
package com.seibel.distanthorizons.common.render.openGl;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.api.enums.rendering.EDhApiRenderPass;
|
||||||
|
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiFramebuffer;
|
||||||
|
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiShaderProgram;
|
||||||
|
import com.seibel.distanthorizons.api.methods.events.abstractEvents.*;
|
||||||
|
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
|
||||||
|
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiTextureCreatedParam;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.GLProxy;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.GlDhFramebuffer;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.texture.*;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.postProcessing.apply.GlDhApplyShader;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.misc.LightMapWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.config.Config;
|
||||||
|
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
|
||||||
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import com.seibel.distanthorizons.core.render.DhApiRenderProxy;
|
||||||
|
import com.seibel.distanthorizons.core.render.RenderParams;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.ILightMapWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IOptifineAccessor;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhMetaRenderer;
|
||||||
|
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
|
||||||
|
import com.seibel.distanthorizons.coreapi.DependencyInjection.OverrideInjector;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.lwjgl.opengl.GL32;
|
||||||
|
|
||||||
|
public class GlDhMetaRenderer implements IDhMetaRenderer
|
||||||
|
{
|
||||||
|
public static final DhLogger LOGGER = new DhLoggerBuilder()
|
||||||
|
.fileLevelConfig(Config.Common.Logging.logRendererEventToFile)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
public static final DhLogger RATE_LIMITED_LOGGER = new DhLoggerBuilder()
|
||||||
|
.fileLevelConfig(Config.Common.Logging.logRendererEventToFile)
|
||||||
|
.maxCountPerSecond(4)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
public static final GlDhMetaRenderer INSTANCE = new GlDhMetaRenderer();
|
||||||
|
|
||||||
|
|
||||||
|
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
|
||||||
|
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
|
||||||
|
|
||||||
|
private static final IOptifineAccessor OPTIFINE_ACCESSOR = ModAccessorInjector.INSTANCE.get(IOptifineAccessor.class);
|
||||||
|
|
||||||
|
|
||||||
|
private int activeFramebufferId = -1;
|
||||||
|
private int activeColorTextureId = -1;
|
||||||
|
private int activeDepthTextureId = -1;
|
||||||
|
private int textureWidth;
|
||||||
|
private int textureHeight;
|
||||||
|
|
||||||
|
|
||||||
|
// framebuffer and texture ID's for this renderer
|
||||||
|
private IDhApiFramebuffer framebuffer;
|
||||||
|
/** will be null if MC's framebuffer is being used since MC already has a color texture */
|
||||||
|
@Nullable
|
||||||
|
private GlDhColorTexture nullableColorTexture;
|
||||||
|
private GlDhDepthTexture depthTexture;
|
||||||
|
/**
|
||||||
|
* If true the {@link GlDhMetaRenderer#framebuffer} is the same as MC's.
|
||||||
|
* This should only be true in the case of Optifine so LODs won't be overwritten when shaders are enabled.
|
||||||
|
*/
|
||||||
|
private boolean usingMcFramebuffer = false;
|
||||||
|
|
||||||
|
private boolean renderObjectsCreated = false;
|
||||||
|
/** used in case there's an API override */
|
||||||
|
public IDhApiShaderProgram shaderProgramForThisFrame;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//============//
|
||||||
|
// pre render //
|
||||||
|
//============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void runRenderPassSetup(RenderParams renderParams)
|
||||||
|
{
|
||||||
|
boolean firstPass =
|
||||||
|
(renderParams.renderPass == EDhApiRenderPass.OPAQUE
|
||||||
|
|| renderParams.renderPass == EDhApiRenderPass.OPAQUE_AND_TRANSPARENT);
|
||||||
|
|
||||||
|
if (!this.renderObjectsCreated)
|
||||||
|
{
|
||||||
|
boolean setupSuccess = this.createRenderObjects();
|
||||||
|
if (!setupSuccess)
|
||||||
|
{
|
||||||
|
// shouldn't normally happen, but just in case
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.renderObjectsCreated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.shaderProgramForThisFrame = GlDhTerrainRenderer.INSTANCE.getTerrainShaderProgram();
|
||||||
|
IDhApiShaderProgram lodShaderProgramOverride = OverrideInjector.INSTANCE.get(IDhApiShaderProgram.class);
|
||||||
|
if (lodShaderProgramOverride != null && this.shaderProgramForThisFrame.overrideThisFrame())
|
||||||
|
{
|
||||||
|
this.shaderProgramForThisFrame = lodShaderProgramOverride;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
this.setGLState(renderParams, firstPass);
|
||||||
|
|
||||||
|
this.bindLightmap(renderParams.lightmap);
|
||||||
|
}
|
||||||
|
private void setGLState(
|
||||||
|
DhApiRenderParam renderEventParam,
|
||||||
|
boolean firstPass)
|
||||||
|
{
|
||||||
|
//===================//
|
||||||
|
// framebuffer setup //
|
||||||
|
//===================//
|
||||||
|
|
||||||
|
// get the active framebuffer
|
||||||
|
IDhApiFramebuffer framebuffer = this.framebuffer;
|
||||||
|
IDhApiFramebuffer framebufferOverride = OverrideInjector.INSTANCE.get(IDhApiFramebuffer.class);
|
||||||
|
if (framebufferOverride != null && framebufferOverride.overrideThisFrame())
|
||||||
|
{
|
||||||
|
framebuffer = framebufferOverride;
|
||||||
|
}
|
||||||
|
this.setActiveFramebufferId(framebuffer.getId());
|
||||||
|
framebuffer.bind();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//==========//
|
||||||
|
// bindings //
|
||||||
|
//==========//
|
||||||
|
|
||||||
|
// by default draw everything as triangles
|
||||||
|
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_FILL);
|
||||||
|
GLMC.enableFaceCulling();
|
||||||
|
|
||||||
|
GLMC.glBlendFunc(GL32.GL_SRC_ALPHA, GL32.GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
GLMC.glBlendFuncSeparate(GL32.GL_SRC_ALPHA, GL32.GL_ONE_MINUS_SRC_ALPHA, GL32.GL_ONE, GL32.GL_ZERO);
|
||||||
|
|
||||||
|
GL32.glDisable(GL32.GL_SCISSOR_TEST);
|
||||||
|
|
||||||
|
// Enable depth test and depth mask
|
||||||
|
GLMC.enableDepthTest();
|
||||||
|
GLMC.glDepthFunc(GL32.GL_LESS);
|
||||||
|
GLMC.enableDepthMask();
|
||||||
|
|
||||||
|
// This is required for MC versions 1.21.5+
|
||||||
|
// due to MC updating the lightmap by changing the viewport size
|
||||||
|
GL32.glViewport(0, 0, this.textureWidth, this.textureHeight);
|
||||||
|
|
||||||
|
this.shaderProgramForThisFrame.bind();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//==========//
|
||||||
|
// uniforms //
|
||||||
|
//==========//
|
||||||
|
|
||||||
|
IDhApiShaderProgram shaderProgramOverride = OverrideInjector.INSTANCE.get(IDhApiShaderProgram.class);
|
||||||
|
if (shaderProgramOverride != null)
|
||||||
|
{
|
||||||
|
shaderProgramOverride.fillUniformData(renderEventParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.shaderProgramForThisFrame.fillUniformData(renderEventParam);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//===============//
|
||||||
|
// texture setup //
|
||||||
|
//===============//
|
||||||
|
|
||||||
|
// resize the textures if needed
|
||||||
|
if (MC_RENDER.getTargetFramebufferViewportWidth() != this.textureWidth
|
||||||
|
|| MC_RENDER.getTargetFramebufferViewportHeight() != this.textureHeight)
|
||||||
|
{
|
||||||
|
// just resizing the textures doesn't work when Optifine is present,
|
||||||
|
// so recreate the textures with the new size instead
|
||||||
|
this.createAndBindTextures();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// set the active textures
|
||||||
|
int depthTextureId = this.depthTexture.getTextureId();
|
||||||
|
this.setActiveDepthTextureId(depthTextureId);
|
||||||
|
|
||||||
|
if (this.nullableColorTexture != null)
|
||||||
|
{
|
||||||
|
int colorTextureId = this.nullableColorTexture.getTextureId();
|
||||||
|
this.setActiveColorTextureId(colorTextureId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// get MC's color texture
|
||||||
|
int colorTextureId = GL32.glGetFramebufferAttachmentParameteri(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
|
||||||
|
this.setActiveColorTextureId(colorTextureId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// needs to be fired after all the textures have been created/bound
|
||||||
|
boolean clearTextures = !ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeTextureClearEvent.class, renderEventParam);
|
||||||
|
if (clearTextures)
|
||||||
|
{
|
||||||
|
GL32.glClearDepth(1.0);
|
||||||
|
|
||||||
|
float[] clearColorValues = new float[4];
|
||||||
|
GL32.glGetFloatv(GL32.GL_COLOR_CLEAR_VALUE, clearColorValues);
|
||||||
|
GL32.glClearColor(clearColorValues[0], clearColorValues[1], clearColorValues[2], 1.0f);
|
||||||
|
|
||||||
|
if (this.usingMcFramebuffer && framebufferOverride == null)
|
||||||
|
{
|
||||||
|
// Due to using MC/Optifine's framebuffer we need to re-bind the depth texture,
|
||||||
|
// otherwise we'll be writing to MC/Optifine's depth texture which causes rendering issues
|
||||||
|
framebuffer.addDepthAttachment(this.depthTexture.getTextureId(), EGlDhDepthBufferFormat.DEPTH32F.isCombinedStencil());
|
||||||
|
|
||||||
|
|
||||||
|
// don't clear the color texture, that removes the sky
|
||||||
|
GL32.glClear(GL32.GL_DEPTH_BUFFER_BIT);
|
||||||
|
}
|
||||||
|
else if (firstPass)
|
||||||
|
{
|
||||||
|
GL32.glClear(GL32.GL_COLOR_BUFFER_BIT | GL32.GL_DEPTH_BUFFER_BIT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean createRenderObjects()
|
||||||
|
{
|
||||||
|
if (this.renderObjectsCreated)
|
||||||
|
{
|
||||||
|
LOGGER.warn("Renderer setup called but it has already completed setup!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// GLProxy should have already been created by this point, but just in case create it now
|
||||||
|
GLProxy.getInstance();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
LOGGER.info("Setting up renderer");
|
||||||
|
|
||||||
|
|
||||||
|
// create or get the frame buffer
|
||||||
|
if (OPTIFINE_ACCESSOR != null)
|
||||||
|
{
|
||||||
|
// use MC/Optifine's default Framebuffer so shaders won't remove the LODs
|
||||||
|
int currentFramebufferId = MC_RENDER.getTargetFramebuffer();
|
||||||
|
this.framebuffer = new GlDhFramebuffer(currentFramebufferId);
|
||||||
|
this.usingMcFramebuffer = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// normal use case
|
||||||
|
this.framebuffer = new GlDhFramebuffer();
|
||||||
|
this.usingMcFramebuffer = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create and bind the necessary textures
|
||||||
|
this.createAndBindTextures();
|
||||||
|
|
||||||
|
if(this.framebuffer.getStatus() != GL32.GL_FRAMEBUFFER_COMPLETE)
|
||||||
|
{
|
||||||
|
// This generally means something wasn't bound, IE missing either the color or depth texture
|
||||||
|
LOGGER.warn("Framebuffer ["+this.framebuffer.getId()+"] isn't complete.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
LOGGER.info("Renderer setup complete");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings( "deprecation" ) // done to ignore DhApiColorDepthTextureCreatedEvent
|
||||||
|
private void createAndBindTextures()
|
||||||
|
{
|
||||||
|
int oldWidth = this.textureWidth;
|
||||||
|
int oldHeight = this.textureHeight;
|
||||||
|
this.textureWidth = MC_RENDER.getTargetFramebufferViewportWidth();
|
||||||
|
this.textureHeight = MC_RENDER.getTargetFramebufferViewportHeight();
|
||||||
|
|
||||||
|
DhApiTextureCreatedParam textureCreatedParam = new DhApiTextureCreatedParam(
|
||||||
|
oldWidth, oldHeight,
|
||||||
|
this.textureWidth, this.textureHeight
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// DhApiColorDepthTextureCreatedEvent needs to be kept around since old versions of Iris need it
|
||||||
|
ApiEventInjector.INSTANCE.fireAllEvents(DhApiColorDepthTextureCreatedEvent.class, new DhApiColorDepthTextureCreatedEvent.EventParam(textureCreatedParam));
|
||||||
|
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeColorDepthTextureCreatedEvent.class, textureCreatedParam);
|
||||||
|
|
||||||
|
|
||||||
|
// also update the framebuffer override if present
|
||||||
|
IDhApiFramebuffer framebufferOverride = OverrideInjector.INSTANCE.get(IDhApiFramebuffer.class);
|
||||||
|
|
||||||
|
|
||||||
|
this.depthTexture = new GlDhDepthTexture(this.textureWidth, this.textureHeight, EGlDhDepthBufferFormat.DEPTH32F);
|
||||||
|
this.framebuffer.addDepthAttachment(this.depthTexture.getTextureId(), EGlDhDepthBufferFormat.DEPTH32F.isCombinedStencil());
|
||||||
|
if (framebufferOverride != null)
|
||||||
|
{
|
||||||
|
framebufferOverride.addDepthAttachment(this.depthTexture.getTextureId(), EGlDhDepthBufferFormat.DEPTH32F.isCombinedStencil());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// if we are using MC's frame buffer, a color texture is already present and shouldn't need to be bound
|
||||||
|
if (!this.usingMcFramebuffer)
|
||||||
|
{
|
||||||
|
this.nullableColorTexture = GlDhColorTexture.builder()
|
||||||
|
.setDimensions(this.textureWidth, this.textureHeight)
|
||||||
|
.setInternalFormat(EGlDhInternalTextureFormat.RGBA8)
|
||||||
|
.setPixelType(EGlDhPixelType.UNSIGNED_BYTE)
|
||||||
|
.setPixelFormat(EGlDhPixelFormat.RGBA)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
this.framebuffer.addColorAttachment(0, this.nullableColorTexture.getTextureId());
|
||||||
|
if (framebufferOverride != null)
|
||||||
|
{
|
||||||
|
framebufferOverride.addColorAttachment(0, this.nullableColorTexture.getTextureId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.nullableColorTexture = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ApiEventInjector.INSTANCE.fireAllEvents(DhApiAfterColorDepthTextureCreatedEvent.class, textureCreatedParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// post render //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void runRenderPassCleanup(RenderParams renderParams)
|
||||||
|
{
|
||||||
|
boolean runningDeferredPass = (renderParams.renderPass == EDhApiRenderPass.TRANSPARENT);
|
||||||
|
if (!runningDeferredPass)
|
||||||
|
{
|
||||||
|
//===================//
|
||||||
|
// optifine clean up //
|
||||||
|
//===================//
|
||||||
|
|
||||||
|
if (this.usingMcFramebuffer)
|
||||||
|
{
|
||||||
|
// If MC's framebuffer is being used the depth needs to be cleared to prevent rendering on top of MC.
|
||||||
|
// This should only happen when Optifine shaders are being used.
|
||||||
|
GL32.glClear(GL32.GL_DEPTH_BUFFER_BIT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
this.unbindLightmap();
|
||||||
|
this.shaderProgramForThisFrame.unbind();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void applyToMcTexture(RenderParams renderParams) { GlDhApplyShader.INSTANCE.render(renderParams); }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// clear textures //
|
||||||
|
//================//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearDhDepthAndColorTextures(RenderParams renderParams)
|
||||||
|
{
|
||||||
|
IDhApiFramebuffer framebufferOverride = OverrideInjector.INSTANCE.get(IDhApiFramebuffer.class);
|
||||||
|
|
||||||
|
boolean firstPass =
|
||||||
|
(renderParams.renderPass == EDhApiRenderPass.OPAQUE
|
||||||
|
|| renderParams.renderPass == EDhApiRenderPass.OPAQUE_AND_TRANSPARENT);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
GL32.glClearDepth(1.0);
|
||||||
|
|
||||||
|
float[] clearColorValues = new float[4];
|
||||||
|
GL32.glGetFloatv(GL32.GL_COLOR_CLEAR_VALUE, clearColorValues);
|
||||||
|
GL32.glClearColor(clearColorValues[0], clearColorValues[1], clearColorValues[2], 1.0f);
|
||||||
|
|
||||||
|
if (this.usingMcFramebuffer
|
||||||
|
&& framebufferOverride == null)
|
||||||
|
{
|
||||||
|
//// Due to using MC/Optifine's framebuffer we need to re-bind the depth texture,
|
||||||
|
//// otherwise we'll be writing to MC/Optifine's depth texture which causes rendering issues
|
||||||
|
//this.framebuffer.addDepthAttachment(this.depthTexture.getTextureId(), EDhDepthBufferFormat.DEPTH32F.isCombinedStencil());
|
||||||
|
|
||||||
|
|
||||||
|
// don't clear the color texture, that removes the sky
|
||||||
|
GL32.glClear(GL32.GL_DEPTH_BUFFER_BIT);
|
||||||
|
}
|
||||||
|
else if (firstPass)
|
||||||
|
{
|
||||||
|
GL32.glClear(GL32.GL_COLOR_BUFFER_BIT | GL32.GL_DEPTH_BUFFER_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//===============//
|
||||||
|
// API functions //
|
||||||
|
//===============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public void setActiveFramebufferId(int id) { this.activeFramebufferId = id; }
|
||||||
|
/** @return -1 if no frame buffer has been bound yet */
|
||||||
|
public int getActiveFramebufferId() { return this.activeFramebufferId; }
|
||||||
|
|
||||||
|
public void setActiveColorTextureId(int id)
|
||||||
|
{
|
||||||
|
this.activeColorTextureId = id;
|
||||||
|
DhApiRenderProxy.activeOpenGlDhColorTextureId = id;
|
||||||
|
}
|
||||||
|
/** @return -1 if no texture has been bound yet */
|
||||||
|
public int getActiveColorTextureId() { return this.activeColorTextureId; }
|
||||||
|
|
||||||
|
public void setActiveDepthTextureId(int id)
|
||||||
|
{
|
||||||
|
this.activeDepthTextureId = id;
|
||||||
|
DhApiRenderProxy.activeOpenGlDhDepthTextureId = id;
|
||||||
|
}
|
||||||
|
/** @return -1 if no texture has been bound yet */
|
||||||
|
public int getActiveDepthTextureId() { return this.activeDepthTextureId; }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// helper methods //
|
||||||
|
//================//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public void bindLightmap(ILightMapWrapper lightMapWrapper)
|
||||||
|
{
|
||||||
|
LightMapWrapper lightMap = (LightMapWrapper)lightMapWrapper;
|
||||||
|
GLMC.glActiveTexture(GL32.GL_TEXTURE0 + LightMapWrapper.GL_BOUND_INDEX);
|
||||||
|
GLMC.glBindTexture(lightMap.getOpenGlId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unbindLightmap()
|
||||||
|
{
|
||||||
|
// strange that we don't call "glActiveTexture" here but since it's working James isn't going to change it right now (2026-03-10)
|
||||||
|
GLMC.glBindTexture(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+79
@@ -0,0 +1,79 @@
|
|||||||
|
package com.seibel.distanthorizons.common.render.openGl;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderingApi;
|
||||||
|
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderingEngine;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.generic.GlGenericObjectRenderer;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.generic.GlGenericObjectVertexContainer;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.GlDummyUniformData;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.buffer.GLVertexBuffer;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.postProcessing.fade.GlDhFarFadeRenderer;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.postProcessing.fade.GlVanillaFadeRenderer;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.postProcessing.fog.GlDhFogRenderer;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.postProcessing.ssao.GlDhSSAORenderer;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.test.GlTestTriangleRenderer;
|
||||||
|
import com.seibel.distanthorizons.core.render.EDhRenderDepth;
|
||||||
|
import com.seibel.distanthorizons.core.render.renderer.AbstractDebugWireframeRenderer;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IDhGenericObjectVertexBufferContainer;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.ILodContainerUniformBufferWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IVertexBufferWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.*;
|
||||||
|
|
||||||
|
public class GlDhRenderApiDefinition extends AbstractDhRenderApiDefinition
|
||||||
|
{
|
||||||
|
//=========//
|
||||||
|
// getters //
|
||||||
|
//=========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public String getApiName() { return "OpenGL"; }
|
||||||
|
|
||||||
|
public EDhRenderDepth getRenderDepth()
|
||||||
|
{
|
||||||
|
// reversed Z shouldn't be supported on OpenGL due
|
||||||
|
// to that breaking Iris shaders
|
||||||
|
return EDhRenderDepth.FORWARD_Z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EDhApiRenderingApi getRenderApi() { return EDhApiRenderingApi.OPEN_GL; }
|
||||||
|
public boolean isNativeRenderer() { return true; }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//============//
|
||||||
|
// singletons //
|
||||||
|
//============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override public IDhMetaRenderer getMetaRenderer() { return GlDhMetaRenderer.INSTANCE; }
|
||||||
|
@Override public IDhTerrainRenderer getTerrainRenderer() { return GlDhTerrainRenderer.INSTANCE; }
|
||||||
|
@Override public IDhSsaoRenderer getSsaoRenderer() { return GlDhSSAORenderer.INSTANCE; }
|
||||||
|
@Override public IDhFogRenderer getFogRenderer() { return GlDhFogRenderer.INSTANCE; }
|
||||||
|
@Override public IDhFarFadeRenderer getFarFadeRenderer() { return GlDhFarFadeRenderer.INSTANCE; }
|
||||||
|
@Override public AbstractDebugWireframeRenderer getDebugWireframeRenderer() { return GlDhDebugWireframeRenderer.INSTANCE; }
|
||||||
|
|
||||||
|
@Override public IDhVanillaFadeRenderer getVanillaFadeRenderer() { return GlVanillaFadeRenderer.INSTANCE; }
|
||||||
|
@Override public IDhTestTriangleRenderer getTestTriangleRenderer() { return GlTestTriangleRenderer.INSTANCE; }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//===========//
|
||||||
|
// factories //
|
||||||
|
//===========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override public IDhGenericRenderer createGenericRenderer() { return new GlGenericObjectRenderer(); }
|
||||||
|
|
||||||
|
@Override public IVertexBufferWrapper createVboWrapper(String name) { return new GLVertexBuffer(); }
|
||||||
|
@Override public ILodContainerUniformBufferWrapper createLodContainerUniformWrapper() { return new GlDummyUniformData(); }
|
||||||
|
@Override public IDhGenericObjectVertexBufferContainer createGenericVboContainer() { return new GlGenericObjectVertexContainer(); }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+67
@@ -0,0 +1,67 @@
|
|||||||
|
package com.seibel.distanthorizons.common.render.openGl;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.terrain.GlDhTerrainShaderProgram;
|
||||||
|
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodBufferContainer;
|
||||||
|
import com.seibel.distanthorizons.core.render.RenderParams;
|
||||||
|
import com.seibel.distanthorizons.core.util.objects.SortedArraySet;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IProfilerWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhTerrainRenderer;
|
||||||
|
|
||||||
|
public class GlDhTerrainRenderer implements IDhTerrainRenderer
|
||||||
|
{
|
||||||
|
public static final GlDhTerrainRenderer INSTANCE = new GlDhTerrainRenderer();
|
||||||
|
|
||||||
|
private GlDhTerrainShaderProgram terrainShaderProgram = null;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
private GlDhTerrainRenderer() {}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
//=========//
|
||||||
|
// getters //
|
||||||
|
//=========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
/** must be called on the render thread the first time so GL can run it's setup */
|
||||||
|
public GlDhTerrainShaderProgram getTerrainShaderProgram()
|
||||||
|
{
|
||||||
|
if (this.terrainShaderProgram == null)
|
||||||
|
{
|
||||||
|
this.terrainShaderProgram = new GlDhTerrainShaderProgram();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.terrainShaderProgram;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//========//
|
||||||
|
// render //
|
||||||
|
//========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(RenderParams renderEventParam, boolean opaquePass, SortedArraySet<LodBufferContainer> bufferContainers, IProfilerWrapper profiler)
|
||||||
|
{
|
||||||
|
this.getTerrainShaderProgram();
|
||||||
|
|
||||||
|
this.terrainShaderProgram.tryInit();
|
||||||
|
this.terrainShaderProgram.render(renderEventParam, opaquePass, bufferContainers, profiler);
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+776
@@ -0,0 +1,776 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Distant Horizons mod
|
||||||
|
* licensed under the GNU LGPL v3 License.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 James Seibel
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.distanthorizons.common.render.openGl.generic;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod;
|
||||||
|
import com.seibel.distanthorizons.api.enums.rendering.EDhApiBlockMaterial;
|
||||||
|
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiGenericObjectShaderProgram;
|
||||||
|
import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderableBoxGroup;
|
||||||
|
import com.seibel.distanthorizons.api.interfaces.render.IDhApiCustomRenderRegister;
|
||||||
|
import com.seibel.distanthorizons.api.methods.events.abstractEvents.*;
|
||||||
|
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
|
||||||
|
import com.seibel.distanthorizons.api.objects.math.DhApiVec3d;
|
||||||
|
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox;
|
||||||
|
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBoxGroupShading;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.GLProxy;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.buffer.GLIndexBuffer;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.buffer.GLVertexBuffer;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.config.Config;
|
||||||
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
|
import com.seibel.distanthorizons.core.jar.EPlatform;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import com.seibel.distanthorizons.core.logging.f3.F3Screen;
|
||||||
|
import com.seibel.distanthorizons.core.render.RenderParams;
|
||||||
|
import com.seibel.distanthorizons.core.render.renderer.GenericRenderObjectFactory;
|
||||||
|
import com.seibel.distanthorizons.core.render.renderer.RenderableBoxGroup;
|
||||||
|
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IProfilerWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.util.math.Vec3d;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhGenericRenderer;
|
||||||
|
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
|
||||||
|
import com.seibel.distanthorizons.coreapi.DependencyInjection.OverrideInjector;
|
||||||
|
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||||
|
import org.lwjgl.opengl.ARBInstancedArrays;
|
||||||
|
import org.lwjgl.opengl.GL32;
|
||||||
|
import org.lwjgl.opengl.GL33;
|
||||||
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles rendering generic groups of {@link DhApiRenderableBox}.
|
||||||
|
*
|
||||||
|
* @see IDhApiCustomRenderRegister
|
||||||
|
* @see DhApiRenderableBox
|
||||||
|
*/
|
||||||
|
public class GlGenericObjectRenderer implements IDhGenericRenderer
|
||||||
|
{
|
||||||
|
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
|
|
||||||
|
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
|
||||||
|
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
|
||||||
|
|
||||||
|
private static final DhApiRenderableBoxGroupShading DEFAULT_SHADING = DhApiRenderableBoxGroupShading.getUnshaded();
|
||||||
|
|
||||||
|
private static final DhApiBeforeGenericObjectRenderEvent.EventParam EVENT_PARAM = new DhApiBeforeGenericObjectRenderEvent.EventParam();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Can be used to troubleshoot the renderer.
|
||||||
|
* If enabled several debug objects will render around (0,150,0).
|
||||||
|
*/
|
||||||
|
public static final boolean RENDER_DEBUG_OBJECTS = false;
|
||||||
|
|
||||||
|
|
||||||
|
// rendering setup
|
||||||
|
private boolean init = false;
|
||||||
|
|
||||||
|
private IDhApiGenericObjectShaderProgram instancedShaderProgram;
|
||||||
|
private IDhApiGenericObjectShaderProgram directShaderProgram;
|
||||||
|
private GLVertexBuffer boxVertexBuffer;
|
||||||
|
private GLIndexBuffer boxIndexBuffer;
|
||||||
|
|
||||||
|
private boolean instancedRenderingAvailable;
|
||||||
|
private boolean vertexAttribDivisorSupported;
|
||||||
|
private boolean instancedArraysSupported;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private final ConcurrentHashMap<Long, RenderableBoxGroup> boxGroupById = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** A box from 0,0,0 to 1,1,1 */
|
||||||
|
private static final float[] BOX_VERTICES = {
|
||||||
|
//region
|
||||||
|
// Pos x y z
|
||||||
|
|
||||||
|
// min X, vertical face
|
||||||
|
0, 0, 0,
|
||||||
|
1, 0, 0,
|
||||||
|
1, 1, 0,
|
||||||
|
0, 1, 0,
|
||||||
|
// max X, vertical face
|
||||||
|
0, 1, 1,
|
||||||
|
1, 1, 1,
|
||||||
|
1, 0, 1,
|
||||||
|
0, 0, 1,
|
||||||
|
|
||||||
|
// min Z, vertical face
|
||||||
|
0, 0, 1,
|
||||||
|
0, 0, 0,
|
||||||
|
0, 1, 0,
|
||||||
|
0, 1, 1,
|
||||||
|
// max Z, vertical face
|
||||||
|
1, 0, 1,
|
||||||
|
1, 1, 1,
|
||||||
|
1, 1, 0,
|
||||||
|
1, 0, 0,
|
||||||
|
|
||||||
|
// min Y, horizontal face
|
||||||
|
0, 0, 1,
|
||||||
|
1, 0, 1,
|
||||||
|
1, 0, 0,
|
||||||
|
0, 0, 0,
|
||||||
|
// max Y, horizontal face
|
||||||
|
0, 1, 1,
|
||||||
|
1, 1, 1,
|
||||||
|
1, 1, 0,
|
||||||
|
0, 1, 0,
|
||||||
|
//endregion
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
private static final int[] BOX_INDICES = {
|
||||||
|
//region
|
||||||
|
// min X, vertical face
|
||||||
|
2, 1, 0,
|
||||||
|
0, 3, 2,
|
||||||
|
// max X, vertical face
|
||||||
|
6, 5, 4,
|
||||||
|
4, 7, 6,
|
||||||
|
|
||||||
|
// min Z, vertical face
|
||||||
|
10, 9, 8,
|
||||||
|
8, 11, 10,
|
||||||
|
// max Z, vertical face
|
||||||
|
14, 13, 12,
|
||||||
|
12, 15, 14,
|
||||||
|
|
||||||
|
// min Y, horizontal face
|
||||||
|
18, 17, 16,
|
||||||
|
16, 19, 18,
|
||||||
|
// max Y, horizontal face
|
||||||
|
20, 21, 22,
|
||||||
|
22, 23, 20,
|
||||||
|
//endregion
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public GlGenericObjectRenderer() { }
|
||||||
|
|
||||||
|
public void init()
|
||||||
|
{
|
||||||
|
if (this.init)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.init = true;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//===================================//
|
||||||
|
// is instanced rendering available? //
|
||||||
|
//===================================//
|
||||||
|
|
||||||
|
this.vertexAttribDivisorSupported = GLProxy.getInstance().vertexAttribDivisorSupported;
|
||||||
|
this.instancedArraysSupported = GLProxy.getInstance().instancedArraysSupported;
|
||||||
|
boolean isMac = (EPlatform.get() == EPlatform.MACOS);
|
||||||
|
if (isMac)
|
||||||
|
{
|
||||||
|
LOGGER.warn("Generic rendering not supported by Mac. Clouds, beacons, and some other effects will be disabled.");
|
||||||
|
Config.Client.Advanced.Graphics.GenericRendering.enableGenericRendering.setApiValue(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.instancedRenderingAvailable = (this.vertexAttribDivisorSupported || this.instancedArraysSupported) && !isMac;
|
||||||
|
if (!this.instancedRenderingAvailable)
|
||||||
|
{
|
||||||
|
LOGGER.warn("Instanced rendering not supported by this GPU, falling back to direct rendering. Generic object rendering will be slow and some effects may be disabled.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//======================//
|
||||||
|
// startup the renderer //
|
||||||
|
//======================//
|
||||||
|
|
||||||
|
this.instancedShaderProgram = new GlGenericObjectShaderProgram(true);
|
||||||
|
this.directShaderProgram = new GlGenericObjectShaderProgram(false);
|
||||||
|
|
||||||
|
this.createBuffers();
|
||||||
|
|
||||||
|
if (RENDER_DEBUG_OBJECTS)
|
||||||
|
{
|
||||||
|
this.addGenericDebugObjects();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void createBuffers()
|
||||||
|
{
|
||||||
|
// box vertices
|
||||||
|
ByteBuffer boxVerticesBuffer = MemoryUtil.memAlloc(BOX_VERTICES.length * Float.BYTES);
|
||||||
|
boxVerticesBuffer.asFloatBuffer().put(BOX_VERTICES);
|
||||||
|
boxVerticesBuffer.rewind();
|
||||||
|
this.boxVertexBuffer = new GLVertexBuffer(false);
|
||||||
|
this.boxVertexBuffer.bind();
|
||||||
|
this.boxVertexBuffer.uploadBuffer(boxVerticesBuffer, 8, EDhApiGpuUploadMethod.DATA, BOX_VERTICES.length * Float.BYTES);
|
||||||
|
MemoryUtil.memFree(boxVerticesBuffer);
|
||||||
|
|
||||||
|
// box vertex indexes
|
||||||
|
ByteBuffer solidIndexBuffer = MemoryUtil.memAlloc(BOX_INDICES.length * Integer.BYTES);
|
||||||
|
solidIndexBuffer.asIntBuffer().put(BOX_INDICES);
|
||||||
|
solidIndexBuffer.rewind();
|
||||||
|
this.boxIndexBuffer = new GLIndexBuffer(false);
|
||||||
|
this.boxIndexBuffer.uploadBuffer(solidIndexBuffer, EDhApiGpuUploadMethod.DATA, BOX_INDICES.length * Integer.BYTES, GL32.GL_STATIC_DRAW);
|
||||||
|
this.boxIndexBuffer.bind();
|
||||||
|
MemoryUtil.memFree(solidIndexBuffer);
|
||||||
|
}
|
||||||
|
private void addGenericDebugObjects()
|
||||||
|
{
|
||||||
|
GenericRenderObjectFactory factory = GenericRenderObjectFactory.INSTANCE;
|
||||||
|
|
||||||
|
|
||||||
|
// single giant box
|
||||||
|
IDhApiRenderableBoxGroup singleGiantBoxGroup = factory.createForSingleBox(
|
||||||
|
ModInfo.NAME + ":CyanChunkBox",
|
||||||
|
new DhApiRenderableBox(
|
||||||
|
new DhApiVec3d(0,0,0), new DhApiVec3d(16,190,16),
|
||||||
|
new Color(Color.CYAN.getRed(), Color.CYAN.getGreen(), Color.CYAN.getBlue(), 125),
|
||||||
|
EDhApiBlockMaterial.WATER)
|
||||||
|
);
|
||||||
|
singleGiantBoxGroup.setSkyLight(LodUtil.MAX_MC_LIGHT);
|
||||||
|
singleGiantBoxGroup.setBlockLight(LodUtil.MAX_MC_LIGHT);
|
||||||
|
this.add(singleGiantBoxGroup);
|
||||||
|
|
||||||
|
|
||||||
|
// single slender box
|
||||||
|
IDhApiRenderableBoxGroup singleTallBoxGroup = factory.createForSingleBox(
|
||||||
|
ModInfo.NAME + ":GreenBeacon",
|
||||||
|
new DhApiRenderableBox(
|
||||||
|
new DhApiVec3d(16,0,31), new DhApiVec3d(17,2000,32),
|
||||||
|
new Color(Color.GREEN.getRed(), Color.GREEN.getGreen(), Color.GREEN.getBlue(), 125),
|
||||||
|
EDhApiBlockMaterial.ILLUMINATED)
|
||||||
|
);
|
||||||
|
singleTallBoxGroup.setSkyLight(LodUtil.MAX_MC_LIGHT);
|
||||||
|
singleTallBoxGroup.setBlockLight(LodUtil.MAX_MC_LIGHT);
|
||||||
|
this.add(singleTallBoxGroup);
|
||||||
|
|
||||||
|
|
||||||
|
// absolute box group
|
||||||
|
ArrayList<DhApiRenderableBox> absBoxList = new ArrayList<>();
|
||||||
|
for (int i = 0; i < 18; i++)
|
||||||
|
{
|
||||||
|
absBoxList.add(new DhApiRenderableBox(
|
||||||
|
new DhApiVec3d(i,150+i,24), new DhApiVec3d(1+i,151+i,25),
|
||||||
|
new Color(Color.ORANGE.getRed(), Color.ORANGE.getGreen(), Color.ORANGE.getBlue()),
|
||||||
|
EDhApiBlockMaterial.LAVA
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
IDhApiRenderableBoxGroup absolutePosBoxGroup = factory.createAbsolutePositionedGroup(ModInfo.NAME + ":OrangeStairs", absBoxList);
|
||||||
|
this.add(absolutePosBoxGroup);
|
||||||
|
|
||||||
|
|
||||||
|
// relative box group
|
||||||
|
ArrayList<DhApiRenderableBox> relBoxList = new ArrayList<>();
|
||||||
|
for (int i = 0; i < 8; i+=2)
|
||||||
|
{
|
||||||
|
relBoxList.add(new DhApiRenderableBox(
|
||||||
|
new DhApiVec3d(0,i,0), new DhApiVec3d(1,1+i,1),
|
||||||
|
new Color(Color.MAGENTA.getRed(), Color.MAGENTA.getGreen(), Color.MAGENTA.getBlue()),
|
||||||
|
EDhApiBlockMaterial.METAL
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
IDhApiRenderableBoxGroup relativePosBoxGroup = factory.createRelativePositionedGroup(
|
||||||
|
ModInfo.NAME + ":MovingMagentaGroup",
|
||||||
|
new DhApiVec3d(24, 140, 24),
|
||||||
|
relBoxList);
|
||||||
|
relativePosBoxGroup.setPreRenderFunc((event) ->
|
||||||
|
{
|
||||||
|
DhApiVec3d pos = relativePosBoxGroup.getOriginBlockPos();
|
||||||
|
pos.x += event.partialTicks / 2;
|
||||||
|
pos.x %= 32;
|
||||||
|
relativePosBoxGroup.setOriginBlockPos(pos);
|
||||||
|
});
|
||||||
|
this.add(relativePosBoxGroup);
|
||||||
|
|
||||||
|
|
||||||
|
// massive relative box group
|
||||||
|
ArrayList<DhApiRenderableBox> massRelBoxList = new ArrayList<>();
|
||||||
|
for (int x = 0; x < 50*2; x+=2)
|
||||||
|
{
|
||||||
|
for (int z = 0; z < 50*2; z+=2)
|
||||||
|
{
|
||||||
|
massRelBoxList.add(new DhApiRenderableBox(
|
||||||
|
new DhApiVec3d(-x, 0, -z), new DhApiVec3d(1-x, 1, 1-z),
|
||||||
|
new Color(Color.RED.getRed(), Color.RED.getGreen(), Color.RED.getBlue()),
|
||||||
|
EDhApiBlockMaterial.TERRACOTTA
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IDhApiRenderableBoxGroup massRelativePosBoxGroup = factory.createRelativePositionedGroup(
|
||||||
|
ModInfo.NAME + ":MassRedGroup",
|
||||||
|
new DhApiVec3d(-25, 140, 0),
|
||||||
|
massRelBoxList);
|
||||||
|
massRelativePosBoxGroup.setPreRenderFunc((event) ->
|
||||||
|
{
|
||||||
|
DhApiVec3d blockPos = massRelativePosBoxGroup.getOriginBlockPos();
|
||||||
|
blockPos.y += event.partialTicks / 4;
|
||||||
|
if (blockPos.y > 150f)
|
||||||
|
{
|
||||||
|
blockPos.y = 140f;
|
||||||
|
|
||||||
|
Color newColor = (massRelativePosBoxGroup.get(0).color == Color.RED) ? Color.RED.darker() : Color.RED;
|
||||||
|
massRelativePosBoxGroup.forEach((box) -> { box.color = newColor; });
|
||||||
|
massRelativePosBoxGroup.triggerBoxChange();
|
||||||
|
}
|
||||||
|
|
||||||
|
massRelativePosBoxGroup.setOriginBlockPos(blockPos);
|
||||||
|
});
|
||||||
|
this.add(massRelativePosBoxGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//==============//
|
||||||
|
// registration //
|
||||||
|
//==============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void add(IDhApiRenderableBoxGroup iBoxGroup) throws IllegalArgumentException
|
||||||
|
{
|
||||||
|
if (!(iBoxGroup instanceof RenderableBoxGroup))
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("Box group must be of type ["+ RenderableBoxGroup.class.getSimpleName()+"], type received: ["+(iBoxGroup != null ? iBoxGroup.getClass() : "NULL")+"].");
|
||||||
|
}
|
||||||
|
RenderableBoxGroup boxGroup = (RenderableBoxGroup) iBoxGroup;
|
||||||
|
if (boxGroup.size() != 0)
|
||||||
|
{
|
||||||
|
// trigger a box change to make sure the initial data is uploaded
|
||||||
|
boxGroup.triggerBoxChange();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
long id = boxGroup.getId();
|
||||||
|
if (this.boxGroupById.containsKey(id))
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("A box group with the ID [" + id + "] is already present.");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.boxGroupById.put(id, boxGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IDhApiRenderableBoxGroup remove(long id) { return this.boxGroupById.remove(id); }
|
||||||
|
|
||||||
|
public void clear() { this.boxGroupById.clear(); }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//===========//
|
||||||
|
// rendering //
|
||||||
|
//===========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param renderingWithSsao
|
||||||
|
* if true that means this render call is happening before the SSAO pass
|
||||||
|
* and any objects rendered in this pass will have SSAO applied to them.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void render(RenderParams renderEventParam, IProfilerWrapper profiler, boolean renderingWithSsao)
|
||||||
|
{
|
||||||
|
// generic rendering (both instanced and direct) is extremely unstable on Mac, so don't render anything
|
||||||
|
if (EPlatform.get() == EPlatform.MACOS)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// render setup //
|
||||||
|
try (IProfilerWrapper.IProfileBlock setup_profile = profiler.push("setup"))
|
||||||
|
{
|
||||||
|
|
||||||
|
this.init();
|
||||||
|
|
||||||
|
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericRenderSetupEvent.class, renderEventParam.apiCopy);
|
||||||
|
|
||||||
|
|
||||||
|
boolean renderWireframe = Config.Client.Advanced.Debugging.renderWireframe.get();
|
||||||
|
if (renderWireframe)
|
||||||
|
{
|
||||||
|
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_LINE);
|
||||||
|
GLMC.disableFaceCulling();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_FILL);
|
||||||
|
GLMC.enableFaceCulling();
|
||||||
|
}
|
||||||
|
|
||||||
|
GLMC.enableBlend();
|
||||||
|
GL32.glBlendEquation(GL32.GL_FUNC_ADD);
|
||||||
|
GLMC.glBlendFuncSeparate(GL32.GL_SRC_ALPHA, GL32.GL_ONE_MINUS_SRC_ALPHA, GL32.GL_ONE, GL32.GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
|
IDhApiGenericObjectShaderProgram shaderProgram = this.instancedRenderingAvailable ? this.instancedShaderProgram : this.directShaderProgram;
|
||||||
|
IDhApiGenericObjectShaderProgram shaderProgramOverride = OverrideInjector.INSTANCE.get(IDhApiGenericObjectShaderProgram.class);
|
||||||
|
if (shaderProgramOverride != null && shaderProgram.overrideThisFrame())
|
||||||
|
{
|
||||||
|
shaderProgram = shaderProgramOverride;
|
||||||
|
}
|
||||||
|
|
||||||
|
shaderProgram.bind(renderEventParam);
|
||||||
|
shaderProgram.bindVertexBuffer(this.boxVertexBuffer.getId());
|
||||||
|
|
||||||
|
this.boxIndexBuffer.bind();
|
||||||
|
|
||||||
|
Vec3d camPos = MC_RENDER.getCameraExactPosition();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// rendering //
|
||||||
|
|
||||||
|
Collection<RenderableBoxGroup> boxList = this.boxGroupById.values();
|
||||||
|
for (RenderableBoxGroup boxGroup : boxList)
|
||||||
|
{
|
||||||
|
// validation //
|
||||||
|
|
||||||
|
// shouldn't happen, but just in case
|
||||||
|
if (boxGroup == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip boxes that shouldn't render this pass
|
||||||
|
if (boxGroup.ssaoEnabled != renderingWithSsao)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
profiler.popPush("render prep");
|
||||||
|
boxGroup.preRender(renderEventParam); // called even if the group is inactive, so the group can be activate if desired
|
||||||
|
|
||||||
|
// ignore inactive groups
|
||||||
|
if (!boxGroup.active)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// allow API users to cancel this object's rendering
|
||||||
|
EVENT_PARAM.update(renderEventParam, boxGroup);
|
||||||
|
boolean cancelRendering = ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericObjectRenderEvent.class, EVENT_PARAM);
|
||||||
|
if (cancelRendering)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update instanced data if needed
|
||||||
|
if (this.instancedRenderingAvailable)
|
||||||
|
{
|
||||||
|
boxGroup.tryUpdateInstancedDataAsync();
|
||||||
|
|
||||||
|
// skip groups that haven't been uploaded yet
|
||||||
|
if (boxGroup.vertexBufferContainer.getState() != GlGenericObjectVertexContainer.EState.RENDER)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// render //
|
||||||
|
|
||||||
|
profiler.popPush("rendering");
|
||||||
|
try (IProfilerWrapper.IProfileBlock namespace_profile = profiler.push(boxGroup.getResourceLocationNamespace());
|
||||||
|
IProfilerWrapper.IProfileBlock location_profile = profiler.push(boxGroup.getResourceLocationPath()))
|
||||||
|
{
|
||||||
|
if (this.instancedRenderingAvailable)
|
||||||
|
{
|
||||||
|
this.renderBoxGroupInstanced(shaderProgram, renderEventParam, boxGroup, camPos, profiler);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.renderBoxGroupDirect(shaderProgram, renderEventParam, boxGroup, camPos, profiler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boxGroup.postRender(renderEventParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//==========//
|
||||||
|
// clean up //
|
||||||
|
//==========//
|
||||||
|
|
||||||
|
profiler.popPush("cleanup");
|
||||||
|
|
||||||
|
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericRenderCleanupEvent.class, renderEventParam.apiCopy);
|
||||||
|
|
||||||
|
if (renderWireframe)
|
||||||
|
{
|
||||||
|
// default back to GL_FILL since all other rendering uses it
|
||||||
|
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_FILL);
|
||||||
|
GLMC.enableFaceCulling();
|
||||||
|
}
|
||||||
|
|
||||||
|
shaderProgram.unbind();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=====================//
|
||||||
|
// instanced rendering //
|
||||||
|
//=====================//
|
||||||
|
//region
|
||||||
|
|
||||||
|
private void renderBoxGroupInstanced(
|
||||||
|
IDhApiGenericObjectShaderProgram shaderProgram, DhApiRenderParam renderEventParam,
|
||||||
|
RenderableBoxGroup boxGroup, Vec3d camPos,
|
||||||
|
IProfilerWrapper profiler)
|
||||||
|
{
|
||||||
|
try (IProfilerWrapper.IProfileBlock render_profile = profiler.push("vertex setup"))
|
||||||
|
{
|
||||||
|
|
||||||
|
// update instance data //
|
||||||
|
DhApiRenderableBoxGroupShading shading = boxGroup.shading;
|
||||||
|
if (shading == null)
|
||||||
|
{
|
||||||
|
shading = DEFAULT_SHADING;
|
||||||
|
}
|
||||||
|
|
||||||
|
shaderProgram.fillIndirectUniformData(
|
||||||
|
renderEventParam,
|
||||||
|
shading, boxGroup,
|
||||||
|
camPos);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Bind instance data //
|
||||||
|
profiler.popPush("binding");
|
||||||
|
|
||||||
|
GlGenericObjectVertexContainer container = (GlGenericObjectVertexContainer) (boxGroup.vertexBufferContainer);
|
||||||
|
|
||||||
|
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, container.color);
|
||||||
|
GL32.glEnableVertexAttribArray(1);
|
||||||
|
GL32.glVertexAttribPointer(1, 4, GL32.GL_FLOAT, false, 4 * Float.BYTES, 0);
|
||||||
|
this.vertexAttribDivisor(1, 1);
|
||||||
|
|
||||||
|
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, container.scale);
|
||||||
|
GL32.glEnableVertexAttribArray(2);
|
||||||
|
this.vertexAttribDivisor(2, 1);
|
||||||
|
GL32.glVertexAttribPointer(2, 3, GL32.GL_FLOAT, false, 3 * Float.BYTES, 0);
|
||||||
|
|
||||||
|
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, container.chunkPos);
|
||||||
|
GL32.glEnableVertexAttribArray(3);
|
||||||
|
this.vertexAttribDivisor(3, 1);
|
||||||
|
GL32.glVertexAttribIPointer(3, 3, GL32.GL_INT, 3 * Integer.BYTES, 0);
|
||||||
|
|
||||||
|
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, container.subChunkPos);
|
||||||
|
GL32.glEnableVertexAttribArray(4);
|
||||||
|
this.vertexAttribDivisor(4, 1);
|
||||||
|
GL32.glVertexAttribPointer(4, 3, GL32.GL_FLOAT, false, 3 * Float.BYTES, 0);
|
||||||
|
|
||||||
|
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, container.material);
|
||||||
|
GL32.glEnableVertexAttribArray(5);
|
||||||
|
this.vertexAttribDivisor(5, 1);
|
||||||
|
GL32.glVertexAttribIPointer(5, 1, GL32.GL_BYTE, Byte.BYTES, 0);
|
||||||
|
|
||||||
|
|
||||||
|
// Draw instanced
|
||||||
|
profiler.popPush("render");
|
||||||
|
if (container.uploadedBoxCount > 0)
|
||||||
|
{
|
||||||
|
GL32.glDrawElementsInstanced(GL32.GL_TRIANGLES, BOX_INDICES.length, GL32.GL_UNSIGNED_INT, 0, container.uploadedBoxCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Clean up
|
||||||
|
profiler.popPush("cleanup");
|
||||||
|
|
||||||
|
GL32.glDisableVertexAttribArray(1);
|
||||||
|
GL32.glDisableVertexAttribArray(2);
|
||||||
|
GL32.glDisableVertexAttribArray(3);
|
||||||
|
GL32.glDisableVertexAttribArray(4);
|
||||||
|
GL32.glDisableVertexAttribArray(5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Clean way to handle both {@link GL33#glVertexAttribDivisor} and {@link ARBInstancedArrays#glVertexAttribDivisorARB}
|
||||||
|
* based on which one is supported.
|
||||||
|
*/
|
||||||
|
private void vertexAttribDivisor(int index, int divisor)
|
||||||
|
{
|
||||||
|
if (this.vertexAttribDivisorSupported)
|
||||||
|
{
|
||||||
|
GL33.glVertexAttribDivisor(index, divisor);
|
||||||
|
}
|
||||||
|
else if(this.instancedArraysSupported)
|
||||||
|
{
|
||||||
|
ARBInstancedArrays.glVertexAttribDivisorARB(index, divisor);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("Instanced rendering isn't supported by this machine. Direct rendering should have been used instead.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//==================//
|
||||||
|
// direct rendering //
|
||||||
|
//==================//
|
||||||
|
//region
|
||||||
|
|
||||||
|
private void renderBoxGroupDirect(
|
||||||
|
IDhApiGenericObjectShaderProgram shaderProgram,
|
||||||
|
DhApiRenderParam renderEventParam,
|
||||||
|
RenderableBoxGroup boxGroup, Vec3d camPos,
|
||||||
|
IProfilerWrapper profiler)
|
||||||
|
{
|
||||||
|
profiler.popPush("shared uniforms");
|
||||||
|
DhApiRenderableBoxGroupShading shading = boxGroup.shading;
|
||||||
|
if (shading == null)
|
||||||
|
{
|
||||||
|
shading = DhApiRenderableBoxGroupShading.getUnshaded();
|
||||||
|
}
|
||||||
|
|
||||||
|
shaderProgram.fillSharedDirectUniformData(renderEventParam, shading, boxGroup, camPos);
|
||||||
|
|
||||||
|
for (int i = 0; i < boxGroup.size(); i++)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
DhApiRenderableBox box = boxGroup.get(i);
|
||||||
|
if (box != null)
|
||||||
|
{
|
||||||
|
profiler.popPush("direct uniforms");
|
||||||
|
shaderProgram.fillDirectUniformData(renderEventParam, boxGroup, box, camPos);
|
||||||
|
|
||||||
|
profiler.popPush("render");
|
||||||
|
GL32.glDrawElements(GL32.GL_TRIANGLES, BOX_INDICES.length, GL32.GL_UNSIGNED_INT, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IndexOutOfBoundsException e)
|
||||||
|
{
|
||||||
|
// Concurrency issue, the list was modified while rendering
|
||||||
|
// this can probably be ignored.
|
||||||
|
// However, if it does become a problem we can add locks to the box group.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=========//
|
||||||
|
// getters //
|
||||||
|
//=========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
/** @throws IllegalStateException if {@link #init()} function hasn't been called yet */
|
||||||
|
public boolean getInstancedRenderingAvailable() throws IllegalStateException
|
||||||
|
{
|
||||||
|
if (!this.init)
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("GL initialization hasn't been completed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.instancedRenderingAvailable;
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=========//
|
||||||
|
// F3 menu //
|
||||||
|
//=========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public String getVboRenderDebugMenuString()
|
||||||
|
{
|
||||||
|
// get counts
|
||||||
|
int totalGroupCount = this.boxGroupById.size();
|
||||||
|
int totalBoxCount = 0;
|
||||||
|
|
||||||
|
int activeGroupCount = 0;
|
||||||
|
int activeBoxCount = 0;
|
||||||
|
|
||||||
|
for (long key : this.boxGroupById.keySet())
|
||||||
|
{
|
||||||
|
RenderableBoxGroup renderGroup = this.boxGroupById.get(key);
|
||||||
|
if (renderGroup.active)
|
||||||
|
{
|
||||||
|
activeGroupCount++;
|
||||||
|
activeBoxCount += renderGroup.size();
|
||||||
|
}
|
||||||
|
totalBoxCount += renderGroup.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return "Generic Obj #: " + F3Screen.NUMBER_FORMAT.format(activeGroupCount) + "/" + F3Screen.NUMBER_FORMAT.format(totalGroupCount) + ", " +
|
||||||
|
"Cube #: " + F3Screen.NUMBER_FORMAT.format(activeBoxCount) + "/" + F3Screen.NUMBER_FORMAT.format(totalBoxCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// base overrides //
|
||||||
|
//================//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close()
|
||||||
|
{
|
||||||
|
if (this.boxVertexBuffer != null)
|
||||||
|
{
|
||||||
|
this.boxVertexBuffer.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.boxIndexBuffer != null)
|
||||||
|
{
|
||||||
|
this.boxIndexBuffer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+231
@@ -0,0 +1,231 @@
|
|||||||
|
package com.seibel.distanthorizons.common.render.openGl.generic;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiGenericObjectShaderProgram;
|
||||||
|
import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderableBoxGroup;
|
||||||
|
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
|
||||||
|
import com.seibel.distanthorizons.api.objects.math.DhApiVec3d;
|
||||||
|
import com.seibel.distanthorizons.api.objects.math.DhApiVec3i;
|
||||||
|
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox;
|
||||||
|
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBoxGroupShading;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.shader.GlShaderProgram;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.vertexAttribute.GlAbstractVertexAttribute;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.vertexAttribute.GlVertexPointer;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.misc.LightMapWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||||
|
import com.seibel.distanthorizons.core.util.math.Mat4f;
|
||||||
|
import com.seibel.distanthorizons.core.util.math.Vec3f;
|
||||||
|
|
||||||
|
public class GlGenericObjectShaderProgram extends GlShaderProgram implements IDhApiGenericObjectShaderProgram
|
||||||
|
{
|
||||||
|
public static final String VERTEX_SHADER_INSTANCED_PATH = "assets/distanthorizons/shaders/generic/gl/instanced/vert.vert";
|
||||||
|
public static final String VERTEX_SHADER_DIRECT_PATH = "assets/distanthorizons/shaders/generic/gl/direct/vert.vert";
|
||||||
|
public static final String FRAGMENT_SHADER_INSTANCED_PATH = "assets/distanthorizons/shaders/generic/gl/instanced/frag.frag";
|
||||||
|
public static final String FRAGMENT_SHADER_DIRECT_PATH = "assets/distanthorizons/shaders/generic/gl/direct/frag.frag";
|
||||||
|
|
||||||
|
public final GlAbstractVertexAttribute va;
|
||||||
|
|
||||||
|
|
||||||
|
// shader uniforms
|
||||||
|
private final int directShaderTransformUniform;
|
||||||
|
private final int directShaderColorUniform;
|
||||||
|
|
||||||
|
private final int instancedShaderOffsetChunkUniform;
|
||||||
|
private final int instancedShaderOffsetSubChunkUniform;
|
||||||
|
private final int instancedShaderCameraChunkPosUniform;
|
||||||
|
private final int instancedShaderCameraSubChunkPosUniform;
|
||||||
|
private final int instancedShaderProjectionModelViewMatrixUniform;
|
||||||
|
|
||||||
|
private final int lightMapUniform;
|
||||||
|
private final int skyLightUniform;
|
||||||
|
private final int blockLightUniform;
|
||||||
|
|
||||||
|
private final int northShadingUniform;
|
||||||
|
private final int southShadingUniform;
|
||||||
|
private final int eastShadingUniform;
|
||||||
|
private final int westShadingUniform;
|
||||||
|
private final int topShadingUniform;
|
||||||
|
private final int bottomShadingUniform;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
|
||||||
|
public GlGenericObjectShaderProgram(boolean useInstancedRendering)
|
||||||
|
{
|
||||||
|
super(
|
||||||
|
useInstancedRendering ? VERTEX_SHADER_INSTANCED_PATH : VERTEX_SHADER_DIRECT_PATH,
|
||||||
|
useInstancedRendering ? FRAGMENT_SHADER_INSTANCED_PATH : FRAGMENT_SHADER_DIRECT_PATH,
|
||||||
|
"vPosition"
|
||||||
|
);
|
||||||
|
|
||||||
|
this.va = GlAbstractVertexAttribute.create();
|
||||||
|
this.va.bind();
|
||||||
|
// Pos
|
||||||
|
this.va.setVertexAttribute(0, 0, GlVertexPointer.addVec3Pointer(false));
|
||||||
|
this.va.completeAndCheck(Float.BYTES * 3);
|
||||||
|
|
||||||
|
this.directShaderTransformUniform = this.tryGetUniformLocation("uTransform");
|
||||||
|
this.directShaderColorUniform = this.tryGetUniformLocation("uColor");
|
||||||
|
|
||||||
|
this.instancedShaderOffsetChunkUniform = this.tryGetUniformLocation("uOffsetChunk");
|
||||||
|
this.instancedShaderOffsetSubChunkUniform = this.tryGetUniformLocation("uOffsetSubChunk");
|
||||||
|
this.instancedShaderCameraChunkPosUniform = this.tryGetUniformLocation("uCameraPosChunk");
|
||||||
|
this.instancedShaderCameraSubChunkPosUniform = this.tryGetUniformLocation("uCameraPosSubChunk");
|
||||||
|
this.instancedShaderProjectionModelViewMatrixUniform = this.tryGetUniformLocation("uProjectionMvm");
|
||||||
|
|
||||||
|
this.lightMapUniform = this.getUniformLocation("uLightMap");
|
||||||
|
this.skyLightUniform = this.getUniformLocation("uSkyLight");
|
||||||
|
this.blockLightUniform = this.getUniformLocation("uBlockLight");
|
||||||
|
this.northShadingUniform = this.getUniformLocation("uNorthShading");
|
||||||
|
this.southShadingUniform = this.getUniformLocation("uSouthShading");
|
||||||
|
this.eastShadingUniform = this.getUniformLocation("uEastShading");
|
||||||
|
this.westShadingUniform = this.getUniformLocation("uWestShading");
|
||||||
|
this.topShadingUniform = this.getUniformLocation("uTopShading");
|
||||||
|
this.bottomShadingUniform = this.getUniformLocation("uBottomShading");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=========//
|
||||||
|
// methods //
|
||||||
|
//=========//
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bind(DhApiRenderParam renderEventParam)
|
||||||
|
{
|
||||||
|
super.bind();
|
||||||
|
this.va.bind();
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void unbind()
|
||||||
|
{
|
||||||
|
super.unbind();
|
||||||
|
this.va.unbind();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void free()
|
||||||
|
{
|
||||||
|
this.va.free();
|
||||||
|
super.free();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bindVertexBuffer(int vbo) { this.va.bindBufferToAllBindingPoints(vbo); }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fillIndirectUniformData(
|
||||||
|
DhApiRenderParam renderParameters,
|
||||||
|
DhApiRenderableBoxGroupShading shading, IDhApiRenderableBoxGroup boxGroup,
|
||||||
|
DhApiVec3d camPos
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Mat4f projectionMvmMatrix = new Mat4f(renderParameters.dhProjectionMatrix);
|
||||||
|
projectionMvmMatrix.multiply(renderParameters.dhModelViewMatrix);
|
||||||
|
|
||||||
|
super.bind();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
this.setUniform(this.instancedShaderOffsetChunkUniform,
|
||||||
|
new DhApiVec3i(
|
||||||
|
LodUtil.getChunkPosFromDouble(boxGroup.getOriginBlockPos().x),
|
||||||
|
LodUtil.getChunkPosFromDouble(boxGroup.getOriginBlockPos().y),
|
||||||
|
LodUtil.getChunkPosFromDouble(boxGroup.getOriginBlockPos().z)
|
||||||
|
));
|
||||||
|
this.setUniform(this.instancedShaderOffsetSubChunkUniform,
|
||||||
|
new Vec3f(
|
||||||
|
LodUtil.getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().x),
|
||||||
|
LodUtil.getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().y),
|
||||||
|
LodUtil.getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().z)
|
||||||
|
));
|
||||||
|
|
||||||
|
this.setUniform(this.instancedShaderCameraChunkPosUniform,
|
||||||
|
new DhApiVec3i(
|
||||||
|
LodUtil.getChunkPosFromDouble(camPos.x),
|
||||||
|
LodUtil.getChunkPosFromDouble(camPos.y),
|
||||||
|
LodUtil.getChunkPosFromDouble(camPos.z)
|
||||||
|
));
|
||||||
|
this.setUniform(this.instancedShaderCameraSubChunkPosUniform,
|
||||||
|
new Vec3f(
|
||||||
|
LodUtil.getSubChunkPosFromDouble(camPos.x),
|
||||||
|
LodUtil.getSubChunkPosFromDouble(camPos.y),
|
||||||
|
LodUtil.getSubChunkPosFromDouble(camPos.z)
|
||||||
|
));
|
||||||
|
|
||||||
|
this.setUniform(this.instancedShaderProjectionModelViewMatrixUniform, projectionMvmMatrix);
|
||||||
|
|
||||||
|
this.setUniform(this.lightMapUniform, LightMapWrapper.GL_BOUND_INDEX);
|
||||||
|
this.setUniform(this.skyLightUniform, boxGroup.getSkyLight());
|
||||||
|
this.setUniform(this.blockLightUniform, boxGroup.getBlockLight());
|
||||||
|
|
||||||
|
|
||||||
|
this.setUniform(this.northShadingUniform, shading.north);
|
||||||
|
this.setUniform(this.southShadingUniform, shading.south);
|
||||||
|
this.setUniform(this.eastShadingUniform, shading.east);
|
||||||
|
this.setUniform(this.westShadingUniform, shading.west);
|
||||||
|
this.setUniform(this.topShadingUniform, shading.top);
|
||||||
|
this.setUniform(this.bottomShadingUniform, shading.bottom);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fillSharedDirectUniformData(
|
||||||
|
DhApiRenderParam renderParameters,
|
||||||
|
DhApiRenderableBoxGroupShading shading, IDhApiRenderableBoxGroup boxGroup,
|
||||||
|
DhApiVec3d camPos)
|
||||||
|
{
|
||||||
|
|
||||||
|
this.setUniform(this.lightMapUniform, LightMapWrapper.GL_BOUND_INDEX);
|
||||||
|
this.setUniform(this.skyLightUniform, boxGroup.getSkyLight());
|
||||||
|
this.setUniform(this.blockLightUniform, boxGroup.getBlockLight());
|
||||||
|
|
||||||
|
|
||||||
|
this.setUniform(this.northShadingUniform, shading.north);
|
||||||
|
this.setUniform(this.southShadingUniform, shading.south);
|
||||||
|
this.setUniform(this.eastShadingUniform, shading.east);
|
||||||
|
this.setUniform(this.westShadingUniform, shading.west);
|
||||||
|
this.setUniform(this.topShadingUniform, shading.top);
|
||||||
|
this.setUniform(this.bottomShadingUniform, shading.bottom);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fillDirectUniformData(
|
||||||
|
DhApiRenderParam renderParameters,
|
||||||
|
IDhApiRenderableBoxGroup boxGroup, DhApiRenderableBox box,
|
||||||
|
DhApiVec3d camPos)
|
||||||
|
{
|
||||||
|
Mat4f projectionMvmMatrix = new Mat4f(renderParameters.dhProjectionMatrix);
|
||||||
|
projectionMvmMatrix.multiply(renderParameters.dhModelViewMatrix);
|
||||||
|
|
||||||
|
Mat4f boxTransform = Mat4f.createTranslateMatrix(
|
||||||
|
(float) (box.minPos.x + boxGroup.getOriginBlockPos().x - camPos.x),
|
||||||
|
(float) (box.minPos.y + boxGroup.getOriginBlockPos().y - camPos.y),
|
||||||
|
(float) (box.minPos.z + boxGroup.getOriginBlockPos().z - camPos.z));
|
||||||
|
boxTransform.multiply(Mat4f.createScaleMatrix(
|
||||||
|
(float) (box.maxPos.x - box.minPos.x),
|
||||||
|
(float) (box.maxPos.y - box.minPos.y),
|
||||||
|
(float) (box.maxPos.z - box.minPos.z)));
|
||||||
|
projectionMvmMatrix.multiply(boxTransform);
|
||||||
|
this.setUniform(this.directShaderTransformUniform, projectionMvmMatrix);
|
||||||
|
|
||||||
|
this.setUniform(this.directShaderColorUniform, box.color);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getId() { return this.id; }
|
||||||
|
|
||||||
|
/** The base DH render program should always render */
|
||||||
|
@Override
|
||||||
|
public boolean overrideThisFrame() { return true; }
|
||||||
|
|
||||||
|
}
|
||||||
+177
@@ -0,0 +1,177 @@
|
|||||||
|
package com.seibel.distanthorizons.common.render.openGl.generic;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import com.seibel.distanthorizons.core.render.renderer.RenderableBoxGroup;
|
||||||
|
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IDhGenericObjectVertexBufferContainer;
|
||||||
|
import org.lwjgl.opengl.GL32;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For use by {@link RenderableBoxGroup}
|
||||||
|
*
|
||||||
|
* @see RenderableBoxGroup
|
||||||
|
*/
|
||||||
|
public class GlGenericObjectVertexContainer implements IDhGenericObjectVertexBufferContainer
|
||||||
|
{
|
||||||
|
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
|
|
||||||
|
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public int chunkPos = 0;
|
||||||
|
public int subChunkPos = 0;
|
||||||
|
public int scale = 0;
|
||||||
|
public int color = 0;
|
||||||
|
public int material = 0;
|
||||||
|
|
||||||
|
public int[] chunkPosData = new int[0];
|
||||||
|
public float[] subChunkPosData = new float[0];
|
||||||
|
public float[] scalingData = new float[0];
|
||||||
|
public float[] colorData = new float[0];
|
||||||
|
public int[] materialData = new int[0];
|
||||||
|
|
||||||
|
public int uploadedBoxCount = 0;
|
||||||
|
|
||||||
|
private EState state = EState.NEW;
|
||||||
|
@Override
|
||||||
|
public EState getState() { return this.state; }
|
||||||
|
@Override
|
||||||
|
public void setState(EState state) { this.state = state; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//===========================//
|
||||||
|
// render building/uploading //
|
||||||
|
//===========================//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public void updateVertexData(List<DhApiRenderableBox> uploadBoxList)
|
||||||
|
{
|
||||||
|
int boxCount = uploadBoxList.size();
|
||||||
|
|
||||||
|
|
||||||
|
// recreate the data arrays if their size is different
|
||||||
|
if (this.uploadedBoxCount != boxCount)
|
||||||
|
{
|
||||||
|
this.uploadedBoxCount = boxCount;
|
||||||
|
|
||||||
|
this.chunkPosData = new int[boxCount * 3]; // 3 elements XYZ
|
||||||
|
this.subChunkPosData = new float[boxCount * 3]; // 3 elements XYZ
|
||||||
|
this.scalingData = new float[boxCount * 3]; // 3 elements XYZ
|
||||||
|
|
||||||
|
this.colorData = new float[boxCount * 4]; // 4 elements, RGBA
|
||||||
|
this.materialData = new int[boxCount];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// transformation / scaling //
|
||||||
|
for (int i = 0; i < boxCount; i++)
|
||||||
|
{
|
||||||
|
DhApiRenderableBox box = uploadBoxList.get(i);
|
||||||
|
|
||||||
|
int dataIndex = i * 3;
|
||||||
|
|
||||||
|
this.chunkPosData[dataIndex] = LodUtil.getChunkPosFromDouble(box.minPos.x);
|
||||||
|
this.chunkPosData[dataIndex + 1] = LodUtil.getChunkPosFromDouble(box.minPos.y);
|
||||||
|
this.chunkPosData[dataIndex + 2] = LodUtil.getChunkPosFromDouble(box.minPos.z);
|
||||||
|
|
||||||
|
this.subChunkPosData[dataIndex] = LodUtil.getSubChunkPosFromDouble(box.minPos.x);
|
||||||
|
this.subChunkPosData[dataIndex + 1] = LodUtil.getSubChunkPosFromDouble(box.minPos.y);
|
||||||
|
this.subChunkPosData[dataIndex + 2] = LodUtil.getSubChunkPosFromDouble(box.minPos.z);
|
||||||
|
|
||||||
|
this.scalingData[dataIndex] = (float) (box.maxPos.x - box.minPos.x);
|
||||||
|
this.scalingData[dataIndex + 1] = (float) (box.maxPos.y - box.minPos.y);
|
||||||
|
this.scalingData[dataIndex + 2] = (float) (box.maxPos.z - box.minPos.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// colors/materials //
|
||||||
|
for (int i = 0; i < boxCount; i++)
|
||||||
|
{
|
||||||
|
DhApiRenderableBox box = uploadBoxList.get(i);
|
||||||
|
Color color = box.color;
|
||||||
|
int colorIndex = i * 4;
|
||||||
|
this.colorData[colorIndex] = color.getRed() / 255.0f;
|
||||||
|
this.colorData[colorIndex + 1] = color.getGreen() / 255.0f;
|
||||||
|
this.colorData[colorIndex + 2] = color.getBlue() / 255.0f;
|
||||||
|
this.colorData[colorIndex + 3] = color.getAlpha() / 255.0f;
|
||||||
|
|
||||||
|
this.materialData[i] = box.material;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void uploadDataToGpu()
|
||||||
|
{
|
||||||
|
this.tryCreateBuffers();
|
||||||
|
|
||||||
|
// Upload transformation matrices
|
||||||
|
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.chunkPos);
|
||||||
|
GL32.glBufferData(GL32.GL_ARRAY_BUFFER, this.chunkPosData, GL32.GL_DYNAMIC_DRAW);
|
||||||
|
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.subChunkPos);
|
||||||
|
GL32.glBufferData(GL32.GL_ARRAY_BUFFER, this.subChunkPosData, GL32.GL_DYNAMIC_DRAW);
|
||||||
|
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.scale);
|
||||||
|
GL32.glBufferData(GL32.GL_ARRAY_BUFFER, this.scalingData, GL32.GL_DYNAMIC_DRAW);
|
||||||
|
|
||||||
|
// Upload colors
|
||||||
|
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.color);
|
||||||
|
GL32.glBufferData(GL32.GL_ARRAY_BUFFER, this.colorData, GL32.GL_DYNAMIC_DRAW);
|
||||||
|
|
||||||
|
// Upload materials
|
||||||
|
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.material);
|
||||||
|
GL32.glBufferData(GL32.GL_ARRAY_BUFFER, this.materialData, GL32.GL_DYNAMIC_DRAW);
|
||||||
|
}
|
||||||
|
/** needs to be done on the render thread */
|
||||||
|
private void tryCreateBuffers()
|
||||||
|
{
|
||||||
|
if (this.chunkPos == 0)
|
||||||
|
{
|
||||||
|
this.chunkPos = GLMC.glGenBuffers();
|
||||||
|
this.subChunkPos = GLMC.glGenBuffers();
|
||||||
|
this.scale = GLMC.glGenBuffers();
|
||||||
|
this.color = GLMC.glGenBuffers();
|
||||||
|
this.material = GLMC.glGenBuffers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// base overrides //
|
||||||
|
//================//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close()
|
||||||
|
{
|
||||||
|
tryDeleteBuffer(this.chunkPos);
|
||||||
|
tryDeleteBuffer(this.subChunkPos);
|
||||||
|
tryDeleteBuffer(this.scale);
|
||||||
|
tryDeleteBuffer(this.color);
|
||||||
|
tryDeleteBuffer(this.material);
|
||||||
|
}
|
||||||
|
private static void tryDeleteBuffer(int bufferId)
|
||||||
|
{
|
||||||
|
// usually unnecessary, but just in case
|
||||||
|
if (bufferId != 0)
|
||||||
|
{
|
||||||
|
GLMC.glDeleteBuffers(bufferId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+382
@@ -0,0 +1,382 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Distant Horizons mod
|
||||||
|
* licensed under the GNU LGPL v3 License.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 James Seibel
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.distanthorizons.common.render.openGl.glObject;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.api.enums.config.EDhApiGLErrorHandlingMode;
|
||||||
|
import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod;
|
||||||
|
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderingApi;
|
||||||
|
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderingEngine;
|
||||||
|
import com.seibel.distanthorizons.core.config.Config;
|
||||||
|
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
|
||||||
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
|
import com.seibel.distanthorizons.core.jar.EPlatform;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import com.seibel.distanthorizons.core.util.objects.GLMessages.*;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IIrisAccessor;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
|
||||||
|
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||||
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
import org.lwjgl.opengl.GL;
|
||||||
|
import org.lwjgl.opengl.GL32;
|
||||||
|
import org.lwjgl.opengl.GLCapabilities;
|
||||||
|
import org.lwjgl.opengl.GLUtil;
|
||||||
|
|
||||||
|
import java.io.PrintStream;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A singleton that holds references to different openGL contexts
|
||||||
|
* and GPU capabilities.
|
||||||
|
*/
|
||||||
|
public class GLProxy
|
||||||
|
{
|
||||||
|
private static final IIrisAccessor IRIS_ACCESSOR = ModAccessorInjector.INSTANCE.get(IIrisAccessor.class);
|
||||||
|
private static final IMinecraftClientWrapper MC_CLIENT = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
|
||||||
|
private static final AbstractDhRenderApiDefinition RENDER_API_DEF = SingletonInjector.INSTANCE.get(AbstractDhRenderApiDefinition.class);
|
||||||
|
|
||||||
|
|
||||||
|
public static final DhLogger LOGGER;
|
||||||
|
static
|
||||||
|
{
|
||||||
|
DhLoggerBuilder loggerBuilder = new DhLoggerBuilder();
|
||||||
|
loggerBuilder.fileLevelConfig(Config.Common.Logging.logRendererGLEventToFile);
|
||||||
|
|
||||||
|
// don't send chat messages if Iris is present since
|
||||||
|
// Iris is known to cause (harmless) GL errors
|
||||||
|
// and this can confuse users
|
||||||
|
boolean irisPresent = (IRIS_ACCESSOR != null);
|
||||||
|
if (!irisPresent)
|
||||||
|
{
|
||||||
|
loggerBuilder.chatLevelConfig(Config.Common.Logging.logRendererGLEventToChat);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGGER = loggerBuilder.build();
|
||||||
|
|
||||||
|
if (irisPresent)
|
||||||
|
{
|
||||||
|
LOGGER.info("Iris detected, Distant Horizons OpenGL error logging won't be sent in the chat due to Iris throwing known (harmless) OpenGL errors. This is a bug with Iris, not Distant Horizons.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Set<String> LOGGED_GL_MESSAGES = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private static GLProxy instance = null;
|
||||||
|
|
||||||
|
|
||||||
|
/** Minecraft's GL capabilities */
|
||||||
|
public final GLCapabilities glCapabilities;
|
||||||
|
|
||||||
|
public boolean namedObjectSupported = false; // ~OpenGL 4.5 (UNUSED CURRENTLY)
|
||||||
|
public boolean bufferStorageSupported = false; // ~OpenGL 4.4
|
||||||
|
public boolean vertexAttributeBufferBindingSupported = false; // ~OpenGL 4.3
|
||||||
|
public boolean instancedArraysSupported = false;
|
||||||
|
public boolean vertexAttribDivisorSupported = false; // OpenGL 3.3 or newer
|
||||||
|
|
||||||
|
private final EDhApiGpuUploadMethod preferredUploadMethod;
|
||||||
|
|
||||||
|
public final GLMessageBuilder vanillaDebugMessageBuilder =
|
||||||
|
new GLMessageBuilder(
|
||||||
|
(type) ->
|
||||||
|
{
|
||||||
|
if (type == EGLMessageType.POP_GROUP)
|
||||||
|
return false;
|
||||||
|
else if (type == EGLMessageType.PUSH_GROUP)
|
||||||
|
return false;
|
||||||
|
else if (type == EGLMessageType.MARKER)
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
(severity) ->
|
||||||
|
{
|
||||||
|
// notifications can generally be ignored (if they are logged at all)
|
||||||
|
if (severity == EGLMessageSeverity.NOTIFICATION)
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
private GLProxy() throws IllegalStateException
|
||||||
|
{
|
||||||
|
if (RENDER_API_DEF.getRenderApi() != EDhApiRenderingApi.OPEN_GL)
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("[" + GLProxy.class.getSimpleName() + "] was created with the wrong Rendering API ["+RENDER_API_DEF.getRenderApi()+"]!");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// this must be created on minecraft's render context to work correctly
|
||||||
|
if (GLFW.glfwGetCurrentContext() == 0L)
|
||||||
|
{
|
||||||
|
String message = "[" + GLProxy.class.getSimpleName() + "] was created outside the render thread!";
|
||||||
|
IllegalStateException exception = new IllegalStateException(message);
|
||||||
|
MC_CLIENT.crashMinecraft(message, exception);
|
||||||
|
throw exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGGER.info("Creating [" + GLProxy.class.getSimpleName() + "]... If this is the last message you see there must have been an OpenGL error.");
|
||||||
|
LOGGER.info("Lod Render OpenGL version [" + GL32.glGetString(GL32.GL_VERSION) + "].");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//============================//
|
||||||
|
// get Minecraft's GL context //
|
||||||
|
//============================//
|
||||||
|
|
||||||
|
// get Minecraft's capabilities
|
||||||
|
this.glCapabilities = GL.getCapabilities();
|
||||||
|
|
||||||
|
// crash the game if the GPU doesn't support OpenGL 3.2
|
||||||
|
if (!this.glCapabilities.OpenGL32)
|
||||||
|
{
|
||||||
|
String supportedVersionInfo = this.getFailedVersionInfo(this.glCapabilities);
|
||||||
|
|
||||||
|
// See full requirement at above.
|
||||||
|
String errorMessage = ModInfo.READABLE_NAME + " was initializing " + GLProxy.class.getSimpleName()
|
||||||
|
+ " and discovered this GPU doesn't meet the OpenGL requirements. Sorry I couldn't tell you sooner :(\n" +
|
||||||
|
"Additional info:\n" + supportedVersionInfo;
|
||||||
|
IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
|
||||||
|
MC.crashMinecraft(errorMessage, new UnsupportedOperationException("Distant Horizon OpenGL requirements not met"));
|
||||||
|
}
|
||||||
|
LOGGER.info("minecraftGlCapabilities:\n" + this.versionInfoToString(this.glCapabilities));
|
||||||
|
|
||||||
|
if (Config.Client.Advanced.Debugging.OpenGl.overrideVanillaGLLogger.get())
|
||||||
|
{
|
||||||
|
GLUtil.setupDebugMessageCallback(new PrintStream(new GLMessageOutputStream(GLProxy::logMessage, this.vanillaDebugMessageBuilder), true));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//======================//
|
||||||
|
// get GPU capabilities //
|
||||||
|
//======================//
|
||||||
|
|
||||||
|
// UNUSED currently
|
||||||
|
// Check if we can use the named version of all calls, which is available in GL4.5 or after
|
||||||
|
this.namedObjectSupported = this.glCapabilities.glNamedBufferData != 0L; //Nullptr
|
||||||
|
|
||||||
|
// Check if we can use the Buffer Storage, which is available in GL4.4 or after
|
||||||
|
this.bufferStorageSupported = this.glCapabilities.glBufferStorage != 0L; // Nullptr
|
||||||
|
if (!this.bufferStorageSupported)
|
||||||
|
{
|
||||||
|
LOGGER.info("This GPU doesn't support Buffer Storage (OpenGL 4.4), falling back to using other methods.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we can use the make-over version of Vertex Attribute, which is available in GL4.3 or after
|
||||||
|
this.vertexAttributeBufferBindingSupported = this.glCapabilities.glBindVertexBuffer != 0L; // Nullptr
|
||||||
|
|
||||||
|
// used by instanced rendering
|
||||||
|
this.vertexAttribDivisorSupported = this.glCapabilities.OpenGL33;
|
||||||
|
// denotes if ARBInstancedArrays.glVertexAttribDivisorARB() is available or not
|
||||||
|
// can be used as a backup if MC didn't create a GL 3.3+ context
|
||||||
|
this.instancedArraysSupported = this.glCapabilities.GL_ARB_instanced_arrays;
|
||||||
|
|
||||||
|
// get the best automatic upload method
|
||||||
|
String vendor = GL32.glGetString(GL32.GL_VENDOR).toUpperCase(); // example return: "NVIDIA CORPORATION"
|
||||||
|
if (EPlatform.get() != EPlatform.MACOS)
|
||||||
|
{
|
||||||
|
if (vendor.contains("NVIDIA") || vendor.contains("GEFORCE"))
|
||||||
|
{
|
||||||
|
// NVIDIA card
|
||||||
|
this.preferredUploadMethod = this.bufferStorageSupported ? EDhApiGpuUploadMethod.BUFFER_STORAGE : EDhApiGpuUploadMethod.SUB_DATA;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// AMD or Intel card
|
||||||
|
this.preferredUploadMethod = this.bufferStorageSupported ? EDhApiGpuUploadMethod.BUFFER_STORAGE : EDhApiGpuUploadMethod.DATA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Mac may have an issue with Buffer Storage, so default to the most basic
|
||||||
|
// form of uploading
|
||||||
|
this.preferredUploadMethod = EDhApiGpuUploadMethod.DATA;
|
||||||
|
}
|
||||||
|
LOGGER.info("GPU Vendor [" + vendor + "] with OS [" + EPlatform.get().getName() + "], Preferred upload method is [" + this.preferredUploadMethod + "].");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//==========//
|
||||||
|
// clean up //
|
||||||
|
//==========//
|
||||||
|
|
||||||
|
// GLProxy creation success
|
||||||
|
LOGGER.info(GLProxy.class.getSimpleName() + " creation successful. OpenGL smiles upon you this day.");
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=========//
|
||||||
|
// getters //
|
||||||
|
//=========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public static boolean hasInstance() { return instance != null; }
|
||||||
|
/** @throws IllegalStateException if the Proxy hasn't been created yet and this is called outside the render thread */
|
||||||
|
public static GLProxy getInstance() throws IllegalStateException
|
||||||
|
{
|
||||||
|
if (instance == null)
|
||||||
|
{
|
||||||
|
instance = new GLProxy();
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EDhApiGpuUploadMethod getGpuUploadMethod() { return this.preferredUploadMethod; }
|
||||||
|
|
||||||
|
public static boolean runningOnRenderThread()
|
||||||
|
{
|
||||||
|
long currentContext = GLFW.glfwGetCurrentContext();
|
||||||
|
return currentContext != 0L; // if the context isn't null, it's the MC context
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=========//
|
||||||
|
// logging //
|
||||||
|
//=========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
/** this method is called on the render thread at the point of the GL Error */
|
||||||
|
private static void logMessage(GLMessage glMessage)
|
||||||
|
{
|
||||||
|
EDhApiGLErrorHandlingMode errorHandlingMode = Config.Client.Advanced.Debugging.OpenGl.glErrorHandlingMode.get();
|
||||||
|
if (errorHandlingMode == EDhApiGLErrorHandlingMode.IGNORE)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
boolean onlyLogOnce = Config.Client.Advanced.Debugging.OpenGl.onlyLogGlErrorsOnce.get();
|
||||||
|
if (onlyLogOnce
|
||||||
|
&& !LOGGED_GL_MESSAGES.add(glMessage.message))
|
||||||
|
{
|
||||||
|
// this message has already been logged
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String errorMessage = "GL ERROR [" + glMessage.id + "] from [" + glMessage.source + "]: [" + glMessage.message + "].";
|
||||||
|
if (onlyLogOnce)
|
||||||
|
{
|
||||||
|
errorMessage += " This message will only be logged once.";
|
||||||
|
errorMessage += " Note: Distant Horizons will catch and log OpenGL errors from other mods, not just DH itself; if everything is rendering correctly these errors can probably be ignored.";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// create an exception so we get a stacktrace of where the message was triggered from
|
||||||
|
RuntimeException exception = new RuntimeException(errorMessage);
|
||||||
|
|
||||||
|
if (glMessage.type == EGLMessageType.ERROR || glMessage.type == EGLMessageType.UNDEFINED_BEHAVIOR)
|
||||||
|
{
|
||||||
|
// critical error
|
||||||
|
|
||||||
|
LOGGER.error(exception.getMessage(), exception);
|
||||||
|
|
||||||
|
if (errorHandlingMode == EDhApiGLErrorHandlingMode.LOG_THROW)
|
||||||
|
{
|
||||||
|
// will probably crash the game,
|
||||||
|
// good for quickly checking if there's a problem while preventing log spam
|
||||||
|
throw exception;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// non-critical log
|
||||||
|
|
||||||
|
EGLMessageSeverity severity = glMessage.severity;
|
||||||
|
if (severity == null)
|
||||||
|
{
|
||||||
|
// just in case the message was malformed
|
||||||
|
severity = EGLMessageSeverity.LOW;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (severity)
|
||||||
|
{
|
||||||
|
case HIGH:
|
||||||
|
LOGGER.error(exception.getMessage(), exception);
|
||||||
|
break;
|
||||||
|
case MEDIUM:
|
||||||
|
LOGGER.warn(exception.getMessage(), exception);
|
||||||
|
break;
|
||||||
|
case LOW:
|
||||||
|
LOGGER.info(exception.getMessage(), exception);
|
||||||
|
break;
|
||||||
|
case NOTIFICATION:
|
||||||
|
LOGGER.debug(exception.getMessage(), exception);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// helper methods //
|
||||||
|
//================//
|
||||||
|
//region
|
||||||
|
|
||||||
|
private String getFailedVersionInfo(GLCapabilities c)
|
||||||
|
{
|
||||||
|
return "Your OpenGL support:\n" +
|
||||||
|
"openGL version 3.2+: [" + c.OpenGL32 + "] <- REQUIRED\n" +
|
||||||
|
"Vertex Attribute Buffer Binding: [" + (c.glVertexAttribBinding != 0) + "] <- optional improvement\n" +
|
||||||
|
"Buffer Storage: [" + (c.glBufferStorage != 0) + "] <- optional improvement\n" +
|
||||||
|
"If you noticed that your computer supports higher OpenGL versions"
|
||||||
|
+ " but not the required version, try running the game in compatibility mode."
|
||||||
|
+ " (How you turn that on, I have no clue~)";
|
||||||
|
}
|
||||||
|
|
||||||
|
private String versionInfoToString(GLCapabilities c)
|
||||||
|
{
|
||||||
|
return "Your OpenGL support:\n" +
|
||||||
|
"openGL version 3.2+: [" + c.OpenGL32 + "] <- REQUIRED\n" +
|
||||||
|
"Vertex Attribute Buffer Binding: [" + (c.glVertexAttribBinding != 0) + "] <- optional improvement\n" +
|
||||||
|
"Buffer Storage: [" + (c.glBufferStorage != 0) + "] <- optional improvement\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+273
@@ -0,0 +1,273 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Distant Horizons mod
|
||||||
|
* licensed under the GNU LGPL v3 License.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 James Seibel
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.distanthorizons.common.render.openGl.glObject;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.enums.GLEnums;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
|
||||||
|
import org.lwjgl.opengl.GL32;
|
||||||
|
|
||||||
|
public class GLState implements AutoCloseable
|
||||||
|
{
|
||||||
|
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
|
||||||
|
|
||||||
|
|
||||||
|
public int program;
|
||||||
|
public int vao;
|
||||||
|
public int vbo;
|
||||||
|
public int ebo;
|
||||||
|
public int fbo;
|
||||||
|
public int texture2D;
|
||||||
|
/** IE: GL_TEXTURE0, GL_TEXTURE1, etc. */
|
||||||
|
public int activeTextureNumber;
|
||||||
|
public int texture0;
|
||||||
|
public int texture1;
|
||||||
|
public int texture2;
|
||||||
|
public int texture3;
|
||||||
|
public int frameBufferTexture0;
|
||||||
|
public int frameBufferTexture1;
|
||||||
|
public int frameBufferDepthTexture;
|
||||||
|
public boolean blend;
|
||||||
|
public boolean scissor;
|
||||||
|
public int blendEqRGB;
|
||||||
|
public int blendEqAlpha;
|
||||||
|
public int blendSrcColor;
|
||||||
|
public int blendSrcAlpha;
|
||||||
|
public int blendDstColor;
|
||||||
|
public int blendDstAlpha;
|
||||||
|
public boolean depth;
|
||||||
|
public boolean writeToDepthBuffer;
|
||||||
|
public int depthFunc;
|
||||||
|
public boolean stencil;
|
||||||
|
public int stencilFunc;
|
||||||
|
public int stencilRef;
|
||||||
|
public int stencilMask;
|
||||||
|
public int[] view;
|
||||||
|
public boolean cull;
|
||||||
|
public int cullMode;
|
||||||
|
public int polyMode;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public GLState() { this.saveState(); }
|
||||||
|
|
||||||
|
public void saveState()
|
||||||
|
{
|
||||||
|
this.program = GL32.glGetInteger(GL32.GL_CURRENT_PROGRAM);
|
||||||
|
this.vao = GL32.glGetInteger(GL32.GL_VERTEX_ARRAY_BINDING);
|
||||||
|
this.vbo = GL32.glGetInteger(GL32.GL_ARRAY_BUFFER_BINDING);
|
||||||
|
this.ebo = GL32.glGetInteger(GL32.GL_ELEMENT_ARRAY_BUFFER_BINDING);
|
||||||
|
|
||||||
|
this.fbo = GL32.glGetInteger(GL32.GL_FRAMEBUFFER_BINDING);
|
||||||
|
|
||||||
|
this.texture2D = GL32.glGetInteger(GL32.GL_TEXTURE_BINDING_2D);
|
||||||
|
this.activeTextureNumber = GL32.glGetInteger(GL32.GL_ACTIVE_TEXTURE);
|
||||||
|
|
||||||
|
GLMC.glActiveTexture(GL32.GL_TEXTURE0);
|
||||||
|
this.texture0 = GL32.glGetInteger(GL32.GL_TEXTURE_BINDING_2D);
|
||||||
|
|
||||||
|
GLMC.glActiveTexture(GL32.GL_TEXTURE1);
|
||||||
|
this.texture1 = GL32.glGetInteger(GL32.GL_TEXTURE_BINDING_2D);
|
||||||
|
|
||||||
|
GLMC.glActiveTexture(GL32.GL_TEXTURE2); // problem with Iris
|
||||||
|
this.texture2 = GL32.glGetInteger(GL32.GL_TEXTURE_BINDING_2D);
|
||||||
|
|
||||||
|
GLMC.glActiveTexture(GL32.GL_TEXTURE3);
|
||||||
|
this.texture3 = GL32.glGetInteger(GL32.GL_TEXTURE_BINDING_2D);
|
||||||
|
|
||||||
|
GLMC.glActiveTexture(this.activeTextureNumber);
|
||||||
|
|
||||||
|
if (this.fbo != 0)
|
||||||
|
{
|
||||||
|
this.frameBufferTexture0 = GL32.glGetFramebufferAttachmentParameteri(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
|
||||||
|
this.frameBufferTexture1 = GL32.glGetFramebufferAttachmentParameteri(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT1, GL32.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
|
||||||
|
|
||||||
|
int depthType = GL32.glGetFramebufferAttachmentParameteri(GL32.GL_FRAMEBUFFER, GL32.GL_DEPTH_ATTACHMENT, GL32.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE);
|
||||||
|
this.frameBufferDepthTexture = (depthType == GL32.GL_TEXTURE) ? GL32.glGetFramebufferAttachmentParameteri(GL32.GL_FRAMEBUFFER, GL32.GL_DEPTH_ATTACHMENT, GL32.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME) : 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// attempting to get values from the default framebuffer can throw errors on Linux
|
||||||
|
this.frameBufferTexture0 = 0;
|
||||||
|
this.frameBufferTexture1 = 0;
|
||||||
|
this.frameBufferDepthTexture = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.blend = GL32.glIsEnabled(GL32.GL_BLEND);
|
||||||
|
this.scissor = GL32.glIsEnabled(GL32.GL_SCISSOR_TEST);
|
||||||
|
this.blendEqRGB = GL32.glGetInteger(GL32.GL_BLEND_EQUATION_RGB);
|
||||||
|
this.blendEqAlpha = GL32.glGetInteger(GL32.GL_BLEND_EQUATION_ALPHA);
|
||||||
|
this.blendSrcColor = GL32.glGetInteger(GL32.GL_BLEND_SRC_RGB);
|
||||||
|
this.blendSrcAlpha = GL32.glGetInteger(GL32.GL_BLEND_SRC_ALPHA);
|
||||||
|
this.blendDstColor = GL32.glGetInteger(GL32.GL_BLEND_DST_RGB);
|
||||||
|
this.blendDstAlpha = GL32.glGetInteger(GL32.GL_BLEND_DST_ALPHA);
|
||||||
|
this.depth = GL32.glIsEnabled(GL32.GL_DEPTH_TEST);
|
||||||
|
this.writeToDepthBuffer = GL32.glGetInteger(GL32.GL_DEPTH_WRITEMASK) == GL32.GL_TRUE;
|
||||||
|
this.depthFunc = GL32.glGetInteger(GL32.GL_DEPTH_FUNC);
|
||||||
|
this.stencil = GL32.glIsEnabled(GL32.GL_STENCIL_TEST);
|
||||||
|
this.stencilFunc = GL32.glGetInteger(GL32.GL_STENCIL_FUNC);
|
||||||
|
this.stencilRef = GL32.glGetInteger(GL32.GL_STENCIL_REF);
|
||||||
|
this.stencilMask = GL32.glGetInteger(GL32.GL_STENCIL_VALUE_MASK);
|
||||||
|
this.view = new int[4];
|
||||||
|
GL32.glGetIntegerv(GL32.GL_VIEWPORT, this.view);
|
||||||
|
this.cull = GL32.glIsEnabled(GL32.GL_CULL_FACE);
|
||||||
|
this.cullMode = GL32.glGetInteger(GL32.GL_CULL_FACE_MODE);
|
||||||
|
this.polyMode = GL32.glGetInteger(GL32.GL_POLYGON_MODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close()
|
||||||
|
{
|
||||||
|
// explicitly unbinding the frame buffer is necessary to prevent GL_CLEAR calls from hitting the wrong buffer
|
||||||
|
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, 0);
|
||||||
|
boolean frameBufferSet = false;
|
||||||
|
|
||||||
|
if (this.fbo != 0 && GL32.glIsFramebuffer(this.fbo))
|
||||||
|
{
|
||||||
|
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, this.fbo);
|
||||||
|
frameBufferSet = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (this.blend)
|
||||||
|
{
|
||||||
|
GLMC.enableBlend();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GLMC.disableBlend();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.scissor)
|
||||||
|
{
|
||||||
|
GLMC.enableScissorTest();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GLMC.disableScissorTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
GLMC.glActiveTexture(GL32.GL_TEXTURE0);
|
||||||
|
GLMC.glBindTexture(GL32.glIsTexture(this.texture0) ? this.texture0 : 0);
|
||||||
|
|
||||||
|
GLMC.glActiveTexture(GL32.GL_TEXTURE1);
|
||||||
|
GLMC.glBindTexture(GL32.glIsTexture(this.texture1) ? this.texture1 : 0);
|
||||||
|
|
||||||
|
GLMC.glActiveTexture(GL32.GL_TEXTURE2);
|
||||||
|
GLMC.glBindTexture(GL32.glIsTexture(this.texture2) ? this.texture2 : 0);
|
||||||
|
|
||||||
|
GLMC.glActiveTexture(GL32.GL_TEXTURE3);
|
||||||
|
GLMC.glBindTexture(GL32.glIsTexture(this.texture3) ? this.texture3 : 0);
|
||||||
|
|
||||||
|
GLMC.glActiveTexture(this.activeTextureNumber);
|
||||||
|
GLMC.glBindTexture(GL32.glIsTexture(this.texture2D) ? this.texture2D : 0);
|
||||||
|
|
||||||
|
// attempting to set textures on the default frame buffer (ID 0) will throw errors
|
||||||
|
if (frameBufferSet)
|
||||||
|
{
|
||||||
|
if (GL32.glIsTexture(this.frameBufferTexture0))
|
||||||
|
{
|
||||||
|
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_TEXTURE_2D, this.frameBufferTexture0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.frameBufferTexture1 != 0 && GL32.glIsTexture(this.frameBufferTexture1))
|
||||||
|
{
|
||||||
|
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT1, GL32.GL_TEXTURE_2D, this.frameBufferTexture1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GL32.glIsTexture(this.frameBufferDepthTexture))
|
||||||
|
{
|
||||||
|
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_DEPTH_ATTACHMENT, GL32.GL_TEXTURE_2D, this.frameBufferDepthTexture, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
GL32.glBindVertexArray(GL32.glIsVertexArray(this.vao) ? this.vao : 0);
|
||||||
|
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, GL32.glIsBuffer(this.vbo) ? this.vbo : 0);
|
||||||
|
GL32.glBindBuffer(GL32.GL_ELEMENT_ARRAY_BUFFER, GL32.glIsBuffer(this.ebo) ? this.ebo: 0);
|
||||||
|
GL32.glUseProgram(GL32.glIsProgram(this.program) ? this.program : 0);
|
||||||
|
|
||||||
|
if (this.writeToDepthBuffer)
|
||||||
|
{
|
||||||
|
GLMC.enableDepthMask();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GLMC.disableDepthMask();
|
||||||
|
}
|
||||||
|
|
||||||
|
GLMC.glBlendFunc(this.blendSrcColor, this.blendDstColor);
|
||||||
|
GL32.glBlendEquationSeparate(this.blendEqRGB, this.blendEqAlpha);
|
||||||
|
GLMC.glBlendFuncSeparate(this.blendSrcColor, this.blendDstColor, this.blendSrcAlpha, this.blendDstAlpha);
|
||||||
|
|
||||||
|
if (this.depth)
|
||||||
|
{
|
||||||
|
GLMC.enableDepthTest();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GLMC.disableDepthTest();
|
||||||
|
}
|
||||||
|
GLMC.glDepthFunc(this.depthFunc);
|
||||||
|
|
||||||
|
if (this.stencil)
|
||||||
|
{
|
||||||
|
GL32.glEnable(GL32.GL_STENCIL_TEST);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GL32.glDisable(GL32.GL_STENCIL_TEST);
|
||||||
|
}
|
||||||
|
GL32.glStencilFunc(this.stencilFunc, this.stencilRef, this.stencilMask);
|
||||||
|
|
||||||
|
GL32.glViewport(this.view[0], this.view[1], this.view[2], this.view[3]);
|
||||||
|
if (this.cull)
|
||||||
|
{
|
||||||
|
GLMC.enableFaceCulling();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GLMC.disableFaceCulling();
|
||||||
|
}
|
||||||
|
GL32.glCullFace(this.cullMode);
|
||||||
|
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, this.polyMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return "GLState{" +
|
||||||
|
"program=" + this.program + ", vao=" + this.vao + ", vbo=" + this.vbo + ", ebo=" + this.ebo + ", fbo=" + this.fbo +
|
||||||
|
", text=" + GLEnums.getString(this.texture2D) + "@" + this.activeTextureNumber + ", text0=" + GLEnums.getString(this.texture0) +
|
||||||
|
", FB text0=" + this.frameBufferTexture0 +
|
||||||
|
", FB text1=" + this.frameBufferTexture1 +
|
||||||
|
", FB depth=" + this.frameBufferDepthTexture +
|
||||||
|
", blend=" + this.blend + ", scissor=" + this.scissor + ", blendMode=" + GLEnums.getString(this.blendSrcColor) + "," + GLEnums.getString(this.blendDstColor) +
|
||||||
|
", depth=" + this.depth +
|
||||||
|
", depthFunc=" + GLEnums.getString(this.depthFunc) + ", stencil=" + this.stencil +
|
||||||
|
", stencilFunc=" + GLEnums.getString(this.stencilFunc) + ", stencilRef=" + this.stencilRef + ", stencilMask=" + this.stencilMask +
|
||||||
|
", view={x:" + this.view[0] + ", y:" + this.view[1] +
|
||||||
|
", w:" + this.view[2] + ", h:" + this.view[3] + "}" + ", cull=" + this.cull +
|
||||||
|
", cullMode=" + GLEnums.getString(this.cullMode) + ", polyMode=" + GLEnums.getString(this.polyMode) +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+94
@@ -0,0 +1,94 @@
|
|||||||
|
package com.seibel.distanthorizons.common.render.openGl.glObject;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiFramebuffer;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
|
||||||
|
import org.lwjgl.opengl.GL32;
|
||||||
|
|
||||||
|
public class GlDhFramebuffer implements IDhApiFramebuffer
|
||||||
|
{
|
||||||
|
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
|
||||||
|
|
||||||
|
private int id;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public GlDhFramebuffer() { this.id = GL32.glGenFramebuffers(); }
|
||||||
|
|
||||||
|
/** For internal use by Iris, do not remove. */
|
||||||
|
public GlDhFramebuffer(int id) { this.id = id; }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=========//
|
||||||
|
// methods //
|
||||||
|
//=========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addDepthAttachment(int textureId, boolean isCombinedStencil)
|
||||||
|
{
|
||||||
|
this.bind();
|
||||||
|
|
||||||
|
int depthAttachment = isCombinedStencil ? GL32.GL_DEPTH_STENCIL_ATTACHMENT : GL32.GL_DEPTH_ATTACHMENT;
|
||||||
|
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, depthAttachment, GL32.GL_TEXTURE_2D, textureId, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addColorAttachment(int textureIndex, int textureId)
|
||||||
|
{
|
||||||
|
this.bind();
|
||||||
|
|
||||||
|
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0 + textureIndex, GL32.GL_TEXTURE_2D, textureId, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bind()
|
||||||
|
{
|
||||||
|
if (this.id == -1)
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("Framebuffer does not exist!");
|
||||||
|
}
|
||||||
|
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, this.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy()
|
||||||
|
{
|
||||||
|
GL32.glDeleteFramebuffers(this.id);
|
||||||
|
this.id = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getStatus()
|
||||||
|
{
|
||||||
|
this.bind();
|
||||||
|
int status = GL32.glCheckFramebufferStatus(GL32.GL_FRAMEBUFFER);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getId() { return this.id; }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// API methods //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public boolean overrideThisFrame() { return true; }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
package com.seibel.distanthorizons.common.render.openGl.glObject;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodBufferContainer;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.ILodContainerUniformBufferWrapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* With OpenGL all uniform data is uploaded during the rendering phase
|
||||||
|
* so nothing is needed here.
|
||||||
|
*/
|
||||||
|
public class GlDummyUniformData implements ILodContainerUniformBufferWrapper
|
||||||
|
{
|
||||||
|
@Override public void tryUpload(LodBufferContainer bufferContainer) { }
|
||||||
|
@Override public void close() { }
|
||||||
|
|
||||||
|
}
|
||||||
+629
@@ -0,0 +1,629 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Distant Horizons mod
|
||||||
|
* licensed under the GNU LGPL v3 License.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 James Seibel
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.distanthorizons.common.render.openGl.glObject.buffer;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.GLProxy;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.config.Config;
|
||||||
|
import com.seibel.distanthorizons.core.jar.EPlatform;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import com.seibel.distanthorizons.core.logging.f3.F3Screen;
|
||||||
|
import com.seibel.distanthorizons.core.render.RenderThreadTaskHandler;
|
||||||
|
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||||
|
import com.seibel.distanthorizons.core.util.ThreadUtil;
|
||||||
|
import com.seibel.distanthorizons.core.util.objects.Pair;
|
||||||
|
import com.seibel.distanthorizons.core.util.objects.pooling.PhantomLoggingHelper;
|
||||||
|
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||||
|
import com.seibel.distanthorizons.coreapi.util.StringUtil;
|
||||||
|
import org.lwjgl.opengl.GL32;
|
||||||
|
import org.lwjgl.opengl.GL44;
|
||||||
|
|
||||||
|
import java.lang.ref.PhantomReference;
|
||||||
|
import java.lang.ref.Reference;
|
||||||
|
import java.lang.ref.ReferenceQueue;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.concurrent.locks.StampedLock;
|
||||||
|
|
||||||
|
public class GLBuffer implements AutoCloseable
|
||||||
|
{
|
||||||
|
private static final DhLogger LOGGER = new DhLoggerBuilder()
|
||||||
|
.fileLevelConfig(Config.Common.Logging.logRendererGLEventToFile)
|
||||||
|
.chatLevelConfig(Config.Common.Logging.logRendererGLEventToChat)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
|
||||||
|
|
||||||
|
|
||||||
|
// TODO move to a shared location that can be handled by both GL and Blaze3D buffers
|
||||||
|
/** if enabled the number of GC'ed buffers will be logged */
|
||||||
|
private static final boolean LOG_PHANTOM_RECOVERY = ModInfo.IS_DEV_BUILD;
|
||||||
|
/** If enabled buffers allocation/upload stacks will be logged when GC'ed. */
|
||||||
|
private static final boolean LOG_PHANTOM_ALLOCATION_STACKS = false; // disabled by default due to the increased GC load
|
||||||
|
|
||||||
|
public static final double BUFFER_EXPANSION_MULTIPLIER = 1.3;
|
||||||
|
public static final double BUFFER_SHRINK_TRIGGER = BUFFER_EXPANSION_MULTIPLIER * BUFFER_EXPANSION_MULTIPLIER;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* On macOS the legacy OpenGL -> Metal bridge crashes with SIGBUS in
|
||||||
|
* {@code _platform_memmove} when {@code glBufferData} or {@code glBufferSubData}
|
||||||
|
* are called with a large ByteBuffer in one shot. To work around it, we split
|
||||||
|
* the upload into smaller sub-data calls that each fit comfortably inside the
|
||||||
|
* driver's internal staging path. <br>
|
||||||
|
* 256 KiB tuned empirically against macOS 26.5 — a 1 MiB chunk still
|
||||||
|
* tripped the same {@code _platform_memmove} crash inside
|
||||||
|
* {@code glBufferSubData_Exec}, but 256 KiB consistently survives.
|
||||||
|
*/
|
||||||
|
public static final int MAC_UPLOAD_CHUNK_BYTES = 256 * 1024;
|
||||||
|
/** Threshold above which the chunked path kicks in on macOS. */
|
||||||
|
public static final int MAC_UPLOAD_CHUNK_THRESHOLD = MAC_UPLOAD_CHUNK_BYTES;
|
||||||
|
/** the number of active buffers, can be used for debugging */
|
||||||
|
public static AtomicInteger bufferCount = new AtomicInteger(0);
|
||||||
|
|
||||||
|
private static final int PHANTOM_REF_CHECK_TIME_IN_MS = 5 * 1000;
|
||||||
|
private static final ConcurrentHashMap<PhantomReference<? extends GLBuffer>, Integer> PHANTOM_TO_BUFFER_ID = new ConcurrentHashMap<>();
|
||||||
|
private static final ConcurrentHashMap<Integer, PhantomReference<? extends GLBuffer>> BUFFER_ID_TO_PHANTOM = new ConcurrentHashMap<>();
|
||||||
|
private static final ConcurrentHashMap<Integer, String> BUFFER_ID_TO_ALLOCATION_STRING = new ConcurrentHashMap<>();
|
||||||
|
private static final ReferenceQueue<GLBuffer> PHANTOM_REFERENCE_QUEUE = new ReferenceQueue<>();
|
||||||
|
private static final ThreadPoolExecutor CLEANUP_THREAD = ThreadUtil.makeSingleDaemonThreadPool("GLBuffer Cleanup");
|
||||||
|
|
||||||
|
|
||||||
|
protected volatile int id = 0;
|
||||||
|
public final int getId() { return this.id; }
|
||||||
|
protected int size = 0;
|
||||||
|
public int getSize() { return this.size; }
|
||||||
|
protected boolean bufferStorage;
|
||||||
|
protected boolean isMapped = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Locking on the render thread isn't great, but is needed due to an inconsistent
|
||||||
|
* race condition where VBOs can be marked as deleted outside the render thread. <br><br>
|
||||||
|
*
|
||||||
|
* But, due to being a read-write lock the chance of freezing
|
||||||
|
* the render thread is very low
|
||||||
|
* and since this is a stamped lock, the optimistic read time is basically zero.
|
||||||
|
* (The optimistic lock time doesn't even appear in the profiler).
|
||||||
|
*/
|
||||||
|
public final StampedLock renderStampLock = new StampedLock();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//==============//
|
||||||
|
// constructors //
|
||||||
|
//==============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
static { CLEANUP_THREAD.execute(() -> runPhantomReferenceCleanupLoop()); }
|
||||||
|
|
||||||
|
public GLBuffer(boolean isBufferStorage) { this.destroyOldAndCreate(isBufferStorage); }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=========//
|
||||||
|
// methods //
|
||||||
|
//=========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
// Should be override by subclasses
|
||||||
|
public int getBufferBindingTarget() { return GL32.GL_COPY_READ_BUFFER; }
|
||||||
|
|
||||||
|
public void bind() { GL32.glBindBuffer(this.getBufferBindingTarget(), this.id); }
|
||||||
|
public void unbind() { GL32.glBindBuffer(this.getBufferBindingTarget(), 0); }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//====================//
|
||||||
|
// create and destroy //
|
||||||
|
//====================//
|
||||||
|
//region
|
||||||
|
|
||||||
|
protected void destroyOldAndCreate(boolean asBufferStorage)
|
||||||
|
{
|
||||||
|
if (!GLProxy.runningOnRenderThread())
|
||||||
|
{
|
||||||
|
LodUtil.assertNotReach("Thread ["+Thread.currentThread()+"] tried to create a GLBuffer outside the MC render thread.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// lock to prevent the render thread from accessing the buffer's ID
|
||||||
|
// while we are removing it
|
||||||
|
long writeStamp = renderStampLock.writeLock();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
final int oldId = this.id;
|
||||||
|
this.id = GLMC.glGenBuffers();
|
||||||
|
//LOGGER.info("created [" + newId + "].");
|
||||||
|
|
||||||
|
// destroy the old buffer
|
||||||
|
// after the new one has been created
|
||||||
|
// to hopefully prevent a rare race conditions where the old ID
|
||||||
|
// is still used somewhere
|
||||||
|
if (oldId != 0)
|
||||||
|
{
|
||||||
|
// this ID doesn't need to be tracked anymore
|
||||||
|
tryRemoveBufferIdFromPhantom(oldId);
|
||||||
|
destroyBufferIdNow(oldId, "destroyOldAndCreate");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
this.bufferStorage = asBufferStorage;
|
||||||
|
bufferCount.getAndIncrement();
|
||||||
|
|
||||||
|
PhantomReference<GLBuffer> phantom = new PhantomReference<>(this, PHANTOM_REFERENCE_QUEUE);
|
||||||
|
PHANTOM_TO_BUFFER_ID.put(phantom, this.id);
|
||||||
|
BUFFER_ID_TO_PHANTOM.put(this.id, phantom);
|
||||||
|
|
||||||
|
this.updateAllocationStackTrace();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
renderStampLock.unlock(writeStamp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void destroyAsync()
|
||||||
|
{
|
||||||
|
// lock to prevent the render thread from accessing the buffer's ID
|
||||||
|
// while we are removing it
|
||||||
|
long writeStamp = renderStampLock.writeLock();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (this.id == 0)
|
||||||
|
{
|
||||||
|
// the buffer has already been closed
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int idToDelete = this.id; // saving the ID to a separate variable is necessary so it can be captured by the lambda
|
||||||
|
|
||||||
|
// remove the phantom tracking now so the phantom doesn't have the chance to
|
||||||
|
// get garbage collected before the render thread task runs
|
||||||
|
// (this can happen if MC is running at extremely low framerates like 1 fps via mods)
|
||||||
|
tryRemoveBufferIdFromPhantom(idToDelete);
|
||||||
|
|
||||||
|
// mark the old data is invalid before deleting to prevent a rare race condition
|
||||||
|
// where the queued on render thread task runs before the ID is cleared
|
||||||
|
this.id = 0;
|
||||||
|
this.size = 0;
|
||||||
|
|
||||||
|
//LOGGER.info("async destroy [" + idToDelete + "].");
|
||||||
|
RenderThreadTaskHandler.INSTANCE.queueRunningOnRenderThread("GLBuffer destroyAsync", () -> { destroyBufferIdNow(idToDelete, "destroyAsync"); });
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
renderStampLock.unlock(writeStamp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void destroyBufferIdNow(int id, String cause)
|
||||||
|
{
|
||||||
|
// only delete valid buffers
|
||||||
|
if (id == 0)
|
||||||
|
{
|
||||||
|
LOGGER.warn("Attempted to destroy a buffer with ID 0, VRAM memory leaks may occur, cause: ["+cause+"].");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bufferCount.decrementAndGet();
|
||||||
|
GLMC.glDeleteBuffers(id);
|
||||||
|
|
||||||
|
if (Config.Client.Advanced.Debugging.logBufferGarbageCollection.get())
|
||||||
|
{
|
||||||
|
LOGGER.info("destroyed buffer [" + id + "], remaining: [" + BUFFER_ID_TO_PHANTOM.size() + "], cause: ["+cause+"].");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** should be called before {@link GLBuffer#destroyBufferIdNow} */
|
||||||
|
private static void tryRemoveBufferIdFromPhantom(int id)
|
||||||
|
{
|
||||||
|
// will contain nothing if stack tracking isn't enabled
|
||||||
|
BUFFER_ID_TO_ALLOCATION_STRING.remove(id);
|
||||||
|
|
||||||
|
PhantomReference<? extends GLBuffer> phantom = BUFFER_ID_TO_PHANTOM.remove(id);
|
||||||
|
if (phantom != null)
|
||||||
|
{
|
||||||
|
// if we are manually closing this buffer, we don't want the phantom reference to accidentally close it again
|
||||||
|
// this can cause a race condition were we accidentally delete an in-use buffer and cause NVIDIA
|
||||||
|
// to throw an EXCEPTION_ACCESS_VIOLATION when we attempt to render it
|
||||||
|
phantom.clear();
|
||||||
|
|
||||||
|
Integer phantomId = PHANTOM_TO_BUFFER_ID.remove(phantom);
|
||||||
|
if (phantomId == null)
|
||||||
|
{
|
||||||
|
LOGGER.warn("No Phantom->ID binding stored for ID ["+id+"]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOGGER.warn("Unable to remove phantom GLBuffer with ID ["+id+"], buffer may have already been deleted.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//==================//
|
||||||
|
// buffer uploading //
|
||||||
|
//==================//
|
||||||
|
//region
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assumes the GL Context is already bound. <br>
|
||||||
|
* Will create the VBO if one exist.
|
||||||
|
*/
|
||||||
|
public void uploadBuffer(ByteBuffer bb, EDhApiGpuUploadMethod uploadMethod, int maxExpansionSize, int bufferHint)
|
||||||
|
{
|
||||||
|
LodUtil.assertTrue(!uploadMethod.useEarlyMapping, "UploadMethod signal that this should use Mapping instead of uploadBuffer!");
|
||||||
|
int bbSize = bb.limit() - bb.position();
|
||||||
|
if (bbSize > maxExpansionSize)
|
||||||
|
{
|
||||||
|
LodUtil.assertNotReach("maxExpansionSize is [" + maxExpansionSize + "] but buffer size is [" + bbSize + "]!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't upload an empty buffer
|
||||||
|
if (bbSize == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// re-binding the old buffers is necessary for old MC versions for the following reasons:
|
||||||
|
// for 16.5 and older the screen may be black when on the home menu
|
||||||
|
// and for 1.19.2 - 1.21.4 the inventory/UI will render without a background
|
||||||
|
int vao = GL32.glGetInteger(GL32.GL_VERTEX_ARRAY_BINDING);
|
||||||
|
int vbo = GL32.glGetInteger(GL32.GL_ARRAY_BUFFER_BINDING);
|
||||||
|
int ebo = GL32.glGetInteger(GL32.GL_ELEMENT_ARRAY_BUFFER_BINDING);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// make sure the buffer is ready for uploading
|
||||||
|
this.createOrChangeBufferTypeForUpload(uploadMethod);
|
||||||
|
|
||||||
|
switch (uploadMethod)
|
||||||
|
{
|
||||||
|
case AUTO:
|
||||||
|
LodUtil.assertNotReach("GpuUploadMethod AUTO must be resolved before call to uploadBuffer()!");
|
||||||
|
case BUFFER_STORAGE:
|
||||||
|
this.uploadBufferStorage(bb);
|
||||||
|
break;
|
||||||
|
case DATA:
|
||||||
|
this.uploadBufferData(bb, bufferHint);
|
||||||
|
break;
|
||||||
|
case SUB_DATA:
|
||||||
|
this.uploadSubData(bb, maxExpansionSize, bufferHint);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LodUtil.assertNotReach("Unknown GpuUploadMethod!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
GL32.glBindVertexArray(GL32.glIsVertexArray(vao) ? vao : 0);
|
||||||
|
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, GL32.glIsBuffer(vbo) ? vbo : 0);
|
||||||
|
GL32.glBindBuffer(GL32.GL_ELEMENT_ARRAY_BUFFER, GL32.glIsBuffer(ebo) ? ebo: 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/** Requires the buffer to be bound */
|
||||||
|
protected void uploadBufferStorage(ByteBuffer bb)
|
||||||
|
{
|
||||||
|
LodUtil.assertTrue(this.bufferStorage, "Buffer is not bufferStorage but its trying to use bufferStorage upload method!");
|
||||||
|
|
||||||
|
int bbSize = bb.limit() - bb.position();
|
||||||
|
this.destroyOldAndCreate(true);
|
||||||
|
this.bind();
|
||||||
|
GL44.glBufferStorage(this.getBufferBindingTarget(), bb, 0);
|
||||||
|
this.size = bbSize;
|
||||||
|
}
|
||||||
|
/** Requires the buffer to be bound */
|
||||||
|
protected void uploadBufferData(ByteBuffer bb, int bufferDataHint)
|
||||||
|
{
|
||||||
|
LodUtil.assertTrue(!this.bufferStorage, "Buffer is bufferStorage but its trying to use bufferData upload method!");
|
||||||
|
|
||||||
|
int bbSize = bb.limit() - bb.position();
|
||||||
|
int target = this.getBufferBindingTarget();
|
||||||
|
|
||||||
|
if (shouldUploadToGpuInChunks(bbSize))
|
||||||
|
{
|
||||||
|
// Two-step path used on macOS to dodge the Apple OpenGL -> Metal
|
||||||
|
// memmove SIGBUS triggered by uploading a large ByteBuffer in one
|
||||||
|
// glBufferData call:
|
||||||
|
// 1) allocate-only with the size overload (no memcpy)
|
||||||
|
// 2) fill the buffer through chunked glBufferSubData calls
|
||||||
|
GL32.glBufferData(target, (long) bbSize, bufferDataHint);
|
||||||
|
subDataUploadInChunks(target, 0, bb, MAC_UPLOAD_CHUNK_BYTES);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GL32.glBufferData(target, bb, bufferDataHint);
|
||||||
|
}
|
||||||
|
this.size = bbSize;
|
||||||
|
|
||||||
|
this.updateAllocationStackTrace();
|
||||||
|
}
|
||||||
|
/** Requires the buffer to be bound */
|
||||||
|
protected void uploadSubData(ByteBuffer bb, int maxExpansionSize, int bufferDataHint)
|
||||||
|
{
|
||||||
|
LodUtil.assertTrue(!this.bufferStorage, "Buffer is bufferStorage but its trying to use subData upload method!");
|
||||||
|
|
||||||
|
int bbSize = bb.limit() - bb.position();
|
||||||
|
int target = this.getBufferBindingTarget();
|
||||||
|
if (this.size < bbSize || this.size > bbSize * BUFFER_SHRINK_TRIGGER)
|
||||||
|
{
|
||||||
|
int newSize = (int) (bbSize * BUFFER_EXPANSION_MULTIPLIER);
|
||||||
|
if (newSize > maxExpansionSize)
|
||||||
|
{
|
||||||
|
newSize = maxExpansionSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
// allocate-only — no memcpy, safe on macOS regardless of size
|
||||||
|
GL32.glBufferData(target, (long) newSize, bufferDataHint);
|
||||||
|
this.size = newSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldUploadToGpuInChunks(bbSize))
|
||||||
|
{
|
||||||
|
subDataUploadInChunks(target, 0, bb, MAC_UPLOAD_CHUNK_BYTES);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GL32.glBufferSubData(target, 0, bb);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateAllocationStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// base overrides //
|
||||||
|
//================//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() { this.destroyAsync(); }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return (this.bufferStorage ? "" : "Static-") + this.getClass().getSimpleName() +
|
||||||
|
"[id:" + this.id + ",size:" + this.size + (this.isMapped ? ",MAPPED" : "") + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// helper methods //
|
||||||
|
//================//
|
||||||
|
//region
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes sure the buffer exists and is of the correct format
|
||||||
|
* before uploading.
|
||||||
|
*/
|
||||||
|
private void createOrChangeBufferTypeForUpload(EDhApiGpuUploadMethod uploadMethod)
|
||||||
|
{
|
||||||
|
// create/change the buffer type if necessary
|
||||||
|
if (uploadMethod.useBufferStorage != this.bufferStorage)
|
||||||
|
{
|
||||||
|
// recreate if the buffer storage type changed
|
||||||
|
this.bind();
|
||||||
|
this.destroyOldAndCreate(uploadMethod.useBufferStorage);
|
||||||
|
this.bind();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Prevent uploading to the null buffer (ID 0).
|
||||||
|
// This can happen if the buffer was deleted previously.
|
||||||
|
if (this.id == 0)
|
||||||
|
{
|
||||||
|
this.destroyOldAndCreate(this.bufferStorage);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.bind();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* macOS-only mitigation for the SIGBUS in
|
||||||
|
* {@code libsystem_platform.dylib _platform_memmove} that happens when the
|
||||||
|
* Apple OpenGL -> Metal translation layer copies a single large ByteBuffer
|
||||||
|
* out of LWJGL into driver memory. Splitting the copy into
|
||||||
|
* {@link #MAC_UPLOAD_CHUNK_BYTES} slices keeps every memmove inside a size
|
||||||
|
* the bridge handles reliably.
|
||||||
|
*/
|
||||||
|
private static boolean shouldUploadToGpuInChunks(int byteCount)
|
||||||
|
{
|
||||||
|
return EPlatform.get() == EPlatform.MACOS
|
||||||
|
&& byteCount > MAC_UPLOAD_CHUNK_THRESHOLD;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uploads {@code bb} into the currently bound buffer at {@code baseOffset}
|
||||||
|
* using a sequence of {@link GL32#glBufferSubData(int, long, ByteBuffer)}
|
||||||
|
* calls of at most {@code chunkBytes} each. The buffer's position/limit are
|
||||||
|
* restored before returning.
|
||||||
|
*/
|
||||||
|
private static void subDataUploadInChunks(int target, int baseOffset, ByteBuffer bb, int chunkBytes)
|
||||||
|
{
|
||||||
|
final int origPos = bb.position();
|
||||||
|
final int origLimit = bb.limit();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
final int total = origLimit - origPos;
|
||||||
|
int uploaded = 0;
|
||||||
|
while (uploaded < total)
|
||||||
|
{
|
||||||
|
int chunk = Math.min(chunkBytes, total - uploaded);
|
||||||
|
bb.position(origPos + uploaded);
|
||||||
|
bb.limit(origPos + uploaded + chunk);
|
||||||
|
GL32.glBufferSubData(target, (long) (baseOffset + uploaded), bb);
|
||||||
|
uploaded += chunk;
|
||||||
|
// Force the driver to drain its command queue between chunks
|
||||||
|
// so the OpenGL -> Metal bridge processes (and frees) each
|
||||||
|
// staging copy before the next sub-data call piles another
|
||||||
|
// memmove on top of it.
|
||||||
|
if (uploaded < total)
|
||||||
|
{
|
||||||
|
GL32.glFlush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
bb.limit(origLimit);
|
||||||
|
bb.position(origPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* used to help track down leaks where the buffer isn't properly closed
|
||||||
|
* Note: this probably needs extending to accept a stack trace from outside where it's being called
|
||||||
|
* since it's often called on the render thread in an un-helpful location.
|
||||||
|
*/
|
||||||
|
public void updateAllocationStackTrace()
|
||||||
|
{
|
||||||
|
if (LOG_PHANTOM_ALLOCATION_STACKS)
|
||||||
|
{
|
||||||
|
String stack;
|
||||||
|
|
||||||
|
RenderThreadTaskHandler.QueuedRunnable parentQueuedRunnable;
|
||||||
|
// if this is running on the render thread, try getting the render task's stack trace instead
|
||||||
|
// since it's a lot more helpful than wherever the render thread tasks themselves are being run from
|
||||||
|
if (RenderThreadTaskHandler.INSTANCE.isCurrentThread()
|
||||||
|
&& (parentQueuedRunnable = RenderThreadTaskHandler.INSTANCE.getCurrentlyRunningTask()) != null
|
||||||
|
&& parentQueuedRunnable.stackTrace != null)
|
||||||
|
{
|
||||||
|
// trim off the getStacktrace() and queueRunningOnRenderThread() methods
|
||||||
|
StackTraceElement[] trimmedElements = Arrays.copyOfRange(parentQueuedRunnable.stackTrace, 2, parentQueuedRunnable.stackTrace.length);
|
||||||
|
stack = StringUtil.join("\n", trimmedElements).intern();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// not running on the render thread, use the normal stack trace
|
||||||
|
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
|
||||||
|
stack = StringUtil.join("\n", stackTraceElements).intern();
|
||||||
|
}
|
||||||
|
|
||||||
|
BUFFER_ID_TO_ALLOCATION_STRING.put(this.id, stack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// static cleanup //
|
||||||
|
//================//
|
||||||
|
//region
|
||||||
|
|
||||||
|
private static void runPhantomReferenceCleanupLoop()
|
||||||
|
{
|
||||||
|
// these arrays are stored here so they don't have to be re-allocated each loop
|
||||||
|
ArrayList<Pair<String, AtomicInteger>> allocationStackTraceCountPairList = new ArrayList<>();
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
allocationStackTraceCountPairList.clear();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.sleep(PHANTOM_REF_CHECK_TIME_IN_MS);
|
||||||
|
}
|
||||||
|
catch (InterruptedException ignore) { }
|
||||||
|
|
||||||
|
int collectedCount = 0;
|
||||||
|
|
||||||
|
Reference<? extends GLBuffer> phantomRef = PHANTOM_REFERENCE_QUEUE.poll();
|
||||||
|
while (phantomRef != null)
|
||||||
|
{
|
||||||
|
// destroy the buffer if it hasn't been cleared yet
|
||||||
|
Integer idRef = PHANTOM_TO_BUFFER_ID.remove((PhantomReference<? extends GLBuffer>)phantomRef); // cast to make IntelliJ happy
|
||||||
|
if (idRef != null)
|
||||||
|
{
|
||||||
|
BUFFER_ID_TO_PHANTOM.remove(idRef);
|
||||||
|
final int id = idRef;
|
||||||
|
RenderThreadTaskHandler.INSTANCE.queueRunningOnRenderThread("GLBuffer phantom destroy", () -> { destroyBufferIdNow(id, "runPhantomReferenceCleanupLoop"); });
|
||||||
|
//LOGGER.info("Buffer Phantom collected, ID: ["+id+"]");
|
||||||
|
|
||||||
|
if (LOG_PHANTOM_ALLOCATION_STACKS) // stack trace shouldn't be null, but just in case
|
||||||
|
{
|
||||||
|
String stack = BUFFER_ID_TO_ALLOCATION_STRING.get(idRef);
|
||||||
|
PhantomLoggingHelper.putAndIncrementTrackingString(stack, allocationStackTraceCountPairList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOGGER.warn("Failed to find Buffer ID for phantom reference: ["+phantomRef+"]");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
collectedCount++;
|
||||||
|
phantomRef = PHANTOM_REFERENCE_QUEUE.poll();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (LOG_PHANTOM_RECOVERY)
|
||||||
|
{
|
||||||
|
// we only want to log when something has been returned
|
||||||
|
if (collectedCount != 0)
|
||||||
|
{
|
||||||
|
LOGGER.warn("GLBuffer phantom recovered: ["+ F3Screen.NUMBER_FORMAT.format(collectedCount)+"].");
|
||||||
|
|
||||||
|
// log stack traces if present
|
||||||
|
if (LOG_PHANTOM_ALLOCATION_STACKS)
|
||||||
|
{
|
||||||
|
PhantomLoggingHelper.LogAllocationStackTracePairCounts(LOGGER, allocationStackTraceCountPairList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
LOGGER.error("Unexpected error in buffer cleanup thread: [" + e.getMessage() + "].", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+56
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Distant Horizons mod
|
||||||
|
* licensed under the GNU LGPL v3 License.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 James Seibel
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.distanthorizons.common.render.openGl.glObject.buffer;
|
||||||
|
|
||||||
|
import org.lwjgl.opengl.GL32;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AKA the GLElementBuffer
|
||||||
|
*
|
||||||
|
* @author James Seibel
|
||||||
|
* @version 11-20-2021
|
||||||
|
*/
|
||||||
|
public class GLIndexBuffer extends GLBuffer
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* When uploading to a buffer that is too small, recreate it this many times
|
||||||
|
* bigger than the upload payload
|
||||||
|
*/
|
||||||
|
protected int indicesCount = 0;
|
||||||
|
protected int glType = GL32.GL_UNSIGNED_INT;
|
||||||
|
public int getGlType() { return this.glType; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public GLIndexBuffer(boolean isBufferStorage) { super(isBufferStorage); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroyAsync()
|
||||||
|
{
|
||||||
|
super.destroyAsync();
|
||||||
|
this.indicesCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBufferBindingTarget() { return GL32.GL_ELEMENT_ARRAY_BUFFER; }
|
||||||
|
|
||||||
|
}
|
||||||
+194
@@ -0,0 +1,194 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Distant Horizons mod
|
||||||
|
* licensed under the GNU LGPL v3 License.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 James Seibel
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.distanthorizons.common.render.openGl.glObject.buffer;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.GLProxy;
|
||||||
|
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.IndexBufferBuilder;
|
||||||
|
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodQuadBuilder;
|
||||||
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
|
import com.seibel.distanthorizons.core.render.RenderThreadTaskHandler;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IVertexBufferWrapper;
|
||||||
|
import org.lwjgl.opengl.GL32;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod;
|
||||||
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a container for a OpenGL
|
||||||
|
* VBO (Vertex Buffer Object).
|
||||||
|
*
|
||||||
|
* @author James Seibel
|
||||||
|
* @version 11-20-2021
|
||||||
|
*/
|
||||||
|
public class GLVertexBuffer extends GLBuffer implements IVertexBufferWrapper
|
||||||
|
{
|
||||||
|
private static final AbstractDhRenderApiDefinition RENDER_DEF = SingletonInjector.INSTANCE.get(AbstractDhRenderApiDefinition.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When uploading to a buffer that is too small, recreate it this many times
|
||||||
|
* bigger than the upload payload
|
||||||
|
*/
|
||||||
|
protected int vertexCount = 0;
|
||||||
|
public int getVertexCount() { return this.vertexCount; }
|
||||||
|
|
||||||
|
|
||||||
|
private GlQuadIndexBuffer quadIBO = null;
|
||||||
|
private static GlQuadIndexBuffer GLOBAL_QUAD_IBO = null;
|
||||||
|
public GlQuadIndexBuffer getQuadIBO()
|
||||||
|
{
|
||||||
|
if (RENDER_DEF.useSingleIbo())
|
||||||
|
{
|
||||||
|
return GLOBAL_QUAD_IBO;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return this.quadIBO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
static
|
||||||
|
{
|
||||||
|
if (RENDER_DEF.useSingleIbo())
|
||||||
|
{
|
||||||
|
RenderThreadTaskHandler.INSTANCE.queueRunningOnRenderThread("Global IBO Creation", () ->
|
||||||
|
{
|
||||||
|
GLOBAL_QUAD_IBO = new GlQuadIndexBuffer();
|
||||||
|
|
||||||
|
int maxSize = LodQuadBuilder.getMaxBufferByteSize();
|
||||||
|
int maxVertexCount = maxSize / LodQuadBuilder.BYTES_PER_VERTEX;
|
||||||
|
int maxQuadCount = (maxVertexCount / 4);
|
||||||
|
|
||||||
|
ByteBuffer buffer = IndexBufferBuilder.createBuffer(maxQuadCount);
|
||||||
|
GLOBAL_QUAD_IBO.upload(buffer, maxQuadCount);
|
||||||
|
MemoryUtil.memFree(buffer);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public GLVertexBuffer() { this(GLProxy.getInstance().getGpuUploadMethod() == EDhApiGpuUploadMethod.BUFFER_STORAGE); }
|
||||||
|
public GLVertexBuffer(boolean isBufferStorage) { super(isBufferStorage); }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//======================//
|
||||||
|
// uploading/destroying //
|
||||||
|
//======================//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBufferBindingTarget() { return GL32.GL_ARRAY_BUFFER; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void uploadVertexBuffer(ByteBuffer buffer, int vertexCount)
|
||||||
|
{
|
||||||
|
EDhApiGpuUploadMethod uploadMethod = GLProxy.getInstance().getGpuUploadMethod();
|
||||||
|
int maxBufferSize = LodQuadBuilder.getMaxBufferByteSize();
|
||||||
|
this.uploadBuffer(buffer, vertexCount, uploadMethod, maxBufferSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bufferSize is the number of shared verticies. <br>
|
||||||
|
* This number will be higher when actually rendered since each box's face needs 2 triangles
|
||||||
|
* with 2 shared verticies.
|
||||||
|
*/
|
||||||
|
public void uploadBuffer(ByteBuffer byteBuffer, int vertexCount, EDhApiGpuUploadMethod uploadMethod, int maxExpansionSize)
|
||||||
|
{
|
||||||
|
if (vertexCount < 0)
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("vertexCount is negative!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// If size is zero, just ignore it.
|
||||||
|
if (byteBuffer.limit() - byteBuffer.position() != 0)
|
||||||
|
{
|
||||||
|
super.uploadBuffer(byteBuffer, uploadMethod, maxExpansionSize, uploadMethod.useBufferStorage ? 0 : GL32.GL_STATIC_DRAW);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.vertexCount = vertexCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void uploadIndexBuffer(ByteBuffer buffer, int vertexCount)
|
||||||
|
{
|
||||||
|
if (RENDER_DEF.useSingleIbo())
|
||||||
|
{
|
||||||
|
// ignore index uploading when running a single IBO
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If size is zero, just ignore it.
|
||||||
|
if (vertexCount == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (this.quadIBO != null)
|
||||||
|
{
|
||||||
|
this.quadIBO.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.quadIBO = new GlQuadIndexBuffer();
|
||||||
|
|
||||||
|
int quadCount = (vertexCount / 4);
|
||||||
|
this.quadIBO.upload(buffer, quadCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// base overrides //
|
||||||
|
//================//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() { this.destroyAsync(); }
|
||||||
|
@Override
|
||||||
|
public void destroyAsync()
|
||||||
|
{
|
||||||
|
super.destroyAsync();
|
||||||
|
if (this.quadIBO != null)
|
||||||
|
{
|
||||||
|
this.quadIBO.destroyAsync();
|
||||||
|
}
|
||||||
|
this.vertexCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+85
@@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Distant Horizons mod
|
||||||
|
* licensed under the GNU LGPL v3 License.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 James Seibel
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.distanthorizons.common.render.openGl.glObject.buffer;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.enums.GLEnums;
|
||||||
|
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.IndexBufferBuilder;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import org.lwjgl.opengl.GL32;
|
||||||
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
/** aka GlQuadElementBuffer */
|
||||||
|
public class GlQuadIndexBuffer extends GLIndexBuffer
|
||||||
|
{
|
||||||
|
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public GlQuadIndexBuffer() { super(false); }
|
||||||
|
|
||||||
|
public void upload(ByteBuffer buffer, int quadCount)
|
||||||
|
{
|
||||||
|
if (quadCount < 0)
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("quadCount must be greater than 0");
|
||||||
|
}
|
||||||
|
if (quadCount == 0)
|
||||||
|
{
|
||||||
|
// shouldn't happen, but just in case
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.indicesCount = quadCount * 6; // 2 triangles per quad
|
||||||
|
if (this.indicesCount >= this.getCapacity()
|
||||||
|
&& this.indicesCount < this.getCapacity() * BUFFER_SHRINK_TRIGGER)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.glType = GL32.GL_UNSIGNED_INT;
|
||||||
|
super.uploadBuffer(buffer, EDhApiGpuUploadMethod.DATA,
|
||||||
|
this.indicesCount * GLEnums.getTypeSize(this.glType), GL32.GL_STATIC_DRAW);
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=========//
|
||||||
|
// getters //
|
||||||
|
//=========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public int getCapacity() { return super.getSize() / GLEnums.getTypeSize(this.getGlType()); }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
package com.seibel.distanthorizons.common.render.openGl.glObject.enums;
|
||||||
|
|
||||||
|
public enum EGlVersion
|
||||||
|
{
|
||||||
|
GL_11,
|
||||||
|
GL_12,
|
||||||
|
GL_30,
|
||||||
|
GL_31
|
||||||
|
}
|
||||||
+261
@@ -0,0 +1,261 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Distant Horizons mod
|
||||||
|
* licensed under the GNU LGPL v3 License.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 James Seibel
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.distanthorizons.common.render.openGl.glObject.enums;
|
||||||
|
|
||||||
|
import static org.lwjgl.opengl.GL46.*;
|
||||||
|
|
||||||
|
// Turns GL int enums back to readable strings
|
||||||
|
public class GLEnums
|
||||||
|
{
|
||||||
|
|
||||||
|
public static String getString(int glEnum)
|
||||||
|
{
|
||||||
|
// blend stuff
|
||||||
|
switch (glEnum)
|
||||||
|
{
|
||||||
|
case GL_ZERO:
|
||||||
|
return "GL_ZERO";
|
||||||
|
case GL_ONE:
|
||||||
|
return "GL_ONE";
|
||||||
|
case GL_SRC_COLOR:
|
||||||
|
return "GL_SRC_COLOR";
|
||||||
|
case GL_ONE_MINUS_SRC_COLOR:
|
||||||
|
return "GL_ONE_MINUS_SRC_COLOR";
|
||||||
|
case GL_DST_COLOR:
|
||||||
|
return "GL_DST_COLOR";
|
||||||
|
case GL_ONE_MINUS_DST_COLOR:
|
||||||
|
return "GL_ONE_MINUS_DST_COLOR";
|
||||||
|
case GL_SRC_ALPHA:
|
||||||
|
return "GL_SRC_ALPHA";
|
||||||
|
case GL_ONE_MINUS_SRC_ALPHA:
|
||||||
|
return "GL_ONE_MINUS_SRC_ALPHA";
|
||||||
|
case GL_DST_ALPHA:
|
||||||
|
return "GL_DST_ALPHA";
|
||||||
|
case GL_ONE_MINUS_DST_ALPHA:
|
||||||
|
return "GL_ONE_MINUS_DST_ALPHA";
|
||||||
|
case GL_CONSTANT_COLOR:
|
||||||
|
return "GL_CONSTANT_COLOR";
|
||||||
|
case GL_ONE_MINUS_CONSTANT_COLOR:
|
||||||
|
return "GL_ONE_MINUS_CONSTANT_COLOR";
|
||||||
|
case GL_CONSTANT_ALPHA:
|
||||||
|
return "GL_CONSTANT_ALPHA";
|
||||||
|
case GL_ONE_MINUS_CONSTANT_ALPHA:
|
||||||
|
return "GL_ONE_MINUS_CONSTANT_ALPHA";
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
// shader stuff
|
||||||
|
switch (glEnum)
|
||||||
|
{
|
||||||
|
case GL_VERTEX_SHADER:
|
||||||
|
return "GL_VERTEX_SHADER";
|
||||||
|
case GL_GEOMETRY_SHADER:
|
||||||
|
return "GL_GEOMETRY_SHADER";
|
||||||
|
case GL_FRAGMENT_SHADER:
|
||||||
|
return "GL_FRAGMENT_SHADER";
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
// stencil stuff
|
||||||
|
switch (glEnum)
|
||||||
|
{
|
||||||
|
case GL_KEEP:
|
||||||
|
return "GL_KEEP";
|
||||||
|
case GL_ZERO:
|
||||||
|
return "GL_ZERO";
|
||||||
|
case GL_REPLACE:
|
||||||
|
return "GL_REPLACE";
|
||||||
|
case GL_INCR:
|
||||||
|
return "GL_INCR";
|
||||||
|
case GL_DECR:
|
||||||
|
return "GL_DECR";
|
||||||
|
case GL_INVERT:
|
||||||
|
return "GL_INVERT";
|
||||||
|
case GL_INCR_WRAP:
|
||||||
|
return "GL_INCR_WRAP";
|
||||||
|
case GL_DECR_WRAP:
|
||||||
|
return "GL_DECR_WRAP";
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
// depth stuff
|
||||||
|
switch (glEnum)
|
||||||
|
{
|
||||||
|
case GL_NEVER:
|
||||||
|
return "GL_NEVER";
|
||||||
|
case GL_LESS:
|
||||||
|
return "GL_LESS";
|
||||||
|
case GL_EQUAL:
|
||||||
|
return "GL_EQUAL";
|
||||||
|
case GL_LEQUAL:
|
||||||
|
return "GL_LEQUAL";
|
||||||
|
case GL_GREATER:
|
||||||
|
return "GL_GREATER";
|
||||||
|
case GL_NOTEQUAL:
|
||||||
|
return "GL_NOTEQUAL";
|
||||||
|
case GL_GEQUAL:
|
||||||
|
return "GL_GEQUAL";
|
||||||
|
case GL_ALWAYS:
|
||||||
|
return "GL_ALWAYS";
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
// Texture binding points
|
||||||
|
switch (glEnum)
|
||||||
|
{
|
||||||
|
case GL_TEXTURE0:
|
||||||
|
return "GL_TEXTURE0";
|
||||||
|
case GL_TEXTURE1:
|
||||||
|
return "GL_TEXTURE1";
|
||||||
|
case GL_TEXTURE2:
|
||||||
|
return "GL_TEXTURE2";
|
||||||
|
case GL_TEXTURE3:
|
||||||
|
return "GL_TEXTURE3";
|
||||||
|
case GL_TEXTURE4:
|
||||||
|
return "GL_TEXTURE4";
|
||||||
|
case GL_TEXTURE5:
|
||||||
|
return "GL_TEXTURE5";
|
||||||
|
case GL_TEXTURE6:
|
||||||
|
return "GL_TEXTURE6";
|
||||||
|
case GL_TEXTURE7:
|
||||||
|
return "GL_TEXTURE7";
|
||||||
|
case GL_TEXTURE8:
|
||||||
|
return "GL_TEXTURE8";
|
||||||
|
case GL_TEXTURE9:
|
||||||
|
return "GL_TEXTURE9";
|
||||||
|
case GL_TEXTURE10:
|
||||||
|
return "GL_TEXTURE10";
|
||||||
|
case GL_TEXTURE11:
|
||||||
|
return "GL_TEXTURE11";
|
||||||
|
case GL_TEXTURE12:
|
||||||
|
return "GL_TEXTURE12";
|
||||||
|
case GL_TEXTURE13:
|
||||||
|
return "GL_TEXTURE13";
|
||||||
|
case GL_TEXTURE14:
|
||||||
|
return "GL_TEXTURE14";
|
||||||
|
case GL_TEXTURE15:
|
||||||
|
return "GL_TEXTURE15";
|
||||||
|
case GL_TEXTURE16:
|
||||||
|
return "GL_TEXTURE16";
|
||||||
|
case GL_TEXTURE17:
|
||||||
|
return "GL_TEXTURE17";
|
||||||
|
case GL_TEXTURE18:
|
||||||
|
return "GL_TEXTURE18";
|
||||||
|
case GL_TEXTURE19:
|
||||||
|
return "GL_TEXTURE19";
|
||||||
|
case GL_TEXTURE20:
|
||||||
|
return "GL_TEXTURE20";
|
||||||
|
case GL_TEXTURE21:
|
||||||
|
return "GL_TEXTURE21";
|
||||||
|
case GL_TEXTURE22:
|
||||||
|
return "GL_TEXTURE22";
|
||||||
|
case GL_TEXTURE23:
|
||||||
|
return "GL_TEXTURE23";
|
||||||
|
case GL_TEXTURE24:
|
||||||
|
return "GL_TEXTURE24";
|
||||||
|
case GL_TEXTURE25:
|
||||||
|
return "GL_TEXTURE25";
|
||||||
|
case GL_TEXTURE26:
|
||||||
|
return "GL_TEXTURE26";
|
||||||
|
case GL_TEXTURE27:
|
||||||
|
return "GL_TEXTURE27";
|
||||||
|
case GL_TEXTURE28:
|
||||||
|
return "GL_TEXTURE28";
|
||||||
|
case GL_TEXTURE29:
|
||||||
|
return "GL_TEXTURE29";
|
||||||
|
case GL_TEXTURE30:
|
||||||
|
return "GL_TEXTURE30";
|
||||||
|
case GL_TEXTURE31:
|
||||||
|
return "GL_TEXTURE31";
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
// Polygon modes
|
||||||
|
switch (glEnum)
|
||||||
|
{
|
||||||
|
case GL_POINT:
|
||||||
|
return "GL_POINT";
|
||||||
|
case GL_LINE:
|
||||||
|
return "GL_LINE";
|
||||||
|
case GL_FILL:
|
||||||
|
return "GL_FILL";
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
// Culling modes
|
||||||
|
switch (glEnum)
|
||||||
|
{
|
||||||
|
case GL_FRONT:
|
||||||
|
return "GL_FRONT";
|
||||||
|
case GL_BACK:
|
||||||
|
return "GL_BACK";
|
||||||
|
case GL_FRONT_AND_BACK:
|
||||||
|
return "GL_FRONT_AND_BACK";
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
// Types
|
||||||
|
switch (glEnum)
|
||||||
|
{
|
||||||
|
case GL_BYTE:
|
||||||
|
return "GL_BYTE";
|
||||||
|
case GL_UNSIGNED_BYTE:
|
||||||
|
return "GL_UNSIGNED_BYTE";
|
||||||
|
case GL_SHORT:
|
||||||
|
return "GL_SHORT";
|
||||||
|
case GL_UNSIGNED_SHORT:
|
||||||
|
return "GL_UNSIGNED_SHORT";
|
||||||
|
case GL_INT:
|
||||||
|
return "GL_INT";
|
||||||
|
case GL_UNSIGNED_INT:
|
||||||
|
return "GL_UNSIGNED_INT";
|
||||||
|
case GL_FLOAT:
|
||||||
|
return "GL_FLOAT";
|
||||||
|
case GL_DOUBLE:
|
||||||
|
return "GL_DOUBLE";
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
return "GL_UNKNOWN(" + glEnum + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getTypeSize(int glTypeEnum)
|
||||||
|
{
|
||||||
|
switch (glTypeEnum)
|
||||||
|
{
|
||||||
|
case GL_BYTE:
|
||||||
|
case GL_UNSIGNED_BYTE:
|
||||||
|
return 1;
|
||||||
|
case GL_SHORT:
|
||||||
|
case GL_UNSIGNED_SHORT:
|
||||||
|
return 2;
|
||||||
|
case GL_INT:
|
||||||
|
case GL_UNSIGNED_INT:
|
||||||
|
return 4;
|
||||||
|
case GL_FLOAT:
|
||||||
|
return 4;
|
||||||
|
case GL_DOUBLE:
|
||||||
|
return 8;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Unknown type enum: " + getString(glTypeEnum));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+184
@@ -0,0 +1,184 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Distant Horizons mod
|
||||||
|
* licensed under the GNU LGPL v3 License.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 James Seibel
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.distanthorizons.common.render.openGl.glObject.shader;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.core.config.Config;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import org.lwjgl.PointerBuffer;
|
||||||
|
import org.lwjgl.opengl.GL32;
|
||||||
|
import org.lwjgl.opengl.GL32C;
|
||||||
|
import org.lwjgl.system.MemoryStack;
|
||||||
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
import org.lwjgl.system.NativeType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This object holds a OpenGL reference to a shader
|
||||||
|
* and allows for reading in and compiling a shader file.
|
||||||
|
*/
|
||||||
|
public class GlShader
|
||||||
|
{
|
||||||
|
private static final DhLogger LOGGER = new DhLoggerBuilder()
|
||||||
|
.fileLevelConfig(Config.Common.Logging.logRendererGLEventToFile)
|
||||||
|
.chatLevelConfig(Config.Common.Logging.logRendererGLEventToChat)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
|
||||||
|
/** OpenGL shader ID */
|
||||||
|
public final int id;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//==============//
|
||||||
|
// constructors //
|
||||||
|
//==============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a shader with specified type.
|
||||||
|
*
|
||||||
|
* @param type Either GL_VERTEX_SHADER or GL_FRAGMENT_SHADER.
|
||||||
|
* @param sourceString File path of the shader
|
||||||
|
* @throws RuntimeException if the shader fails to compile
|
||||||
|
*/
|
||||||
|
public GlShader(int type, String sourceString)
|
||||||
|
{
|
||||||
|
LOGGER.info("Loading shader with type: ["+type+"]");
|
||||||
|
LOGGER.debug("Source: \n["+sourceString+"]");
|
||||||
|
if (sourceString == null || sourceString.isEmpty())
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("No shader source given.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create an empty shader object
|
||||||
|
this.id = GL32.glCreateShader(type);
|
||||||
|
if (this.id == 0)
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("Failed to create shader with type ["+type+"] and Source: \n["+sourceString+"].");
|
||||||
|
}
|
||||||
|
|
||||||
|
safeShaderSource(this.id, sourceString);
|
||||||
|
GL32.glCompileShader(this.id);
|
||||||
|
// check if the shader compiled
|
||||||
|
int status = GL32.glGetShaderi(this.id, GL32.GL_COMPILE_STATUS);
|
||||||
|
if (status != GL32.GL_TRUE)
|
||||||
|
{
|
||||||
|
|
||||||
|
String message = "Shader compiler error. Details: [" + GL32.glGetShaderInfoLog(this.id) + "]\n";
|
||||||
|
message += "Source: \n[" + sourceString + "]";
|
||||||
|
this.free(); // important!
|
||||||
|
throw new RuntimeException(message);
|
||||||
|
}
|
||||||
|
LOGGER.info("Shader loaded sucessfully.");
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=========//
|
||||||
|
// helpers //
|
||||||
|
//=========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identical in function to {@link GL32C#glShaderSource(int, CharSequence)} but
|
||||||
|
* passes a null pointer for string length to force the driver to rely on the null
|
||||||
|
* terminator for string length. This is a workaround for an apparent flaw with some
|
||||||
|
* AMD drivers that don't receive or interpret the length correctly, resulting in
|
||||||
|
* an access violation when the driver tries to read past the string memory.
|
||||||
|
*
|
||||||
|
* <p>Hat tip to fewizz for the find and the fix.
|
||||||
|
*
|
||||||
|
* <p>Source: https://github.com/vram-guild/canvas/commit/820bf754092ccaf8d0c169620c2ff575722d7d96
|
||||||
|
*/
|
||||||
|
private static void safeShaderSource(@NativeType("GLuint") int glId, @NativeType("GLchar const **") CharSequence source)
|
||||||
|
{
|
||||||
|
final MemoryStack stack = MemoryStack.stackGet();
|
||||||
|
final int stackPointer = stack.getPointer();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
final ByteBuffer sourceBuffer = MemoryUtil.memUTF8(source, true);
|
||||||
|
final PointerBuffer pointers = stack.mallocPointer(1);
|
||||||
|
pointers.put(sourceBuffer);
|
||||||
|
|
||||||
|
GL32.nglShaderSource(glId, 1, pointers.address0(), 0);
|
||||||
|
org.lwjgl.system.APIUtil.apiArrayFree(pointers.address0(), 1);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
stack.setPointer(stackPointer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void free() { GL32.glDeleteShader(this.id); }
|
||||||
|
|
||||||
|
public static String loadFile(String path, boolean absoluteFilePath)
|
||||||
|
{
|
||||||
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// open the file
|
||||||
|
InputStream in;
|
||||||
|
if (absoluteFilePath)
|
||||||
|
{
|
||||||
|
// Throws FileNotFoundException
|
||||||
|
in = new FileInputStream(path); // Note: this should use OS path seperator
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
in = GlShader.class.getClassLoader().getResourceAsStream(path); // Note: path seperator should be '/'
|
||||||
|
if (in == null)
|
||||||
|
{
|
||||||
|
throw new FileNotFoundException("Shader file not found in resource: " + path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
|
||||||
|
|
||||||
|
// read in the file
|
||||||
|
String line;
|
||||||
|
while ((line = reader.readLine()) != null)
|
||||||
|
{
|
||||||
|
stringBuilder.append(line).append("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
throw new RuntimeException("Unable to load shader from file [" + path + "]. Error: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return stringBuilder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+250
@@ -0,0 +1,250 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Distant Horizons mod
|
||||||
|
* licensed under the GNU LGPL v3 License.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 James Seibel
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.distanthorizons.common.render.openGl.glObject.shader;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.nio.FloatBuffer;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.api.objects.math.DhApiMat4f;
|
||||||
|
import com.seibel.distanthorizons.api.objects.math.DhApiVec3i;
|
||||||
|
import org.lwjgl.opengl.GL32;
|
||||||
|
import org.lwjgl.system.MemoryStack;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.core.util.math.Mat4f;
|
||||||
|
import com.seibel.distanthorizons.core.util.math.Vec3f;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This object holds the reference to a OpenGL shader program
|
||||||
|
* and contains a few methods that can be used with OpenGL shader programs.
|
||||||
|
* The reason for many of these simple wrapper methods is as reminders of what
|
||||||
|
* can (and needs to be) done with a shader program.
|
||||||
|
*/
|
||||||
|
public class GlShaderProgram
|
||||||
|
{
|
||||||
|
/** Stores the handle of the program. */
|
||||||
|
public final int id;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public GlShaderProgram(String vertResourcePath, String fragResourcePath, String attribute) { this(vertResourcePath, fragResourcePath, new String[]{ attribute }); }
|
||||||
|
/**
|
||||||
|
* @param vertResourcePath the relative path the vertex shader should be found
|
||||||
|
* @param fragResourcePath the relative path the fragment shader should be found
|
||||||
|
*/
|
||||||
|
public GlShaderProgram(String vertResourcePath, String fragResourcePath, String[] attributes)
|
||||||
|
{
|
||||||
|
this.id = GL32.glCreateProgram();
|
||||||
|
|
||||||
|
{
|
||||||
|
String shaderString = GlShader.loadFile(vertResourcePath, false);
|
||||||
|
GlShader vertShader = new GlShader(GL32.GL_VERTEX_SHADER, shaderString);
|
||||||
|
GL32.glAttachShader(this.id, vertShader.id);
|
||||||
|
vertShader.free();
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
String shaderString = GlShader.loadFile(fragResourcePath, false);
|
||||||
|
GlShader fragShader = new GlShader(GL32.GL_FRAGMENT_SHADER, shaderString);
|
||||||
|
GL32.glAttachShader(this.id, fragShader.id);
|
||||||
|
fragShader.free();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < attributes.length; i++)
|
||||||
|
{
|
||||||
|
GL32.glBindAttribLocation(this.id, i, attributes[i]);
|
||||||
|
}
|
||||||
|
GL32.glLinkProgram(this.id);
|
||||||
|
|
||||||
|
int status = GL32.glGetProgrami(this.id, GL32.GL_LINK_STATUS);
|
||||||
|
if (status != GL32.GL_TRUE)
|
||||||
|
{
|
||||||
|
String message = "Shader Link Error. Details: " + GL32.glGetProgramInfoLog(this.id);
|
||||||
|
this.free(); // important!
|
||||||
|
throw new RuntimeException(message);
|
||||||
|
}
|
||||||
|
GL32.glUseProgram(this.id); // This HAVE to be a direct call to prevent calling the overloaded version
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=========//
|
||||||
|
// binding //
|
||||||
|
//=========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public void bind() { GL32.glUseProgram(this.id); }
|
||||||
|
public void unbind() { GL32.glUseProgram(0); }
|
||||||
|
|
||||||
|
public void free() { GL32.glDeleteProgram(this.id); }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//============//
|
||||||
|
// attributes //
|
||||||
|
//============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WARNING: Slow native call! Cache it if possible!
|
||||||
|
* Gets the location of an attribute variable with specified name.
|
||||||
|
* Calls GL20.glGetAttribLocation(id, name)
|
||||||
|
*
|
||||||
|
* @param name Attribute name
|
||||||
|
* @return Location of the attribute
|
||||||
|
* @throws RuntimeException if attribute not found
|
||||||
|
*/
|
||||||
|
public int getAttributeLocation(CharSequence name)
|
||||||
|
{
|
||||||
|
int i = GL32.glGetAttribLocation(id, name);
|
||||||
|
if (i == -1) throw new RuntimeException("Attribute name not found: " + name);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Same as above but without throwing errors. <br>
|
||||||
|
* Returns -1 if the attribute doesn't exist or has been optimized out.
|
||||||
|
*/
|
||||||
|
public int tryGetAttributeLocation(CharSequence name)
|
||||||
|
{ return GL32.glGetAttribLocation(this.id, name); }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//==========//
|
||||||
|
// uniforms //
|
||||||
|
//==========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WARNING: Slow native call! Cache it if possible!
|
||||||
|
* Gets the location of a uniform variable with specified name.
|
||||||
|
* Calls GL20.glGetUniformLocation(id, name)
|
||||||
|
*
|
||||||
|
* @param name Uniform name
|
||||||
|
* @return Location of the Uniform
|
||||||
|
* @throws RuntimeException if uniform not found
|
||||||
|
*/
|
||||||
|
public int getUniformLocation(CharSequence name) throws RuntimeException
|
||||||
|
{
|
||||||
|
int i = GL32.glGetUniformLocation(id, name);
|
||||||
|
if (i == -1)
|
||||||
|
{
|
||||||
|
throw new RuntimeException("Uniform name not found: " + name);
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Same as above but without throwing errors.
|
||||||
|
// Return -1 if uniform doesn't exist or has been optimized out
|
||||||
|
public int tryGetUniformLocation(CharSequence name)
|
||||||
|
{ return GL32.glGetUniformLocation(this.id, name); }
|
||||||
|
|
||||||
|
/** Requires a bound ShaderProgram. */
|
||||||
|
public void setUniform(int location, boolean value) { GL32.glUniform1i(location, value ? 1 : 0); }
|
||||||
|
/** @see GlShaderProgram#setUniform(int, boolean) */
|
||||||
|
public void trySetUniform(int location, boolean value) { if (location != -1) { this.setUniform(location, value); } }
|
||||||
|
|
||||||
|
/** Requires a bound ShaderProgram. */
|
||||||
|
public void setUniform(int location, int value) { GL32.glUniform1i(location, value); }
|
||||||
|
/** @see GlShaderProgram#setUniform(int, int) */
|
||||||
|
public void trySetUniform(int location, int value) { if (location != -1) { this.setUniform(location, value); } }
|
||||||
|
|
||||||
|
/** Requires a bound ShaderProgram. */
|
||||||
|
public void setUniform(int location, float value) { GL32.glUniform1f(location, value); }
|
||||||
|
/** @see GlShaderProgram#setUniform(int, float) */
|
||||||
|
public void trySetUniform(int location, float value) { if (location != -1) { this.setUniform(location, value); } }
|
||||||
|
|
||||||
|
/** Requires a bound ShaderProgram. */
|
||||||
|
public void setUniform(int location, Vec3f value) { GL32.glUniform3f(location, value.x, value.y, value.z); }
|
||||||
|
/** @see GlShaderProgram#setUniform(int, Vec3f) */
|
||||||
|
public void trySetUniform(int location, Vec3f value) { if (location != -1) { this.setUniform(location, value); } }
|
||||||
|
|
||||||
|
/** Requires a bound ShaderProgram. */
|
||||||
|
public void setUniform(int location, DhApiVec3i value) { GL32.glUniform3i(location, value.x, value.y, value.z); }
|
||||||
|
/** @see GlShaderProgram#setUniform(int, DhApiMat4f) */
|
||||||
|
public void trySetUniform(int location, DhApiVec3i value) { if (location != -1) { this.setUniform(location, value); } }
|
||||||
|
|
||||||
|
/** Requires a bound ShaderProgram. */
|
||||||
|
public void setUniform(int location, DhApiMat4f value)
|
||||||
|
{
|
||||||
|
try (MemoryStack stack = MemoryStack.stackPush())
|
||||||
|
{
|
||||||
|
FloatBuffer buffer = stack.mallocFloat(16);
|
||||||
|
storeMatrixInBuffer(value, buffer);
|
||||||
|
GL32.glUniformMatrix4fv(location, false, buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private static void storeMatrixInBuffer(DhApiMat4f matrix, FloatBuffer floatBuffer)
|
||||||
|
{
|
||||||
|
floatBuffer.put(bufferIndex(0, 0), matrix.m00);
|
||||||
|
floatBuffer.put(bufferIndex(0, 1), matrix.m01);
|
||||||
|
floatBuffer.put(bufferIndex(0, 2), matrix.m02);
|
||||||
|
floatBuffer.put(bufferIndex(0, 3), matrix.m03);
|
||||||
|
|
||||||
|
floatBuffer.put(bufferIndex(1, 0), matrix.m10);
|
||||||
|
floatBuffer.put(bufferIndex(1, 1), matrix.m11);
|
||||||
|
floatBuffer.put(bufferIndex(1, 2), matrix.m12);
|
||||||
|
floatBuffer.put(bufferIndex(1, 3), matrix.m13);
|
||||||
|
|
||||||
|
floatBuffer.put(bufferIndex(2, 0), matrix.m20);
|
||||||
|
floatBuffer.put(bufferIndex(2, 1), matrix.m21);
|
||||||
|
floatBuffer.put(bufferIndex(2, 2), matrix.m22);
|
||||||
|
floatBuffer.put(bufferIndex(2, 3), matrix.m23);
|
||||||
|
|
||||||
|
floatBuffer.put(bufferIndex(3, 0), matrix.m30);
|
||||||
|
floatBuffer.put(bufferIndex(3, 1), matrix.m31);
|
||||||
|
floatBuffer.put(bufferIndex(3, 2), matrix.m32);
|
||||||
|
floatBuffer.put(bufferIndex(3, 3), matrix.m33);
|
||||||
|
}
|
||||||
|
private static int bufferIndex(int xIndex, int zIndex) { return (zIndex * 4) + xIndex; }
|
||||||
|
|
||||||
|
/** @see GlShaderProgram#setUniform(int, DhApiMat4f) */
|
||||||
|
public void trySetUniform(int location, Mat4f value) { if (location != -1) { this.setUniform(location, value); } }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the color's RGBA values into values between 0 and 1. <br>
|
||||||
|
* Requires a bound ShaderProgram.
|
||||||
|
*/
|
||||||
|
public void setUniform(int location, Color value)
|
||||||
|
{
|
||||||
|
GL32.glUniform4f(location,
|
||||||
|
value.getRed() / 256.0f,
|
||||||
|
value.getGreen() / 256.0f,
|
||||||
|
value.getBlue() / 256.0f,
|
||||||
|
value.getAlpha() / 256.0f);
|
||||||
|
}
|
||||||
|
/** @see GlShaderProgram#setUniform(int, Color) */
|
||||||
|
public void trySetUniform(int location, Color value) { if (location != -1) { this.setUniform(location, value); } }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+114
@@ -0,0 +1,114 @@
|
|||||||
|
package com.seibel.distanthorizons.common.render.openGl.glObject.texture;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.lwjgl.opengl.GL30C;
|
||||||
|
import org.lwjgl.opengl.GL43C;
|
||||||
|
|
||||||
|
public enum EGlDhDepthBufferFormat
|
||||||
|
{
|
||||||
|
DEPTH(false),
|
||||||
|
DEPTH16(false),
|
||||||
|
DEPTH24(false),
|
||||||
|
DEPTH32(false),
|
||||||
|
DEPTH32F(false),
|
||||||
|
DEPTH_STENCIL(true),
|
||||||
|
DEPTH24_STENCIL8(true),
|
||||||
|
DEPTH32F_STENCIL8(true);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private final boolean combinedStencil;
|
||||||
|
|
||||||
|
EGlDhDepthBufferFormat(boolean combinedStencil) { this.combinedStencil = combinedStencil; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static EGlDhDepthBufferFormat fromGlEnum(int glenum)
|
||||||
|
{
|
||||||
|
switch (glenum)
|
||||||
|
{
|
||||||
|
case GL30C.GL_DEPTH_COMPONENT:
|
||||||
|
return EGlDhDepthBufferFormat.DEPTH;
|
||||||
|
case GL30C.GL_DEPTH_COMPONENT16:
|
||||||
|
return EGlDhDepthBufferFormat.DEPTH16;
|
||||||
|
case GL30C.GL_DEPTH_COMPONENT24:
|
||||||
|
return EGlDhDepthBufferFormat.DEPTH24;
|
||||||
|
case GL30C.GL_DEPTH_COMPONENT32:
|
||||||
|
return EGlDhDepthBufferFormat.DEPTH32;
|
||||||
|
case GL30C.GL_DEPTH_COMPONENT32F:
|
||||||
|
return EGlDhDepthBufferFormat.DEPTH32F;
|
||||||
|
case GL30C.GL_DEPTH_STENCIL:
|
||||||
|
return EGlDhDepthBufferFormat.DEPTH_STENCIL;
|
||||||
|
case GL30C.GL_DEPTH24_STENCIL8:
|
||||||
|
return EGlDhDepthBufferFormat.DEPTH24_STENCIL8;
|
||||||
|
case GL30C.GL_DEPTH32F_STENCIL8:
|
||||||
|
return EGlDhDepthBufferFormat.DEPTH32F_STENCIL8;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static EGlDhDepthBufferFormat fromGlEnumOrDefault(int glenum)
|
||||||
|
{
|
||||||
|
EGlDhDepthBufferFormat format = fromGlEnum(glenum);
|
||||||
|
if (format == null)
|
||||||
|
{
|
||||||
|
// yolo, just assume it's GL_DEPTH_COMPONENT
|
||||||
|
return EGlDhDepthBufferFormat.DEPTH;
|
||||||
|
}
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getGlInternalFormat()
|
||||||
|
{
|
||||||
|
switch (this)
|
||||||
|
{
|
||||||
|
case DEPTH:
|
||||||
|
return GL30C.GL_DEPTH_COMPONENT;
|
||||||
|
case DEPTH16:
|
||||||
|
return GL30C.GL_DEPTH_COMPONENT16;
|
||||||
|
case DEPTH24:
|
||||||
|
return GL30C.GL_DEPTH_COMPONENT24;
|
||||||
|
case DEPTH32:
|
||||||
|
return GL30C.GL_DEPTH_COMPONENT32;
|
||||||
|
case DEPTH32F:
|
||||||
|
return GL30C.GL_DEPTH_COMPONENT32F;
|
||||||
|
case DEPTH_STENCIL:
|
||||||
|
return GL30C.GL_DEPTH_STENCIL;
|
||||||
|
case DEPTH24_STENCIL8:
|
||||||
|
return GL30C.GL_DEPTH24_STENCIL8;
|
||||||
|
case DEPTH32F_STENCIL8:
|
||||||
|
return GL30C.GL_DEPTH32F_STENCIL8;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new AssertionError("unreachable");
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getGlType() { return isCombinedStencil() ? GL30C.GL_DEPTH_STENCIL : GL30C.GL_DEPTH_COMPONENT; }
|
||||||
|
|
||||||
|
public int getGlFormat()
|
||||||
|
{
|
||||||
|
switch (this)
|
||||||
|
{
|
||||||
|
case DEPTH:
|
||||||
|
case DEPTH16:
|
||||||
|
return GL43C.GL_UNSIGNED_SHORT;
|
||||||
|
case DEPTH24:
|
||||||
|
case DEPTH32:
|
||||||
|
return GL43C.GL_UNSIGNED_INT;
|
||||||
|
case DEPTH32F:
|
||||||
|
return GL30C.GL_FLOAT;
|
||||||
|
case DEPTH_STENCIL:
|
||||||
|
case DEPTH24_STENCIL8:
|
||||||
|
return GL30C.GL_UNSIGNED_INT_24_8;
|
||||||
|
case DEPTH32F_STENCIL8:
|
||||||
|
return GL30C.GL_FLOAT_32_UNSIGNED_INT_24_8_REV;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new AssertionError("unreachable");
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCombinedStencil() { return combinedStencil; }
|
||||||
|
|
||||||
|
}
|
||||||
+131
@@ -0,0 +1,131 @@
|
|||||||
|
package com.seibel.distanthorizons.common.render.openGl.glObject.texture;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.enums.EGlVersion;
|
||||||
|
import org.lwjgl.opengl.GL11C;
|
||||||
|
import org.lwjgl.opengl.GL30C;
|
||||||
|
import org.lwjgl.opengl.GL31C;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public enum EGlDhInternalTextureFormat
|
||||||
|
{
|
||||||
|
RGBA(GL11C.GL_RGBA, EGlVersion.GL_11, EGlDhPixelFormat.RGBA),
|
||||||
|
|
||||||
|
// 8-bit normalized
|
||||||
|
R8(GL30C.GL_R8, EGlVersion.GL_30, EGlDhPixelFormat.RED),
|
||||||
|
RG8(GL30C.GL_RG8, EGlVersion.GL_30, EGlDhPixelFormat.RG),
|
||||||
|
RGB8(GL11C.GL_RGB8, EGlVersion.GL_11, EGlDhPixelFormat.RGB),
|
||||||
|
RGBA8(GL11C.GL_RGBA8, EGlVersion.GL_11, EGlDhPixelFormat.RGBA),
|
||||||
|
|
||||||
|
// 8-bit signed normalized
|
||||||
|
R8_SNORM(GL31C.GL_R8_SNORM, EGlVersion.GL_31, EGlDhPixelFormat.RED),
|
||||||
|
RG8_SNORM(GL31C.GL_RG8_SNORM, EGlVersion.GL_31, EGlDhPixelFormat.RG),
|
||||||
|
RGB8_SNORM(GL31C.GL_RGB8_SNORM, EGlVersion.GL_31, EGlDhPixelFormat.RGB),
|
||||||
|
RGBA8_SNORM(GL31C.GL_RGBA8_SNORM, EGlVersion.GL_31, EGlDhPixelFormat.RGBA),
|
||||||
|
|
||||||
|
// 16-bit normalized
|
||||||
|
R16(GL30C.GL_R16, EGlVersion.GL_30, EGlDhPixelFormat.RED),
|
||||||
|
RG16(GL30C.GL_RG16, EGlVersion.GL_30, EGlDhPixelFormat.RG),
|
||||||
|
RGB16(GL11C.GL_RGB16, EGlVersion.GL_11, EGlDhPixelFormat.RGB),
|
||||||
|
RGBA16(GL11C.GL_RGBA16, EGlVersion.GL_11, EGlDhPixelFormat.RGBA),
|
||||||
|
|
||||||
|
// 16-bit signed normalized
|
||||||
|
R16_SNORM(GL31C.GL_R16_SNORM, EGlVersion.GL_31, EGlDhPixelFormat.RED),
|
||||||
|
RG16_SNORM(GL31C.GL_RG16_SNORM, EGlVersion.GL_31, EGlDhPixelFormat.RG),
|
||||||
|
RGB16_SNORM(GL31C.GL_RGB16_SNORM, EGlVersion.GL_31, EGlDhPixelFormat.RGB),
|
||||||
|
RGBA16_SNORM(GL31C.GL_RGBA16_SNORM, EGlVersion.GL_31, EGlDhPixelFormat.RGBA),
|
||||||
|
|
||||||
|
// 16-bit float
|
||||||
|
R16F(GL30C.GL_R16F, EGlVersion.GL_30, EGlDhPixelFormat.RED),
|
||||||
|
RG16F(GL30C.GL_RG16F, EGlVersion.GL_30, EGlDhPixelFormat.RG),
|
||||||
|
RGB16F(GL30C.GL_RGB16F, EGlVersion.GL_30, EGlDhPixelFormat.RGB),
|
||||||
|
RGBA16F(GL30C.GL_RGBA16F, EGlVersion.GL_30, EGlDhPixelFormat.RGBA),
|
||||||
|
|
||||||
|
// 32-bit float
|
||||||
|
R32F(GL30C.GL_R32F, EGlVersion.GL_30, EGlDhPixelFormat.RED),
|
||||||
|
RG32F(GL30C.GL_RG32F, EGlVersion.GL_30, EGlDhPixelFormat.RG),
|
||||||
|
RGB32F(GL30C.GL_RGB32F, EGlVersion.GL_30, EGlDhPixelFormat.RGB),
|
||||||
|
RGBA32F(GL30C.GL_RGBA32F, EGlVersion.GL_30, EGlDhPixelFormat.RGBA),
|
||||||
|
|
||||||
|
// 8-bit integer
|
||||||
|
R8I(GL30C.GL_R8I, EGlVersion.GL_30, EGlDhPixelFormat.RED_INTEGER),
|
||||||
|
RG8I(GL30C.GL_RG8I, EGlVersion.GL_30, EGlDhPixelFormat.RG_INTEGER),
|
||||||
|
RGB8I(GL30C.GL_RGB8I, EGlVersion.GL_30, EGlDhPixelFormat.RGB_INTEGER),
|
||||||
|
RGBA8I(GL30C.GL_RGBA8I, EGlVersion.GL_30, EGlDhPixelFormat.RGBA_INTEGER),
|
||||||
|
|
||||||
|
// 8-bit unsigned integer
|
||||||
|
R8UI(GL30C.GL_R8UI, EGlVersion.GL_30, EGlDhPixelFormat.RED_INTEGER),
|
||||||
|
RG8UI(GL30C.GL_RG8UI, EGlVersion.GL_30, EGlDhPixelFormat.RG_INTEGER),
|
||||||
|
RGB8UI(GL30C.GL_RGB8UI, EGlVersion.GL_30, EGlDhPixelFormat.RGB_INTEGER),
|
||||||
|
RGBA8UI(GL30C.GL_RGBA8UI, EGlVersion.GL_30, EGlDhPixelFormat.RGBA_INTEGER),
|
||||||
|
|
||||||
|
// 16-bit integer
|
||||||
|
R16I(GL30C.GL_R16I, EGlVersion.GL_30, EGlDhPixelFormat.RED_INTEGER),
|
||||||
|
RG16I(GL30C.GL_RG16I, EGlVersion.GL_30, EGlDhPixelFormat.RG_INTEGER),
|
||||||
|
RGB16I(GL30C.GL_RGB16I, EGlVersion.GL_30, EGlDhPixelFormat.RGB_INTEGER),
|
||||||
|
RGBA16I(GL30C.GL_RGBA16I, EGlVersion.GL_30, EGlDhPixelFormat.RGBA_INTEGER),
|
||||||
|
|
||||||
|
// 16-bit unsigned integer
|
||||||
|
R16UI(GL30C.GL_R16UI, EGlVersion.GL_30, EGlDhPixelFormat.RED_INTEGER),
|
||||||
|
RG16UI(GL30C.GL_RG16UI, EGlVersion.GL_30, EGlDhPixelFormat.RG_INTEGER),
|
||||||
|
RGB16UI(GL30C.GL_RGB16UI, EGlVersion.GL_30, EGlDhPixelFormat.RGB_INTEGER),
|
||||||
|
RGBA16UI(GL30C.GL_RGBA16UI, EGlVersion.GL_30, EGlDhPixelFormat.RGBA_INTEGER),
|
||||||
|
|
||||||
|
// 32-bit integer
|
||||||
|
R32I(GL30C.GL_R32I, EGlVersion.GL_30, EGlDhPixelFormat.RED_INTEGER),
|
||||||
|
RG32I(GL30C.GL_RG32I, EGlVersion.GL_30, EGlDhPixelFormat.RG_INTEGER),
|
||||||
|
RGB32I(GL30C.GL_RGB32I, EGlVersion.GL_30, EGlDhPixelFormat.RGB_INTEGER),
|
||||||
|
RGBA32I(GL30C.GL_RGBA32I, EGlVersion.GL_30, EGlDhPixelFormat.RGBA_INTEGER),
|
||||||
|
|
||||||
|
// 32-bit unsigned integer
|
||||||
|
R32UI(GL30C.GL_R32UI, EGlVersion.GL_30, EGlDhPixelFormat.RED_INTEGER),
|
||||||
|
RG32UI(GL30C.GL_RG32UI, EGlVersion.GL_30, EGlDhPixelFormat.RG_INTEGER),
|
||||||
|
RGB32UI(GL30C.GL_RGB32UI, EGlVersion.GL_30, EGlDhPixelFormat.RGB_INTEGER),
|
||||||
|
RGBA32UI(GL30C.GL_RGBA32UI, EGlVersion.GL_30, EGlDhPixelFormat.RGBA_INTEGER),
|
||||||
|
|
||||||
|
// Mixed
|
||||||
|
R3_G3_B2(GL11C.GL_R3_G3_B2, EGlVersion.GL_11, EGlDhPixelFormat.RGB),
|
||||||
|
RGB5_A1(GL11C.GL_RGB5_A1, EGlVersion.GL_11, EGlDhPixelFormat.RGBA),
|
||||||
|
RGB10_A2(GL11C.GL_RGB10_A2, EGlVersion.GL_11, EGlDhPixelFormat.RGBA),
|
||||||
|
R11F_G11F_B10F(GL30C.GL_R11F_G11F_B10F, EGlVersion.GL_30, EGlDhPixelFormat.RGB),
|
||||||
|
RGB9_E5(GL30C.GL_RGB9_E5, EGlVersion.GL_30, EGlDhPixelFormat.RGB);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private final int glFormat;
|
||||||
|
private final EGlVersion minimumGlVersion;
|
||||||
|
private final EGlDhPixelFormat expectedPixelFormat;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
EGlDhInternalTextureFormat(int glFormat, EGlVersion minimumGlVersion, EGlDhPixelFormat expectedPixelFormat)
|
||||||
|
{
|
||||||
|
this.glFormat = glFormat;
|
||||||
|
this.minimumGlVersion = minimumGlVersion;
|
||||||
|
this.expectedPixelFormat = expectedPixelFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static Optional<EGlDhInternalTextureFormat> fromString(String name)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return Optional.of(EGlDhInternalTextureFormat.valueOf(name.toUpperCase(Locale.US)));
|
||||||
|
}
|
||||||
|
catch (IllegalArgumentException e)
|
||||||
|
{
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getGlFormat() { return this.glFormat; }
|
||||||
|
|
||||||
|
public EGlDhPixelFormat getPixelFormat() { return this.expectedPixelFormat; }
|
||||||
|
|
||||||
|
public EGlVersion getMinimumGlVersion() { return this.minimumGlVersion; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+61
@@ -0,0 +1,61 @@
|
|||||||
|
package com.seibel.distanthorizons.common.render.openGl.glObject.texture;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.enums.EGlVersion;
|
||||||
|
import org.lwjgl.opengl.GL11C;
|
||||||
|
import org.lwjgl.opengl.GL12C;
|
||||||
|
import org.lwjgl.opengl.GL30C;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public enum EGlDhPixelFormat
|
||||||
|
{
|
||||||
|
RED(GL11C.GL_RED, EGlVersion.GL_11, false),
|
||||||
|
RG(GL30C.GL_RG, EGlVersion.GL_30, false),
|
||||||
|
RGB(GL11C.GL_RGB, EGlVersion.GL_11, false),
|
||||||
|
BGR(GL12C.GL_BGR, EGlVersion.GL_12, false),
|
||||||
|
RGBA(GL11C.GL_RGBA, EGlVersion.GL_11, false),
|
||||||
|
BGRA(GL12C.GL_BGRA, EGlVersion.GL_12, false),
|
||||||
|
RED_INTEGER(GL30C.GL_RED_INTEGER, EGlVersion.GL_30, true),
|
||||||
|
RG_INTEGER(GL30C.GL_RG_INTEGER, EGlVersion.GL_30, true),
|
||||||
|
RGB_INTEGER(GL30C.GL_RGB_INTEGER, EGlVersion.GL_30, true),
|
||||||
|
BGR_INTEGER(GL30C.GL_BGR_INTEGER, EGlVersion.GL_30, true),
|
||||||
|
RGBA_INTEGER(GL30C.GL_RGBA_INTEGER, EGlVersion.GL_30, true),
|
||||||
|
BGRA_INTEGER(GL30C.GL_BGRA_INTEGER, EGlVersion.GL_30, true);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private final int glFormat;
|
||||||
|
private final EGlVersion minimumGlVersion;
|
||||||
|
private final boolean isInteger;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
EGlDhPixelFormat(int glFormat, EGlVersion minimumGlVersion, boolean isInteger)
|
||||||
|
{
|
||||||
|
this.glFormat = glFormat;
|
||||||
|
this.minimumGlVersion = minimumGlVersion;
|
||||||
|
this.isInteger = isInteger;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static Optional<EGlDhPixelFormat> fromString(String name)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return Optional.of(EGlDhPixelFormat.valueOf(name.toUpperCase(Locale.US)));
|
||||||
|
}
|
||||||
|
catch (IllegalArgumentException e)
|
||||||
|
{
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getGlFormat() { return this.glFormat; }
|
||||||
|
|
||||||
|
public EGlVersion getMinimumGlVersion() { return this.minimumGlVersion; }
|
||||||
|
|
||||||
|
public boolean isInteger() { return this.isInteger; }
|
||||||
|
|
||||||
|
}
|
||||||
+65
@@ -0,0 +1,65 @@
|
|||||||
|
package com.seibel.distanthorizons.common.render.openGl.glObject.texture;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.enums.EGlVersion;
|
||||||
|
import org.lwjgl.opengl.GL11C;
|
||||||
|
import org.lwjgl.opengl.GL12C;
|
||||||
|
import org.lwjgl.opengl.GL30C;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public enum EGlDhPixelType
|
||||||
|
{
|
||||||
|
BYTE(GL11C.GL_BYTE, EGlVersion.GL_11),
|
||||||
|
SHORT(GL11C.GL_SHORT, EGlVersion.GL_11),
|
||||||
|
INT(GL11C.GL_INT, EGlVersion.GL_11),
|
||||||
|
HALF_FLOAT(GL30C.GL_HALF_FLOAT, EGlVersion.GL_30),
|
||||||
|
FLOAT(GL11C.GL_FLOAT, EGlVersion.GL_11),
|
||||||
|
UNSIGNED_BYTE(GL11C.GL_UNSIGNED_BYTE, EGlVersion.GL_11),
|
||||||
|
UNSIGNED_BYTE_3_3_2(GL12C.GL_UNSIGNED_BYTE_3_3_2, EGlVersion.GL_12),
|
||||||
|
UNSIGNED_BYTE_2_3_3_REV(GL12C.GL_UNSIGNED_BYTE_2_3_3_REV, EGlVersion.GL_12),
|
||||||
|
UNSIGNED_SHORT(GL11C.GL_UNSIGNED_SHORT, EGlVersion.GL_11),
|
||||||
|
UNSIGNED_SHORT_5_6_5(GL12C.GL_UNSIGNED_SHORT_5_6_5, EGlVersion.GL_12),
|
||||||
|
UNSIGNED_SHORT_5_6_5_REV(GL12C.GL_UNSIGNED_SHORT_5_6_5_REV, EGlVersion.GL_12),
|
||||||
|
UNSIGNED_SHORT_4_4_4_4(GL12C.GL_UNSIGNED_SHORT_4_4_4_4, EGlVersion.GL_12),
|
||||||
|
UNSIGNED_SHORT_4_4_4_4_REV(GL12C.GL_UNSIGNED_SHORT_4_4_4_4_REV, EGlVersion.GL_12),
|
||||||
|
UNSIGNED_SHORT_5_5_5_1(GL12C.GL_UNSIGNED_SHORT_5_5_5_1, EGlVersion.GL_12),
|
||||||
|
UNSIGNED_SHORT_1_5_5_5_REV(GL12C.GL_UNSIGNED_SHORT_1_5_5_5_REV, EGlVersion.GL_12),
|
||||||
|
UNSIGNED_INT(GL11C.GL_UNSIGNED_INT, EGlVersion.GL_11),
|
||||||
|
UNSIGNED_INT_8_8_8_8(GL12C.GL_UNSIGNED_INT_8_8_8_8, EGlVersion.GL_12),
|
||||||
|
UNSIGNED_INT_8_8_8_8_REV(GL12C.GL_UNSIGNED_INT_8_8_8_8_REV, EGlVersion.GL_12),
|
||||||
|
UNSIGNED_INT_10_10_10_2(GL12C.GL_UNSIGNED_INT_10_10_10_2, EGlVersion.GL_12),
|
||||||
|
UNSIGNED_INT_2_10_10_10_REV(GL12C.GL_UNSIGNED_INT_2_10_10_10_REV, EGlVersion.GL_12);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private final int glFormat;
|
||||||
|
private final EGlVersion minimumGlVersion;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
EGlDhPixelType(int glFormat, EGlVersion minimumGlVersion)
|
||||||
|
{
|
||||||
|
this.glFormat = glFormat;
|
||||||
|
this.minimumGlVersion = minimumGlVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static Optional<EGlDhPixelType> fromString(String name)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return Optional.of(EGlDhPixelType.valueOf(name.toUpperCase(Locale.US)));
|
||||||
|
}
|
||||||
|
catch (IllegalArgumentException e)
|
||||||
|
{
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getGlFormat() { return glFormat; }
|
||||||
|
|
||||||
|
public EGlVersion getMinimumGlVersion() { return minimumGlVersion; }
|
||||||
|
|
||||||
|
}
|
||||||
+183
@@ -0,0 +1,183 @@
|
|||||||
|
package com.seibel.distanthorizons.common.render.openGl.glObject.texture;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
|
||||||
|
import org.joml.Vector2i;
|
||||||
|
import org.lwjgl.opengl.GL11C;
|
||||||
|
import org.lwjgl.opengl.GL13C;
|
||||||
|
import org.lwjgl.opengl.GL43C;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
public class GlDhColorTexture
|
||||||
|
{
|
||||||
|
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
|
||||||
|
|
||||||
|
|
||||||
|
private final EGlDhInternalTextureFormat internalFormat;
|
||||||
|
private final EGlDhPixelFormat format;
|
||||||
|
private final EGlDhPixelType type;
|
||||||
|
private int width;
|
||||||
|
private int height;
|
||||||
|
|
||||||
|
private boolean isValid;
|
||||||
|
/** AKA, the OpenGL name of this texture */
|
||||||
|
private final int id;
|
||||||
|
|
||||||
|
private static final ByteBuffer NULL_BUFFER = null;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
|
||||||
|
public GlDhColorTexture(Builder builder)
|
||||||
|
{
|
||||||
|
this.isValid = true;
|
||||||
|
|
||||||
|
this.internalFormat = builder.internalFormat;
|
||||||
|
this.format = builder.format;
|
||||||
|
this.type = builder.type;
|
||||||
|
|
||||||
|
this.width = builder.width;
|
||||||
|
this.height = builder.height;
|
||||||
|
|
||||||
|
this.id = GL43C.glGenTextures();
|
||||||
|
|
||||||
|
boolean isPixelFormatInteger = builder.internalFormat.getPixelFormat().isInteger();
|
||||||
|
this.setupTexture(this.id, builder.width, builder.height, !isPixelFormatInteger); // this binds the texture
|
||||||
|
|
||||||
|
// Clean up after ourselves
|
||||||
|
// This is strictly defensive to ensure that other buggy code doesn't tamper with our textures
|
||||||
|
GL43C.glBindTexture(GL43C.GL_TEXTURE_2D, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=========//
|
||||||
|
// methods //
|
||||||
|
//=========//
|
||||||
|
|
||||||
|
private void setupTexture(int id, int width, int height, boolean allowsLinear)
|
||||||
|
{
|
||||||
|
this.resizeTexture(id, width, height);
|
||||||
|
|
||||||
|
GL43C.glTexParameteri(GL11C.GL_TEXTURE_2D, GL11C.GL_TEXTURE_MIN_FILTER, allowsLinear ? GL11C.GL_LINEAR : GL11C.GL_NEAREST);
|
||||||
|
GL43C.glTexParameteri(GL11C.GL_TEXTURE_2D, GL11C.GL_TEXTURE_MAG_FILTER, allowsLinear ? GL11C.GL_LINEAR : GL11C.GL_NEAREST);
|
||||||
|
GL43C.glTexParameteri(GL11C.GL_TEXTURE_2D, GL11C.GL_TEXTURE_WRAP_S, GL13C.GL_CLAMP_TO_EDGE);
|
||||||
|
GL43C.glTexParameteri(GL11C.GL_TEXTURE_2D, GL11C.GL_TEXTURE_WRAP_T, GL13C.GL_CLAMP_TO_EDGE);
|
||||||
|
|
||||||
|
// disable mip-mapping since DH is just going to draw straight to the screen
|
||||||
|
GL43C.glTexParameteri(GL43C.GL_TEXTURE_2D, GL43C.GL_TEXTURE_BASE_LEVEL, 0);
|
||||||
|
GL43C.glTexParameteri(GL43C.GL_TEXTURE_2D, GL43C.GL_TEXTURE_MAX_LEVEL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void resizeTexture(int texture, int width, int height)
|
||||||
|
{
|
||||||
|
GL43C.glBindTexture(GL43C.GL_TEXTURE_2D, texture);
|
||||||
|
GL43C.glTexImage2D(GL11C.GL_TEXTURE_2D, 0, this.internalFormat.getGlFormat(), width, height, 0, this.format.getGlFormat(), this.type.getGlFormat(), NULL_BUFFER);
|
||||||
|
}
|
||||||
|
|
||||||
|
void resize(Vector2i textureScaleOverride) { this.resize(textureScaleOverride.x, textureScaleOverride.y); }
|
||||||
|
|
||||||
|
// Package private, call CompositeRenderTargets#resizeIfNeeded instead.
|
||||||
|
public void resize(int width, int height)
|
||||||
|
{
|
||||||
|
this.throwIfInvalid();
|
||||||
|
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
|
||||||
|
this.resizeTexture(this.id, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
public EGlDhInternalTextureFormat getInternalFormat() { return this.internalFormat; }
|
||||||
|
|
||||||
|
public int getTextureId()
|
||||||
|
{
|
||||||
|
this.throwIfInvalid();
|
||||||
|
return this.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getWidth() { return this.width; }
|
||||||
|
|
||||||
|
public int getHeight() { return this.height; }
|
||||||
|
|
||||||
|
public void destroy()
|
||||||
|
{
|
||||||
|
this.throwIfInvalid();
|
||||||
|
this.isValid = false;
|
||||||
|
|
||||||
|
GLMC.glDeleteTextures(this.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @throws IllegalStateException if the texture isn't valid */
|
||||||
|
private void throwIfInvalid()
|
||||||
|
{
|
||||||
|
if (!this.isValid)
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("Attempted to use a deleted composite render target");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Builder builder() { return new Builder(); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// helper classes //
|
||||||
|
//================//
|
||||||
|
|
||||||
|
public static class Builder
|
||||||
|
{
|
||||||
|
private EGlDhInternalTextureFormat internalFormat = EGlDhInternalTextureFormat.RGBA8;
|
||||||
|
private int width = 0;
|
||||||
|
private int height = 0;
|
||||||
|
private EGlDhPixelFormat format = EGlDhPixelFormat.RGBA;
|
||||||
|
private EGlDhPixelType type = EGlDhPixelType.UNSIGNED_BYTE;
|
||||||
|
|
||||||
|
private Builder()
|
||||||
|
{
|
||||||
|
// No-op
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setInternalFormat(EGlDhInternalTextureFormat format)
|
||||||
|
{
|
||||||
|
this.internalFormat = format;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setDimensions(int width, int height)
|
||||||
|
{
|
||||||
|
if (width <= 0)
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("Width must be greater than zero");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (height <= 0)
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("Height must be greater than zero");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setPixelFormat(EGlDhPixelFormat pixelFormat)
|
||||||
|
{
|
||||||
|
this.format = pixelFormat;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setPixelType(EGlDhPixelType pixelType)
|
||||||
|
{
|
||||||
|
this.type = pixelType;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GlDhColorTexture build() { return new GlDhColorTexture(this); }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
+62
@@ -0,0 +1,62 @@
|
|||||||
|
package com.seibel.distanthorizons.common.render.openGl.glObject.texture;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
|
||||||
|
import org.lwjgl.opengl.GL11C;
|
||||||
|
import org.lwjgl.opengl.GL13C;
|
||||||
|
import org.lwjgl.opengl.GL43C;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
public class GlDhDepthTexture
|
||||||
|
{
|
||||||
|
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
|
||||||
|
|
||||||
|
|
||||||
|
private int id;
|
||||||
|
public GlDhDepthTexture(int width, int height, EGlDhDepthBufferFormat format)
|
||||||
|
{
|
||||||
|
this.id = GL43C.glGenTextures();
|
||||||
|
|
||||||
|
this.resize(width, height, format);
|
||||||
|
|
||||||
|
GL43C.glTexParameteri(GL11C.GL_TEXTURE_2D, GL11C.GL_TEXTURE_MIN_FILTER, GL11C.GL_NEAREST);
|
||||||
|
GL43C.glTexParameteri(GL11C.GL_TEXTURE_2D, GL11C.GL_TEXTURE_MAG_FILTER, GL11C.GL_NEAREST);
|
||||||
|
GL43C.glTexParameteri(GL11C.GL_TEXTURE_2D, GL11C.GL_TEXTURE_WRAP_S, GL13C.GL_CLAMP_TO_EDGE);
|
||||||
|
GL43C.glTexParameteri(GL11C.GL_TEXTURE_2D, GL11C.GL_TEXTURE_WRAP_T, GL13C.GL_CLAMP_TO_EDGE);
|
||||||
|
|
||||||
|
// disable mip-mapping since DH is just going to draw straight to the screen
|
||||||
|
GL43C.glTexParameteri(GL43C.GL_TEXTURE_2D, GL43C.GL_TEXTURE_BASE_LEVEL, 0);
|
||||||
|
GL43C.glTexParameteri(GL43C.GL_TEXTURE_2D, GL43C.GL_TEXTURE_MAX_LEVEL, 0);
|
||||||
|
|
||||||
|
GL43C.glBindTexture(GL43C.GL_TEXTURE_2D, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For internal use by Iris for copying data. Do not use this in DH.
|
||||||
|
public GlDhDepthTexture(int id) { this.id = id; }
|
||||||
|
|
||||||
|
public void resize(int width, int height, EGlDhDepthBufferFormat format)
|
||||||
|
{
|
||||||
|
GL43C.glBindTexture(GL43C.GL_TEXTURE_2D, this.getTextureId());
|
||||||
|
GL43C.glTexImage2D(GL11C.GL_TEXTURE_2D, 0, format.getGlInternalFormat(), width, height, 0,
|
||||||
|
format.getGlType(), format.getGlFormat(), (ByteBuffer) null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTextureId()
|
||||||
|
{
|
||||||
|
if (this.id == -1)
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("Depth texture does not exist!");
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void destroy()
|
||||||
|
{
|
||||||
|
GLMC.glDeleteTextures(this.getTextureId());
|
||||||
|
this.id = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+92
@@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Distant Horizons mod
|
||||||
|
* licensed under the GNU LGPL v3 License.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 James Seibel
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.seibel.distanthorizons.common.render.openGl.glObject.vertexAttribute;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.GLProxy;
|
||||||
|
import org.lwjgl.opengl.GL32;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base for binding/unbinding Vertex Attribute objects (VAO's).
|
||||||
|
*
|
||||||
|
* @see GlVertexAttributePostGL43
|
||||||
|
* @see GlVertexAttributePreGL43
|
||||||
|
*/
|
||||||
|
public abstract class GlAbstractVertexAttribute
|
||||||
|
{
|
||||||
|
/** Stores the handle of the AbstractVertexAttribute. */
|
||||||
|
public final int id;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//==============//
|
||||||
|
// constructors //
|
||||||
|
//==============//
|
||||||
|
|
||||||
|
// This will bind AbstractVertexAttribute
|
||||||
|
protected GlAbstractVertexAttribute()
|
||||||
|
{
|
||||||
|
this.id = GL32.glGenVertexArrays();
|
||||||
|
GL32.glBindVertexArray(this.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GlAbstractVertexAttribute create()
|
||||||
|
{
|
||||||
|
if (GLProxy.getInstance().vertexAttributeBufferBindingSupported)
|
||||||
|
{
|
||||||
|
return new GlVertexAttributePostGL43();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new GlVertexAttributePreGL43();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=========//
|
||||||
|
// binding //
|
||||||
|
//=========//
|
||||||
|
|
||||||
|
public void bind() { GL32.glBindVertexArray(this.id); }
|
||||||
|
public void unbind() { GL32.glBindVertexArray(0); }
|
||||||
|
|
||||||
|
/** Always remember to always free your resources! */
|
||||||
|
public void free() { GL32.glDeleteVertexArrays(this.id); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//==================//
|
||||||
|
// abstract methods //
|
||||||
|
//==================//
|
||||||
|
|
||||||
|
/** Requires both AbstractVertexAttribute and VertexBuffer to be bound */
|
||||||
|
public abstract void bindBufferToAllBindingPoints(int buffer);
|
||||||
|
/** Requires both AbstractVertexAttribute and VertexBuffer to be bound */
|
||||||
|
public abstract void bindBufferToBindingPoint(int buffer, int bindingPoint);
|
||||||
|
/** Requires both AbstractVertexAttribute to be bound */
|
||||||
|
public abstract void unbindBuffersFromAllBindingPoint();
|
||||||
|
/** Requires both AbstractVertexAttribute to be bound */
|
||||||
|
public abstract void unbindBuffersFromBindingPoint(int bindingPoint);
|
||||||
|
/** Requires both AbstractVertexAttribute to be bound */
|
||||||
|
public abstract void setVertexAttribute(int bindingPoint, int attributeIndex, GlVertexPointer attribute);
|
||||||
|
/** Requires both AbstractVertexAttribute to be bound */
|
||||||
|
public abstract void completeAndCheck(int expectedStrideSize);
|
||||||
|
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user