Compare commits
471 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 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 | |||
| 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 | |||
| d360402bc3 | |||
| cb59d76f09 | |||
| 7512a41ef7 | |||
| 7d083bdad2 | |||
| 9972363846 | |||
| 4f171234c4 | |||
| 6c56d09b18 | |||
| 2716059840 | |||
| a60887e9a7 | |||
| 1b6c5a451a | |||
| 4e91911e58 | |||
| bfae194919 | |||
| e562b2fdca | |||
| 47fa6d7d8b | |||
| 053d1333ca | |||
| 961c4190ad | |||
| 2f2ac0859c | |||
| b59781b064 | |||
| 39cc5bb8aa | |||
| abdbc73865 | |||
| 596f9f834a | |||
| 8f2aaf4ef4 | |||
| 2320740a4a | |||
| 4f0dc07995 | |||
| 336a9a94c8 | |||
| 1158496d9d | |||
| 84479ed48c | |||
| 0c71ca96c6 | |||
| 43dff26063 | |||
| 3cba883ba2 | |||
| 2d2e7524ae | |||
| e8ff7abaea | |||
| 008ad52bbc | |||
| d0b44a1ffc | |||
| 4ffe430686 | |||
| 19ca97c6c1 | |||
| 3334394bfd | |||
| 180e7cd814 | |||
| 84cf4505f2 | |||
| 1d74eea3ef | |||
| 6ee2e6be25 | |||
| b5c47d67cb | |||
| ead59d0817 | |||
| 1c9229c8f1 | |||
| 968a14c6a5 | |||
| 5608db9c56 | |||
| 81b6a25805 | |||
| 276d90b3e6 | |||
| 851c7439d5 | |||
| c902357a8f | |||
| 63170078f5 | |||
| d0dd1f125b | |||
| 32950d793e | |||
| 54e9bad907 | |||
| bb4ac770bd | |||
| 16afada6e9 | |||
| 7d0785a5fa | |||
| 6a67df462b | |||
| 0c45c76ff8 | |||
| bcb442e38d | |||
| 977ae471ea | |||
| b1701ab0d0 | |||
| c048d5cb56 | |||
| 2702f742d6 | |||
| 7add025c8a | |||
| 9dc220feb2 | |||
| 79955252c9 | |||
| bf13cc48a3 | |||
| cf454c80d7 | |||
| e6404cd882 | |||
| 52e64dc403 | |||
| 7c858afc5d | |||
| a44a5d7465 | |||
| f2d373b779 | |||
| 5138af0b78 | |||
| 37e99cd0a5 | |||
| 6cb8cd2bd9 | |||
| c5ae7da96c | |||
| 59b886c5e3 | |||
| 01e78f249f | |||
| e1c3da59db | |||
| cdfb46b041 | |||
| f944fe4409 | |||
| c2e45f3d65 | |||
| a9c4f3ea46 | |||
| 204d48517b | |||
| 759ec3676c | |||
| 8d2b5fa3ce | |||
| 2851b2c2db | |||
| e5ea86bf8f | |||
| 533c6a7f93 | |||
| ff41e070fd | |||
| b3f607e132 | |||
| 9ecbb9cc9f | |||
| 7888de8200 | |||
| d2327ae836 | |||
| ea92a8f922 | |||
| 47e97630b4 | |||
| c518345bcd | |||
| c250a7408e | |||
| 30da01f580 | |||
| 2c71c2bf76 | |||
| 13a4505d7d | |||
| 7f0eeb9f15 | |||
| d7eabcf3a6 | |||
| 7047d0afdf | |||
| f318b52280 | |||
| f50613e20c | |||
| af3a993042 | |||
| ace1aab42e | |||
| 350d72b6ec | |||
| 986a6cdc19 | |||
| 2aa8d9f489 | |||
| 5652a9328c | |||
| b7253b6549 | |||
| e026cf104c | |||
| ab4a9cbb55 | |||
| a709ab6071 | |||
| 3c11a2dc33 | |||
| ce2aa6602a | |||
| 738aff8ec6 | |||
| 91da0bf252 | |||
| af8dea9d9f | |||
| 384933d351 | |||
| a5344d50c2 | |||
| 2b4c5b91a4 | |||
| 3090544b85 | |||
| 75e1bbbe17 | |||
| 31b604b5c8 | |||
| 70ba93abec | |||
| f628a7f21e | |||
| 254f51ea5e | |||
| d44152dc46 | |||
| 0ef979ee6c | |||
| f67fb1758d | |||
| cf643372b6 | |||
| dc1a117f6b | |||
| 2545c7e76d | |||
| 506ba05b34 | |||
| 70be3f9364 | |||
| 8d9b5f66fa | |||
| 3a01151137 | |||
| 197051747a | |||
| 45efeb96fa | |||
| e05dff3fb9 | |||
| aec28854a3 | |||
| 106d97e0a1 | |||
| 63acd94fd4 | |||
| 34412305d0 | |||
| 6a418de153 | |||
| 41c6b2936b | |||
| 97130d1535 | |||
| d61dcfaab6 | |||
| 3c3f1ef41b | |||
| ed1d6396fd | |||
| 518ec18362 | |||
| 5715cd9266 | |||
| 56953efabc | |||
| 351802de4c | |||
| f60e74c838 | |||
| 2007a6af24 | |||
| 4bc199fe14 | |||
| bcd9a0da2c | |||
| 50c97e3ca3 | |||
| 7539cb94d4 | |||
| 3a20329096 | |||
| 702002c540 | |||
| 7f790e2c9c | |||
| b3f8b03fdf | |||
| 3597d69fa4 | |||
| ab10265150 | |||
| 671ee84136 | |||
| c489cebae3 | |||
| e55eeda1ac | |||
| 0086f40053 | |||
| 71bb151e61 | |||
| a71ceac15d | |||
| ada36c34c7 | |||
| 3cfb4386d9 | |||
| 352d0f4759 | |||
| d158a89592 | |||
| 9cc826f8a9 | |||
| 22a4c6bc79 | |||
| 20b9f4f1cb | |||
| 5c0c1c5e20 | |||
| 69645994c9 | |||
| fdcbb0594d | |||
| e5711b4ddb | |||
| cb1a617b92 | |||
| 4187eaf112 | |||
| 084de2b3f1 | |||
| 7b0a9d4843 | |||
| c42f800db5 | |||
| 300ef3745f | |||
| 5a9fdb3314 | |||
| 8708ca3048 | |||
| 9cfdbdc0ca | |||
| 48f82b0966 | |||
| 75f7ef0085 | |||
| 270776a782 | |||
| 21fff72521 | |||
| a860a9740d | |||
| a2105699fa | |||
| ea4838c791 | |||
| 9168543945 | |||
| 460996d8cd | |||
| c3948abc40 | |||
| 8ed902f6f2 | |||
| 15dda30050 | |||
| 26428ff905 | |||
| 4419ab4b8c | |||
| 5d50994beb | |||
| ce9f843048 | |||
| 8c934b4982 | |||
| 9ae41865f3 | |||
| ade7a8d8dc | |||
| 461dad9fe8 | |||
| b832e77ac2 | |||
| 66c41e49db | |||
| 0f968255e0 | |||
| ed50161cfd | |||
| 7e18acdb8f | |||
| 5c05fdd9fa | |||
| afca4d837f | |||
| 6db3795fa5 | |||
| 21fe38da8e | |||
| 340c0bc586 | |||
| 77c7ebc0d0 | |||
| f55cb4b320 | |||
| 9d3c88f0b2 | |||
| e397a3e47a | |||
| 4ff315de91 | |||
| 2fb1c43d7c | |||
| 58b5fac20b | |||
| ec238d29c6 | |||
| dac36c9e34 | |||
| caca05c0f0 | |||
| 5ce7eae7c0 | |||
| 2c38401637 | |||
| 489fe753f5 | |||
| 2293afc2d3 | |||
| b48adeb3e3 | |||
| 438186cb70 | |||
| c86ff4acae | |||
| e27e1bc2d7 | |||
| 336bf2ea26 | |||
| e72c08b0bc | |||
| 4ced316304 | |||
| c84ee721e3 | |||
| c46c056980 | |||
| d486878876 | |||
| b0b0b38bf8 | |||
| 9e43896864 | |||
| d09ddf57d3 | |||
| 486edac1d8 | |||
| 3b3731a137 | |||
| 563ec70154 | |||
| 175f5ed6d6 | |||
| 1e63607233 | |||
| 4dd8be23fa | |||
| 7fac5b4c6e | |||
| f2ec1ecf3f | |||
| 2674e6b2e9 | |||
| bcbe3f0fb7 | |||
| f85108ed11 | |||
| 2bc5169ce5 | |||
| 1edd809708 | |||
| 475111b38b | |||
| b44a967e56 | |||
| acea685e75 | |||
| 20f15a6b39 | |||
| debf52418c | |||
| cf71491381 | |||
| 0a4a8466cf | |||
| 31fac60d34 | |||
| c335020c2f | |||
| 4db4f2fbc6 | |||
| f9f4a208e7 | |||
| b5fa5936b3 | |||
| 6ceabe7895 | |||
| ec3d8afbfc | |||
| e9a0c6d097 | |||
| 0238568370 | |||
| 74be00e025 | |||
| c10af6dd04 | |||
| 85ee5ac833 | |||
| 21877d67a5 | |||
| ae33a79d6e | |||
| 9204b357d8 | |||
| 78b1b74036 | |||
| 864c5b5f86 | |||
| b271c8e119 | |||
| 79bdae5b8b | |||
| d5dc9f6b79 | |||
| a50f13caa0 | |||
| 75b3649a97 | |||
| 69adb54b91 | |||
| 458c1ae7e0 | |||
| a647551d26 | |||
| 3a45bdd2a2 | |||
| 4806cd2445 | |||
| af7f90f128 | |||
| f72ad60f58 | |||
| 6015afbf4c | |||
| 0369ae63f3 | |||
| 278d5063fb | |||
| a64e72034e | |||
| fcdb56660c | |||
| 0c26261cd5 | |||
| b50525fff9 | |||
| 92e403823b | |||
| e02f56f4ef | |||
| aa4681e044 | |||
| 1c9130c3f1 | |||
| c3597cd843 | |||
| d4a52ac5a3 | |||
| 1b9d14e7b4 | |||
| 0ea27b676e | |||
| cd73608b07 | |||
| 03fc22f611 | |||
| cc251e46b0 | |||
| 7aa0bfefec | |||
| 9bdad5e4f1 | |||
| baebb7323d | |||
| 8a3175f345 | |||
| dc58efb301 | |||
| c9ac4b2ada | |||
| 6e1ec476ed | |||
| d1aa5a524b | |||
| 5c661a3a76 |
+2
-3
@@ -5,14 +5,13 @@ root = true
|
|||||||
|
|
||||||
[*]
|
[*]
|
||||||
charset = utf-8
|
charset = utf-8
|
||||||
end_of_line = crlf
|
|
||||||
indent_size = 4
|
indent_size = 4
|
||||||
indent_style = space
|
indent_style = space
|
||||||
insert_final_newline = false
|
insert_final_newline = false
|
||||||
max_line_length = 1000
|
max_line_length = 1000
|
||||||
tab_width = 4
|
tab_width = 4
|
||||||
trim_trailing_whitespace = false
|
trim_trailing_whitespace = false
|
||||||
ij_continuation_indent_size = 8
|
ij_continuation_indent_size = 4
|
||||||
ij_formatter_off_tag = @formatter:off
|
ij_formatter_off_tag = @formatter:off
|
||||||
ij_formatter_on_tag = @formatter:on
|
ij_formatter_on_tag = @formatter:on
|
||||||
ij_formatter_tags_enabled = true
|
ij_formatter_tags_enabled = true
|
||||||
@@ -688,7 +687,7 @@ ij_markdown_wrap_text_inside_blockquotes = true
|
|||||||
ij_toml_keep_indents_on_empty_lines = false
|
ij_toml_keep_indents_on_empty_lines = false
|
||||||
|
|
||||||
[{*.yaml,*.yml}]
|
[{*.yaml,*.yml}]
|
||||||
indent_size = 2
|
indent_size = 4
|
||||||
ij_yaml_align_values_properties = do_not_align
|
ij_yaml_align_values_properties = do_not_align
|
||||||
ij_yaml_autoinsert_sequence_marker = true
|
ij_yaml_autoinsert_sequence_marker = true
|
||||||
ij_yaml_block_mapping_on_new_line = false
|
ij_yaml_block_mapping_on_new_line = false
|
||||||
|
|||||||
+13
-31
@@ -3,10 +3,8 @@
|
|||||||
image: eclipse-temurin:21
|
image: eclipse-temurin:21
|
||||||
|
|
||||||
# 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:
|
||||||
- build
|
- build
|
||||||
- multiversion
|
|
||||||
- api
|
- api
|
||||||
- pages
|
- pages
|
||||||
|
|
||||||
@@ -36,49 +34,33 @@ build:
|
|||||||
stage: build
|
stage: build
|
||||||
parallel:
|
parallel:
|
||||||
matrix:
|
matrix:
|
||||||
- MC_VER: ["1.16.5", "1.17.1", "1.18.2", "1.19.2", "1.19.4", "1.20.1", "1.20.2", "1.20.4", "1.20.6", "1.21.1", "1.21.3", "1.21.4", "1.21.5"]
|
- MC_VER: [
|
||||||
|
"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.19.4", "1.19.2",
|
||||||
|
"1.18.2",
|
||||||
|
"1.17.1",
|
||||||
|
"1.16.5"
|
||||||
|
]
|
||||||
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 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/;
|
- ./gradlew mergeJars -PmcVer="${MC_VER}" -PinfoGitCommit="${CI_COMMIT_SHA}" -PinfoGitBranch="${CI_COMMIT_BRANCH}" -PinfoBuildSource="GitLab CI (${CI_PIPELINE_ID})" --gradle-user-home cache/;
|
||||||
- cp ./build/forgix/* . || true
|
- cp ./fabric/build/libs/* ./forge/build/libs/* ./neoforge/build/libs/* ./build/merged/* . || true
|
||||||
- mkdir -p ./builds
|
|
||||||
- cp ./fabric/build/libs/* ./forge/build/libs/* ./neoforge/build/libs/* ./builds || true
|
|
||||||
# When the archive is created, the merged jar will be the main jar and a subfolder named "builds" will contain the other jars
|
|
||||||
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:
|
||||||
- ./*.jar
|
- ./*.jar
|
||||||
- ./builds/*.jar
|
|
||||||
exclude:
|
exclude:
|
||||||
- ./builds/*-all.jar
|
- ./*-all.jar
|
||||||
- ./builds/*-dev.jar
|
- ./*-dev.jar
|
||||||
- ./builds/*-sources.jar
|
- ./*-sources.jar
|
||||||
expire_in: 14 days
|
expire_in: 14 days
|
||||||
when: always
|
when: always
|
||||||
extends: .build_java
|
extends: .build_java
|
||||||
|
|
||||||
|
|
||||||
multiversion:
|
|
||||||
stage: multiversion
|
|
||||||
needs: [build]
|
|
||||||
script:
|
|
||||||
# Create a semicolon-separated list of jar paths
|
|
||||||
- MC_VER_PATHS=$(find . -maxdepth 1 -name "*.jar" -type f | tr '\n' ';')
|
|
||||||
# Run the mergeVersions task
|
|
||||||
- ./gradlew mergeVersions -PmergeVersions="${MC_VER_PATHS}" -PinfoGitCommit="${CI_COMMIT_SHA}" -PinfoGitBranch="${CI_COMMIT_BRANCH}" -PinfoBuildSource="GitLab CI (${CI_PIPELINE_ID})" --gradle-user-home cache/;
|
|
||||||
# Clean up existing jars and make sure only the multiversion jar remains which will be uploaded
|
|
||||||
- rm -f ./*.jar
|
|
||||||
- cp ./build/forgix/multiversion/* .
|
|
||||||
artifacts:
|
|
||||||
name: "NightlyBuild_Multiversion-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
|
|
||||||
paths:
|
|
||||||
- ./*.jar
|
|
||||||
expire_in: 30 days
|
|
||||||
when: always
|
|
||||||
extends: .build_java
|
|
||||||
|
|
||||||
|
|
||||||
api:
|
api:
|
||||||
stage: api
|
stage: api
|
||||||
needs: []
|
needs: []
|
||||||
|
|||||||
@@ -1,3 +1,37 @@
|
|||||||
Before creating an issue, please select the appropriate template from the dropdown above.
|
## Check off each item in this list before submitting:
|
||||||
|
|
||||||
|
<!--
|
||||||
|
To mark a section as complete either put an "x" in between the square brackets, example: "[x]"
|
||||||
|
Or click the checkbox once the issue has been created.
|
||||||
|
-->
|
||||||
|
|
||||||
|
1. [ ] Check the FAQ to see if your issue has already been reported and has a solution:
|
||||||
|
[Problems-and-solutions](https://gitlab.com/distant-horizons-team/distant-horizons/-/wikis/1-user-guide/1-frequently-asked-questions/2-problems-and-solutions/Problems-and-Solutions)
|
||||||
|
|
||||||
|
2. [ ] Make sure you are not using any mods on the incompatible list:
|
||||||
|
[Mod support FAQ](https://gitlab.com/distant-horizons-team/distant-horizons/-/wikis/1-user-guide/1-frequently-asked-questions/4-mod-support/Mod-Support)
|
||||||
|
|
||||||
|
3. [ ] Check the existing issues to verify that your bug hasn't already been submitted:
|
||||||
|
[Issues](https://gitlab.com/distant-horizons-team/distant-horizons/-/issues)
|
||||||
|
|
||||||
|
4. [ ] Upload Minecraft's crash report and/or log. \
|
||||||
|
Minecraft crash reports are located in: `.minecraft/crash-reports` \
|
||||||
|
Minecraft logs are located in: `.minecraft/logs`
|
||||||
|
|
||||||
|
5. [ ] Upload your Distant Horizons Config. \
|
||||||
|
The config is found in: `.minecraft/configs/DistantHorizons.toml`
|
||||||
|
|
||||||
|
6. [ ] Fill out the information below:
|
||||||
|
|
||||||
|
* **minecraft version**:
|
||||||
|
|
||||||
|
* **Distant Horizons version**:
|
||||||
|
|
||||||
|
* **Mod loader**:
|
||||||
|
|
||||||
|
* **Installed mods (list the smallest number of mods that you can use to re-create the bug)**:
|
||||||
|
|
||||||
|
* **Describe the bug**:
|
||||||
|
|
||||||
|
* **Steps to reproduce the bug**:
|
||||||
|
|
||||||
The template will walk you through submitting a bug, feature, or improvement request.
|
|
||||||
|
|||||||
+65
-83
@@ -5,6 +5,9 @@ import org.apache.tools.zip.ZipEntry
|
|||||||
import javax.annotation.Nonnull
|
import javax.annotation.Nonnull
|
||||||
import org.apache.tools.zip.ZipOutputStream
|
import org.apache.tools.zip.ZipOutputStream
|
||||||
|
|
||||||
|
import java.util.function.Function
|
||||||
|
import java.util.function.Predicate
|
||||||
|
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id "java"
|
id "java"
|
||||||
@@ -13,23 +16,15 @@ plugins {
|
|||||||
id "com.github.johnrengelman.shadow" version '8.1.1' apply false
|
id "com.github.johnrengelman.shadow" version '8.1.1' apply false
|
||||||
|
|
||||||
// Plugin to create merged jars
|
// Plugin to create merged jars
|
||||||
id "io.github.pacifistmc.forgix" version "2.0.0-SNAPSHOT.2"
|
id "io.github.pacifistmc.forgix" version "1.3.4"
|
||||||
|
|
||||||
// Manifold preprocessor
|
// Manifold preprocessor
|
||||||
id "systems.manifold.manifold-gradle-plugin" version "0.0.2-alpha"
|
id "systems.manifold.manifold-gradle-plugin" version "0.0.2-alpha"
|
||||||
|
|
||||||
// Architectury is used here only as a replacement for forge's own loom
|
// Architectury is used here only as a replacement for forge's own loom
|
||||||
id "dev.architectury.loom" version "1.10-SNAPSHOT" apply false
|
id "dev.architectury.loom" version "1.13-SNAPSHOT" apply false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets up Forgix for multiversion merging
|
|
||||||
forgix {
|
|
||||||
if (project.hasProperty('mergeVersions')) { // This is set using -PmergeVersions by the GitLab CI
|
|
||||||
multiversion {
|
|
||||||
inputJars = project.files(project.property('mergeVersions').toString().split(';'))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the list of preprocessors to use.
|
* Creates the list of preprocessors to use.
|
||||||
@@ -50,8 +45,10 @@ def writeBuildGradlePredefine(List<String> mcVers, int mcIndex)
|
|||||||
String verStr = mcVers[i].replace(".", "_");
|
String verStr = mcVers[i].replace(".", "_");
|
||||||
sb.append("MC_" + verStr + "=" + i.toString() + "\n");
|
sb.append("MC_" + verStr + "=" + i.toString() + "\n");
|
||||||
|
|
||||||
if (mcIndex == i)
|
if (mcIndex == i)
|
||||||
|
{
|
||||||
sb.append("MC_VER=" + i.toString() + "\n");
|
sb.append("MC_VER=" + i.toString() + "\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -79,12 +76,23 @@ writeBuildGradlePredefine(rootProject.mcVers, rootProject.mcIndex)
|
|||||||
rootProject.versionStr = rootProject.mod_version + "-" + rootProject.minecraft_version // + "-" + new Date().format("yyyy_MM_dd_HH_mm")
|
rootProject.versionStr = rootProject.mod_version + "-" + rootProject.minecraft_version // + "-" + new Date().format("yyyy_MM_dd_HH_mm")
|
||||||
|
|
||||||
class NativeTransformer implements Transformer {
|
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, String> replacements = new HashMap()
|
||||||
private final HashMap<String, byte[]> rewrittenFiles = new HashMap()
|
private final HashMap<String, byte[]> rewrittenFiles = new HashMap()
|
||||||
private var nativeRelocator
|
private var nativeRelocator
|
||||||
|
|
||||||
public File rootDir
|
public File rootDir
|
||||||
|
|
||||||
|
void matchFiles(Predicate<String> matcher) {
|
||||||
|
fileMatcher = matcher
|
||||||
|
}
|
||||||
|
|
||||||
|
void mapPaths(Function<String, String> mapper) {
|
||||||
|
filePathMapper = mapper
|
||||||
|
}
|
||||||
|
|
||||||
void relocateNative(String target, String replacement) {
|
void relocateNative(String target, String replacement) {
|
||||||
if (replacement.length() > target.length()) {
|
if (replacement.length() > target.length()) {
|
||||||
throw new GradleException("Length of value \"${replacement}\" exceeds the length of \"${target}\": ${replacement.length()} > ${target.length()}")
|
throw new GradleException("Length of value \"${replacement}\" exceeds the length of \"${target}\": ${replacement.length()} > ${target.length()}")
|
||||||
@@ -95,9 +103,7 @@ class NativeTransformer implements Transformer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
boolean canTransformResource(@Nonnull FileTreeElement element) {
|
boolean canTransformResource(@Nonnull FileTreeElement element) {
|
||||||
return replacements.keySet().stream().anyMatch {
|
return fileMatcher.test(element.name)
|
||||||
element.name.startsWith(it as String)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -109,11 +115,9 @@ class NativeTransformer implements Transformer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Map.Entry<String, String> pathReplacement = replacements.entrySet().stream().filter {
|
String path = filePathMapper != null
|
||||||
context.path.startsWith(it.key as String)
|
? filePathMapper.apply(context.path)
|
||||||
}.findFirst().orElseThrow()
|
: context.path
|
||||||
|
|
||||||
String path = context.path.replace(pathReplacement.key as String, pathReplacement.value as String)
|
|
||||||
content = nativeRelocator.processBinary(path, content, replacements)
|
content = nativeRelocator.processBinary(path, content, replacements)
|
||||||
|
|
||||||
rewrittenFiles.put(path, content)
|
rewrittenFiles.put(path, content)
|
||||||
@@ -200,15 +204,6 @@ subprojects { p ->
|
|||||||
developmentForge.extendsFrom coreProjects
|
developmentForge.extendsFrom coreProjects
|
||||||
if (findProject(":neoforge"))
|
if (findProject(":neoforge"))
|
||||||
developmentNeoForge.extendsFrom coreProjects
|
developmentNeoForge.extendsFrom coreProjects
|
||||||
|
|
||||||
// TODO remove unused fabricLike
|
|
||||||
if (findProject(":fabricLike") && p != project(":fabricLike")) {
|
|
||||||
// Shadow fabricLike
|
|
||||||
fabricLike
|
|
||||||
shadowFabricLike
|
|
||||||
compileClasspath.extendsFrom fabricLike
|
|
||||||
runtimeClasspath.extendsFrom fabricLike
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,7 +248,8 @@ subprojects { p ->
|
|||||||
// Note: MC 1.16 uses 8.2.1, and versions after use 8.5.12
|
// 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
|
// We cannot relocate this library since we call some MC classes that reference it
|
||||||
implementation("it.unimi.dsi:fastutil:${rootProject.fastutil_version}")
|
implementation("it.unimi.dsi:fastutil:${rootProject.fastutil_version}")
|
||||||
|
|
||||||
|
forgeShadowMe("com.github.luben:zstd-jni:${rootProject.zstd_version}")
|
||||||
|
|
||||||
// Compression
|
// Compression
|
||||||
forgeShadowMe("org.lz4:lz4-java:${rootProject.lz4_version}") // LZ4
|
forgeShadowMe("org.lz4:lz4-java:${rootProject.lz4_version}") // LZ4
|
||||||
@@ -272,11 +268,6 @@ subprojects { p ->
|
|||||||
// Netty
|
// Netty
|
||||||
implementation("io.netty:netty-buffer:${rootProject.netty_version}")
|
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
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//==========================//
|
//==========================//
|
||||||
@@ -313,12 +304,6 @@ subprojects { p ->
|
|||||||
// Common
|
// Common
|
||||||
common(project(":common")) { transitive false }
|
common(project(":common")) { transitive false }
|
||||||
shadowCommon(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 }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -328,18 +313,9 @@ subprojects { p ->
|
|||||||
if (isMinecraftSubProject && p != project(":common")) {
|
if (isMinecraftSubProject && p != project(":common")) {
|
||||||
configurations.push(project.configurations.shadowCommon) // Shadow the common subproject
|
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
|
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"
|
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)
|
// Compression (LZ4)
|
||||||
relocate "net.jpountz", "${librariesLocation}.jpountz"
|
relocate "net.jpountz", "${librariesLocation}.jpountz"
|
||||||
|
|
||||||
@@ -356,9 +332,30 @@ subprojects { p ->
|
|||||||
|
|
||||||
transform(NativeTransformer) {
|
transform(NativeTransformer) {
|
||||||
rootDir = project.rootDir
|
rootDir = project.rootDir
|
||||||
|
|
||||||
|
matchFiles { it.startsWith("org/sqlite") }
|
||||||
|
mapPaths { it.replace("org/sqlite", "dh_sqlite") }
|
||||||
|
|
||||||
relocateNative "org/sqlite", "dh_sqlite"
|
relocateNative "org/sqlite", "dh_sqlite"
|
||||||
relocateNative "org_sqlite", "dh_1sqlite"
|
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
|
// JOML
|
||||||
@@ -368,9 +365,6 @@ subprojects { p ->
|
|||||||
// NightConfig (includes Toml & Json)
|
// NightConfig (includes Toml & Json)
|
||||||
relocate "com.electronwill.nightconfig", "${librariesLocation}.electronwill.nightconfig"
|
relocate "com.electronwill.nightconfig", "${librariesLocation}.electronwill.nightconfig"
|
||||||
|
|
||||||
// SVG (not needed atm)
|
|
||||||
// relocate "com.kitfox.svg", "${librariesLocation}.kitfox.svg"
|
|
||||||
|
|
||||||
// Netty
|
// Netty
|
||||||
// Don't relocate, it causes problems with using MC's FriendlyByteBufs
|
// Don't relocate, it causes problems with using MC's FriendlyByteBufs
|
||||||
// relocate "io.netty", "${librariesLocation}.netty"
|
// relocate "io.netty", "${librariesLocation}.netty"
|
||||||
@@ -382,10 +376,10 @@ subprojects { p ->
|
|||||||
|
|
||||||
|
|
||||||
// Put stuff from gradle.properties into the mod info
|
// Put stuff from gradle.properties into the mod info
|
||||||
|
// Note: these resources are only included in the mod jars, the core and API jars don't include these files
|
||||||
processResources {
|
processResources {
|
||||||
def resourceTargets = [ // Location of where to inject the properties
|
def resourceTargets = [ // Location of where to inject the properties
|
||||||
// Holds info like git commit
|
// Holds info like git commit
|
||||||
// TODO: For some reason this script doesnt work with the core project
|
|
||||||
"build_info.json",
|
"build_info.json",
|
||||||
|
|
||||||
// Properties for each of the loaders
|
// Properties for each of the loaders
|
||||||
@@ -395,7 +389,7 @@ subprojects { p ->
|
|||||||
"META-INF/neoforge.mods.toml",
|
"META-INF/neoforge.mods.toml",
|
||||||
|
|
||||||
// The mixins for each of the loaders
|
// The mixins for each of the loaders
|
||||||
"DistantHorizons."+ p.name +".fabricLike.mixins.json"
|
//"DistantHorizons."+ p.name +".fabricLike.mixins.json"
|
||||||
]
|
]
|
||||||
def intoTargets = ["$buildDir/resources/main/"] // Location of the built resources folder
|
def intoTargets = ["$buildDir/resources/main/"] // Location of the built resources folder
|
||||||
|
|
||||||
@@ -415,9 +409,6 @@ subprojects { p ->
|
|||||||
quilt_contributors.reverse()
|
quilt_contributors.reverse()
|
||||||
//println quilt_contributors.join(", ")
|
//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)
|
// These "hasProperty"'s are so that they can be passed through the cli (ie in the CI)
|
||||||
try {
|
try {
|
||||||
@@ -453,6 +444,8 @@ subprojects { p ->
|
|||||||
|
|
||||||
fabric_incompatibility_list : fabric_incompatibility_list,
|
fabric_incompatibility_list : fabric_incompatibility_list,
|
||||||
fabric_recommend_list : fabric_recommend_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
|
// replace any properties in the sub-projects with the values defined here
|
||||||
@@ -477,13 +470,8 @@ subprojects { p ->
|
|||||||
|
|
||||||
|
|
||||||
// ==================== Delete un-needed files ====================
|
// ==================== 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
|
// 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
|
// (neo)forge (well, mainly architectury) requires the original accesswidener file, meaning we require this jank solution to keep it
|
||||||
exclude { file ->
|
exclude { file ->
|
||||||
if (file.name.contains(".distanthorizons.accesswidener") && file.name != "${accessWidenerVersion}.distanthorizons.accesswidener") {
|
if (file.name.contains(".distanthorizons.accesswidener") && file.name != "${accessWidenerVersion}.distanthorizons.accesswidener") {
|
||||||
return true
|
return true
|
||||||
@@ -626,33 +614,36 @@ allprojects { p ->
|
|||||||
includeGroup "forge-mod"
|
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
|
// Adds some dependencies that are in vanilla but not in core
|
||||||
if (p == project(":core")) {
|
if (p == project(":core")) {
|
||||||
OperatingSystem os = org.gradle.nativeplatform.platform.internal.DefaultNativePlatform.currentOperatingSystem;
|
OperatingSystem os = org.gradle.nativeplatform.platform.internal.DefaultNativePlatform.currentOperatingSystem;
|
||||||
|
|
||||||
// Set the OS lwjgl is using to the current os
|
// Set the OS lwjgl is using to the current os
|
||||||
project.ext.lwjglNatives = "natives-" + os.toFamilyName()
|
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
|
dependencies {
|
||||||
// Imports most of lwjgl's libraries (well, only the ones that we need)
|
// All of these dependencies are in Vanilla Minecraft, but we need to depend on them as we arent importing Minecraft in the core
|
||||||
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
|
|
||||||
|
// Imports most of lwjgl's libraries
|
||||||
|
implementation platform("org.lwjgl:lwjgl-bom:${rootProject.lwjgl_version}")
|
||||||
|
|
||||||
// REMEMBER: Dont shadow stuff here, these are just the libs that are included in Minecraft so that the core can use
|
// REMEMBER: Don't shadow stuff here, these are just the libs that are included in Minecraft so that the core can use them
|
||||||
implementation "org.lwjgl:lwjgl"
|
implementation "org.lwjgl:lwjgl"
|
||||||
implementation "org.lwjgl:lwjgl-assimp"
|
implementation "org.lwjgl:lwjgl-assimp"
|
||||||
implementation "org.lwjgl:lwjgl-glfw"
|
implementation "org.lwjgl:lwjgl-glfw"
|
||||||
implementation "org.lwjgl:lwjgl-openal"
|
// OpenGL is removed since DH now handles rendering in the "Common" project
|
||||||
implementation "org.lwjgl:lwjgl-opengl"
|
// so we can use OpenGL for old MC versions and Blaze3D (IE Vulkan) for newer ones
|
||||||
|
// implementation "org.lwjgl:lwjgl-openal"
|
||||||
|
// implementation "org.lwjgl:lwjgl-opengl"
|
||||||
implementation "org.lwjgl:lwjgl-stb"
|
implementation "org.lwjgl:lwjgl-stb"
|
||||||
implementation "org.lwjgl:lwjgl-tinyfd"
|
implementation "org.lwjgl:lwjgl-tinyfd"
|
||||||
runtimeOnly "org.lwjgl:lwjgl::$lwjglNatives"
|
runtimeOnly "org.lwjgl:lwjgl::$lwjglNatives"
|
||||||
runtimeOnly "org.lwjgl:lwjgl-assimp::$lwjglNatives"
|
runtimeOnly "org.lwjgl:lwjgl-assimp::$lwjglNatives"
|
||||||
runtimeOnly "org.lwjgl:lwjgl-glfw::$lwjglNatives"
|
runtimeOnly "org.lwjgl:lwjgl-glfw::$lwjglNatives"
|
||||||
runtimeOnly "org.lwjgl:lwjgl-openal::$lwjglNatives"
|
// runtimeOnly "org.lwjgl:lwjgl-openal::$lwjglNatives"
|
||||||
runtimeOnly "org.lwjgl:lwjgl-opengl::$lwjglNatives"
|
// runtimeOnly "org.lwjgl:lwjgl-opengl::$lwjglNatives"
|
||||||
runtimeOnly "org.lwjgl:lwjgl-stb::$lwjglNatives"
|
runtimeOnly "org.lwjgl:lwjgl-stb::$lwjglNatives"
|
||||||
runtimeOnly "org.lwjgl:lwjgl-tinyfd::$lwjglNatives"
|
runtimeOnly "org.lwjgl:lwjgl-tinyfd::$lwjglNatives"
|
||||||
implementation "org.joml:joml:${rootProject.joml_version}"
|
implementation "org.joml:joml:${rootProject.joml_version}"
|
||||||
@@ -671,14 +662,6 @@ allprojects { p ->
|
|||||||
from project(":common").file("src/main/resources/${accessWidenerVersion}.distanthorizons.accesswidener")
|
from project(":common").file("src/main/resources/${accessWidenerVersion}.distanthorizons.accesswidener")
|
||||||
into(file(p.file("build/resources/main")))
|
into(file(p.file("build/resources/main")))
|
||||||
rename "${accessWidenerVersion}.distanthorizons.accesswidener", "distanthorizons.accesswidener"
|
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) {
|
task copyCoreResources(type: Copy) {
|
||||||
@@ -691,7 +674,6 @@ allprojects { p ->
|
|||||||
options.release = rootProject.java_version as Integer
|
options.release = rootProject.java_version as Integer
|
||||||
} else {
|
} else {
|
||||||
options.release = 8; // Core & Api should use Java 8 no matter what
|
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"
|
options.encoding = "UTF-8"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ for d in versionProperties/*; do
|
|||||||
echo "==================== Merging $version ===================="
|
echo "==================== Merging $version ===================="
|
||||||
sh gradlew mergeJars -PmcVer=$version
|
sh gradlew mergeJars -PmcVer=$version
|
||||||
if [ $? != 0 ]; then continue; fi
|
if [ $? != 0 ]; then continue; fi
|
||||||
|
|
||||||
echo "==================== Moving jar ===================="
|
echo "==================== Moving jar ===================="
|
||||||
mv Merged/*.jar buildAllJars/
|
mv build/merged/*.jar buildAllJars/
|
||||||
done
|
done
|
||||||
|
|||||||
+6
-3
@@ -15,12 +15,15 @@ for %%f in (versionProperties\*) do (
|
|||||||
@rem Clean out the folders, build it, and merge it
|
@rem Clean out the folders, build it, and merge it
|
||||||
echo ==================== Cleaning workspace to build !version! ====================
|
echo ==================== Cleaning workspace to build !version! ====================
|
||||||
call .\gradlew.bat clean
|
call .\gradlew.bat clean
|
||||||
echo ==================== Building !version! ====================
|
|
||||||
|
echo ==================== Building !version! ====================
|
||||||
call .\gradlew.bat build -PmcVer="!version!"
|
call .\gradlew.bat build -PmcVer="!version!"
|
||||||
echo ==================== Merging !version! ====================
|
|
||||||
|
echo ==================== Merging !version! ====================
|
||||||
call .\gradlew.bat mergeJars -PmcVer="!version!"
|
call .\gradlew.bat mergeJars -PmcVer="!version!"
|
||||||
|
|
||||||
echo ==================== Moving jar ====================
|
echo ==================== Moving jar ====================
|
||||||
move Merged\*.jar buildAllJars\
|
move build\merged\*.jar buildAllJars\
|
||||||
)
|
)
|
||||||
|
|
||||||
endlocal
|
endlocal
|
||||||
|
|||||||
@@ -34,7 +34,10 @@ class NativeRelocator
|
|||||||
{
|
{
|
||||||
processBuilder.command("powershell", "-ExecutionPolicy", "Bypass", "./prepare.ps1");
|
processBuilder.command("powershell", "-ExecutionPolicy", "Bypass", "./prepare.ps1");
|
||||||
}
|
}
|
||||||
else if (os.contains("nix") || os.contains("nux") || os.contains("mac"))
|
else if (os.contains("nix")
|
||||||
|
|| os.contains("nux")
|
||||||
|
|| os.contains("mac")
|
||||||
|
|| os.contains("freebsd"))
|
||||||
{
|
{
|
||||||
processBuilder.command("./prepare.sh");
|
processBuilder.command("./prepare.sh");
|
||||||
}
|
}
|
||||||
|
|||||||
+108
-27
@@ -1,21 +1,28 @@
|
|||||||
package com.seibel.distanthorizons.common;
|
package com.seibel.distanthorizons.common;
|
||||||
|
|
||||||
import com.mojang.brigadier.CommandDispatcher;
|
import com.mojang.brigadier.CommandDispatcher;
|
||||||
|
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderApi;
|
||||||
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.minecraft.MinecraftServerWrapper;
|
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftServerWrapper;
|
||||||
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.api.internal.SharedApi;
|
||||||
import com.seibel.distanthorizons.core.config.Config;
|
import com.seibel.distanthorizons.core.config.Config;
|
||||||
import com.seibel.distanthorizons.core.config.ConfigBase;
|
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;
|
||||||
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
|
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
|
||||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
|
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.util.NativeDialogUtil;
|
||||||
|
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;
|
||||||
@@ -23,9 +30,8 @@ import com.seibel.distanthorizons.coreapi.ModInfo;
|
|||||||
import net.minecraft.commands.CommandSourceStack;
|
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 org.apache.logging.log4j.Logger;
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
|
||||||
import java.lang.invoke.MethodHandles;
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
@@ -35,7 +41,7 @@ import java.util.function.Supplier;
|
|||||||
*/
|
*/
|
||||||
public abstract class AbstractModInitializer
|
public abstract class AbstractModInitializer
|
||||||
{
|
{
|
||||||
protected static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName());
|
protected static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
|
|
||||||
private CommandInitializer commandInitializer;
|
private CommandInitializer commandInitializer;
|
||||||
|
|
||||||
@@ -44,8 +50,10 @@ public abstract class AbstractModInitializer
|
|||||||
//==================//
|
//==================//
|
||||||
// abstract methods //
|
// abstract methods //
|
||||||
//==================//
|
//==================//
|
||||||
|
//region
|
||||||
|
|
||||||
protected abstract void createInitialBindings();
|
protected abstract void createInitialSharedBindings();
|
||||||
|
protected abstract void createInitialClientBindings();
|
||||||
protected abstract IEventProxy createClientProxy();
|
protected abstract IEventProxy createClientProxy();
|
||||||
protected abstract IEventProxy createServerProxy(boolean isDedicated);
|
protected abstract IEventProxy createServerProxy(boolean isDedicated);
|
||||||
protected abstract void initializeModCompat();
|
protected abstract void initializeModCompat();
|
||||||
@@ -56,17 +64,21 @@ public abstract class AbstractModInitializer
|
|||||||
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()
|
||||||
{
|
{
|
||||||
DependencySetup.createClientBindings();
|
DependencySetup.createClientBindings();
|
||||||
|
this.createInitialClientBindings();
|
||||||
|
|
||||||
LOGGER.info("Initializing " + ModInfo.READABLE_NAME + " client.");
|
LOGGER.info("Initializing " + ModInfo.READABLE_NAME + " client, firing DhApiBeforeDhInitEvent...");
|
||||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeDhInitEvent.class, null);
|
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeDhInitEvent.class, null);
|
||||||
|
|
||||||
this.startup();
|
this.startup();
|
||||||
@@ -77,21 +89,27 @@ public abstract class AbstractModInitializer
|
|||||||
|
|
||||||
this.initializeModCompat();
|
this.initializeModCompat();
|
||||||
|
|
||||||
LOGGER.info(ModInfo.READABLE_NAME + " client Initialized.");
|
|
||||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiAfterDhInitEvent.class, null);
|
|
||||||
|
|
||||||
// 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
|
logModIncompatibilityWarnings(); // needs to be called after config loading
|
||||||
|
|
||||||
|
LOGGER.info(ModInfo.READABLE_NAME + " client Initialized.");
|
||||||
|
|
||||||
|
#if MC_VER < MC_1_21_9
|
||||||
|
// debug screen rendering handled via a mixin
|
||||||
|
#else
|
||||||
|
DhDebugScreenEntry.register();
|
||||||
|
#endif
|
||||||
|
|
||||||
this.subscribeClientStartedEvent(this::postInit);
|
this.subscribeClientStartedEvent(this::postInit);
|
||||||
|
this.subscribeClientStartedEvent(this::postClientInit);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onInitializeServer()
|
public void onInitializeServer()
|
||||||
{
|
{
|
||||||
DependencySetup.createServerBindings();
|
DependencySetup.createServerBindings();
|
||||||
|
|
||||||
LOGGER.info("Initializing " + ModInfo.READABLE_NAME + " server.");
|
LOGGER.info("Initializing " + ModInfo.READABLE_NAME + " server, firing DhApiBeforeDhInitEvent event...");
|
||||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeDhInitEvent.class, null);
|
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeDhInitEvent.class, null);
|
||||||
|
|
||||||
this.startup();
|
this.startup();
|
||||||
@@ -106,10 +124,9 @@ public abstract class AbstractModInitializer
|
|||||||
|
|
||||||
this.initializeModCompat();
|
this.initializeModCompat();
|
||||||
|
|
||||||
LOGGER.info(ModInfo.READABLE_NAME + " server Initialized.");
|
LOGGER.info(ModInfo.READABLE_NAME + " server Initialized, adding event subscribers...");
|
||||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiAfterDhInitEvent.class, null);
|
this.commandInitializer = new CommandInitializer();
|
||||||
|
this.subscribeRegisterCommandsEvent(dispatcher -> { this.commandInitializer.initCommands(dispatcher); });
|
||||||
this.subscribeRegisterCommandsEvent(dispatcher -> { this.commandInitializer = new CommandInitializer(dispatcher); });
|
|
||||||
|
|
||||||
this.subscribeServerStartingEvent(server ->
|
this.subscribeServerStartingEvent(server ->
|
||||||
{
|
{
|
||||||
@@ -117,25 +134,28 @@ public abstract class AbstractModInitializer
|
|||||||
|
|
||||||
this.initConfig();
|
this.initConfig();
|
||||||
this.postInit();
|
this.postInit();
|
||||||
this.commandInitializer.initCommands();
|
this.commandInitializer.onServerReady();
|
||||||
|
|
||||||
this.checkForUpdates();
|
this.checkForUpdates();
|
||||||
|
|
||||||
LOGGER.info("Dedicated server initialized at " + server.getServerDirectory());
|
LOGGER.info(ModInfo.READABLE_NAME + " server Initialized at " + server.getServerDirectory());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//===========================//
|
//===========================//
|
||||||
// inner initializer methods //
|
// inner initializer methods //
|
||||||
//===========================//
|
//===========================//
|
||||||
|
//region
|
||||||
|
|
||||||
private void startup()
|
private void startup()
|
||||||
{
|
{
|
||||||
DependencySetup.createSharedBindings();
|
DependencySetup.createSharedBindings();
|
||||||
SharedApi.init();
|
SharedApi.init();
|
||||||
this.createInitialBindings();
|
this.createInitialSharedBindings();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void logBuildInfo()
|
private void logBuildInfo()
|
||||||
@@ -159,12 +179,17 @@ public abstract class AbstractModInitializer
|
|||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
ModAccessorInjector.INSTANCE.bind((Class<? extends IModAccessor>) accessorClass, accessorConstructor.get());
|
ModAccessorInjector.INSTANCE.bind((Class<? extends IModAccessor>) accessorClass, accessorConstructor.get());
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOGGER.debug("Skipping mod compatibility accessor for: ["+modId+"]");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initConfig()
|
private void initConfig()
|
||||||
{
|
{
|
||||||
ConfigBase.INSTANCE = new ConfigBase(ModInfo.ID, ModInfo.NAME, Config.class, ModInfo.CONFIG_FILE_VERSION);
|
ConfigHandler.tryRunFirstTimeSetup();
|
||||||
Config.completeDelayedSetup();
|
Config.completeDelayedSetup();
|
||||||
|
DhLogger.runDelayedConfigSetup();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkForUpdates()
|
private void checkForUpdates()
|
||||||
@@ -183,16 +208,30 @@ public abstract class AbstractModInitializer
|
|||||||
|
|
||||||
private void postInit()
|
private void postInit()
|
||||||
{
|
{
|
||||||
LOGGER.info("Post-Initializing Mod");
|
LOGGER.info("Running Delayed setup...");
|
||||||
this.runDelayedSetup();
|
this.runDelayedSetup();
|
||||||
LOGGER.info("Mod Post-Initialized");
|
|
||||||
|
if (ConfigHandler.INSTANCE == null)
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("Config was not initialized. Make sure to call LodCommonMain.initConfig() before calling this method.");
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGGER.info("Delayed setup complete, firing DhApiAfterDhInitEvent event...");
|
||||||
|
|
||||||
|
// should be fired after all delayed setup so singletons and config can be accessed
|
||||||
|
ApiEventInjector.INSTANCE.fireAllEvents(DhApiAfterDhInitEvent.class, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void postClientInit() { DependencySetup.setRenderingApiBindings(); }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//==================================//
|
//==================================//
|
||||||
// mod partial compatibility checks //
|
// mod partial compatibility checks //
|
||||||
//==================================//
|
//==================================//
|
||||||
|
//region
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Some mods will work with a few tweaks
|
* Some mods will work with a few tweaks
|
||||||
@@ -210,6 +249,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
|
||||||
@@ -219,16 +259,17 @@ public abstract class AbstractModInitializer
|
|||||||
if (showChatWarnings)
|
if (showChatWarnings)
|
||||||
{
|
{
|
||||||
String message =
|
String message =
|
||||||
// orange text
|
MinecraftTextFormat.ORANGE + "Distant Horizons: Alex's Cave detected." + MinecraftTextFormat.CLEAR_FORMATTING +
|
||||||
"\u00A76" + "Distant Horizons: Alex's Cave detected." + "\u00A7r\n" +
|
|
||||||
"You may have to change Alex's config for DH to render. ";
|
"You may have to change Alex's config for DH to render. ";
|
||||||
ClientApi.INSTANCE.showChatMessageNextFrame(message);
|
ClientApi.INSTANCE.showChatMessageNextFrame(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
@@ -242,16 +283,18 @@ public abstract class AbstractModInitializer
|
|||||||
if (showChatWarnings)
|
if (showChatWarnings)
|
||||||
{
|
{
|
||||||
String message =
|
String message =
|
||||||
// orange text
|
MinecraftTextFormat.ORANGE + "Distant Horizons: WWOO detected." + MinecraftTextFormat.CLEAR_FORMATTING + "\n" +
|
||||||
"\u00A76" + "Distant Horizons: WWOO detected." + "\u00A7r\n" +
|
|
||||||
wwooWarning;
|
wwooWarning;
|
||||||
ClientApi.INSTANCE.showChatMessageNextFrame(message);
|
ClientApi.INSTANCE.showChatMessageNextFrame(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGGER.warn(startingString + "[WWOO] "+ wwooWarning);
|
LOGGER.warn(startingString + "[WWOO] "+ wwooWarning);
|
||||||
}
|
}
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
// Chunky //
|
||||||
|
//region
|
||||||
|
|
||||||
// Chunky
|
|
||||||
boolean chunkyPresent = false;
|
boolean chunkyPresent = false;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -273,8 +316,7 @@ public abstract class AbstractModInitializer
|
|||||||
if (showChatWarnings)
|
if (showChatWarnings)
|
||||||
{
|
{
|
||||||
String message =
|
String message =
|
||||||
// orange text
|
MinecraftTextFormat.ORANGE + "Distant Horizons: Chunky detected." + MinecraftTextFormat.CLEAR_FORMATTING + "\n" +
|
||||||
"\u00A76" + "Distant Horizons: Chunky detected." + "\u00A7r\n" +
|
|
||||||
chunkyWarning;
|
chunkyWarning;
|
||||||
ClientApi.INSTANCE.showChatMessageNextFrame(message);
|
ClientApi.INSTANCE.showChatMessageNextFrame(message);
|
||||||
}
|
}
|
||||||
@@ -282,17 +324,56 @@ 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
|
||||||
|
EDhApiRenderApi renderApi = Config.Client.Advanced.Graphics.Experimental.renderingApi.get();
|
||||||
|
if (renderApi == EDhApiRenderApi.AUTO)
|
||||||
|
{
|
||||||
|
IVersionConstants versionConstants = SingletonInjector.INSTANCE.get(IVersionConstants.class);
|
||||||
|
renderApi = versionConstants.getDefaultRenderingApi();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iris only supports nataive OpenGL
|
||||||
|
if (renderApi != EDhApiRenderApi.OPEN_GL)
|
||||||
|
{
|
||||||
|
String irisUnsupportedMessage = "Iris doesn't support DH when using the ["+EDhApiRenderApi.BLAZE_3D+"] rendering API, please change it to ["+EDhApiRenderApi.OPEN_GL+"] in DH's 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
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//================//
|
//================//
|
||||||
// helper classes //
|
// helper classes //
|
||||||
//================//
|
//================//
|
||||||
|
//region
|
||||||
|
|
||||||
public interface IEventProxy
|
public interface IEventProxy
|
||||||
{
|
{
|
||||||
void registerEvents();
|
void registerEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-8
@@ -1,8 +1,8 @@
|
|||||||
package com.seibel.distanthorizons.common;
|
package com.seibel.distanthorizons.common;
|
||||||
|
|
||||||
import com.seibel.distanthorizons.core.config.Config;
|
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.ConfigBasedLogger;
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
import com.seibel.distanthorizons.core.network.event.internal.IncompatibleMessageInternalEvent;
|
import com.seibel.distanthorizons.core.network.event.internal.IncompatibleMessageInternalEvent;
|
||||||
import com.seibel.distanthorizons.core.network.event.internal.ProtocolErrorInternalEvent;
|
import com.seibel.distanthorizons.core.network.event.internal.ProtocolErrorInternalEvent;
|
||||||
import com.seibel.distanthorizons.core.network.messages.MessageRegistry;
|
import com.seibel.distanthorizons.core.network.messages.MessageRegistry;
|
||||||
@@ -13,22 +13,29 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapp
|
|||||||
import com.seibel.distanthorizons.coreapi.ModInfo;
|
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||||
import io.netty.buffer.ByteBufUtil;
|
import io.netty.buffer.ByteBufUtil;
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import org.apache.logging.log4j.LogManager;
|
|
||||||
|
#if MC_VER <= MC_1_21_10
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
#else
|
||||||
|
import net.minecraft.resources.Identifier;
|
||||||
|
#endif
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
public abstract class AbstractPluginPacketSender implements IPluginPacketSender
|
public abstract class AbstractPluginPacketSender implements IPluginPacketSender
|
||||||
{
|
{
|
||||||
private static final ConfigBasedLogger LOGGER = new ConfigBasedLogger(LogManager.getLogger(),
|
private static final DhLogger LOGGER = new DhLoggerBuilder()
|
||||||
() -> Config.Common.Logging.logNetworkEvent.get());
|
.fileLevelConfig(Config.Common.Logging.logNetworkEventToFile)
|
||||||
|
.build();
|
||||||
|
|
||||||
#if MC_VER >= MC_1_21_1
|
#if MC_VER <= MC_1_20_6
|
||||||
|
public static final ResourceLocation WRAPPER_PACKET_RESOURCE = new ResourceLocation(ModInfo.RESOURCE_NAMESPACE, ModInfo.WRAPPER_PACKET_PATH);
|
||||||
|
#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);
|
||||||
#else
|
#else
|
||||||
public static final ResourceLocation WRAPPER_PACKET_RESOURCE = new ResourceLocation(ModInfo.RESOURCE_NAMESPACE, ModInfo.WRAPPER_PACKET_PATH);
|
public static final Identifier WRAPPER_PACKET_RESOURCE = Identifier.fromNamespaceAndPath(ModInfo.RESOURCE_NAMESPACE, ModInfo.WRAPPER_PACKET_PATH);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// "Forge byte" is an unused packet ID. We have our own system which works with all mod loaders,
|
// "Forge byte" is an unused packet ID. We have our own system which works with all mod loaders,
|
||||||
|
|||||||
+49
-14
@@ -3,36 +3,71 @@ package com.seibel.distanthorizons.common.commands;
|
|||||||
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 org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
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;
|
import static net.minecraft.commands.Commands.literal;
|
||||||
|
|
||||||
/**
|
#if MC_VER <= MC_1_21_10
|
||||||
* Initializes commands of the mod.
|
#else
|
||||||
*/
|
import net.minecraft.server.permissions.PermissionCheck;
|
||||||
|
import net.minecraft.server.permissions.Permissions;
|
||||||
|
#endif
|
||||||
|
|
||||||
public class CommandInitializer
|
public class CommandInitializer
|
||||||
{
|
{
|
||||||
private final CommandDispatcher<CommandSourceStack> commandDispatcher;
|
private boolean serverReady = false;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_21_10
|
||||||
|
private static final int REQUIRED_PERMISSION_LEVEL = 4;
|
||||||
|
#else
|
||||||
|
private static final PermissionCheck COMMAND_PERMISSION_CHECK = new PermissionCheck.Require(Permissions.COMMANDS_OWNER);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new instance of this class.
|
* A received command dispatcher, which is held until the server is ready to initialize the commands.
|
||||||
*
|
|
||||||
* @param commandDispatcher The dispatcher to use for registering commands.
|
|
||||||
*/
|
*/
|
||||||
public CommandInitializer(CommandDispatcher<CommandSourceStack> commandDispatcher)
|
@Nullable
|
||||||
|
private CommandDispatcher<CommandSourceStack> commandDispatcher;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notify the command initializer that the game is ready to accept commands.
|
||||||
|
* If {@link CommandInitializer#initCommands(CommandDispatcher)} has been fired before it was ready, it will also initialize the commands.
|
||||||
|
*/
|
||||||
|
public void onServerReady()
|
||||||
{
|
{
|
||||||
this.commandDispatcher = commandDispatcher;
|
this.serverReady = true;
|
||||||
|
if (this.commandDispatcher != null)
|
||||||
|
{
|
||||||
|
this.initCommands(this.commandDispatcher);
|
||||||
|
this.commandDispatcher = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes all available commands.
|
* Initializes all available commands.
|
||||||
|
* If the game is not ready yet, it stores the dispatcher to initialize the commands later.
|
||||||
|
*
|
||||||
|
* @param commandDispatcher The command dispatcher to register commands to.
|
||||||
*/
|
*/
|
||||||
public void initCommands()
|
public void initCommands(CommandDispatcher<CommandSourceStack> commandDispatcher)
|
||||||
{
|
{
|
||||||
|
if (!this.serverReady)
|
||||||
|
{
|
||||||
|
this.commandDispatcher = commandDispatcher;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
LiteralArgumentBuilder<CommandSourceStack> builder = literal("dh")
|
LiteralArgumentBuilder<CommandSourceStack> builder = literal("dh")
|
||||||
.requires(source -> source.hasPermission(4));
|
.requires((source) ->
|
||||||
|
{
|
||||||
|
#if MC_VER <= MC_1_21_10
|
||||||
|
return source.hasPermission(REQUIRED_PERMISSION_LEVEL);
|
||||||
|
#else
|
||||||
|
return COMMAND_PERMISSION_CHECK.check(source.permissions());
|
||||||
|
#endif
|
||||||
|
});
|
||||||
|
|
||||||
builder.then(new ConfigCommand().buildCommand());
|
builder.then(new ConfigCommand().buildCommand());
|
||||||
builder.then(new DebugCommand().buildCommand());
|
builder.then(new DebugCommand().buildCommand());
|
||||||
@@ -43,7 +78,7 @@ public class CommandInitializer
|
|||||||
builder.then(new CrashCommand().buildCommand());
|
builder.then(new CrashCommand().buildCommand());
|
||||||
}
|
}
|
||||||
|
|
||||||
this.commandDispatcher.register(builder);
|
commandDispatcher.register(builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package com.seibel.distanthorizons.common.commands;
|
|||||||
import com.mojang.brigadier.arguments.*;
|
import com.mojang.brigadier.arguments.*;
|
||||||
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.core.config.ConfigBase;
|
import com.seibel.distanthorizons.core.config.ConfigHandler;
|
||||||
import com.seibel.distanthorizons.core.config.types.AbstractConfigType;
|
import com.seibel.distanthorizons.core.config.types.AbstractConfigBase;
|
||||||
import com.seibel.distanthorizons.core.config.types.ConfigEntry;
|
import com.seibel.distanthorizons.core.config.types.ConfigEntry;
|
||||||
import net.minecraft.commands.CommandSourceStack;
|
import net.minecraft.commands.CommandSourceStack;
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ public class ConfigCommand extends AbstractCommand
|
|||||||
LiteralArgumentBuilder<CommandSourceStack> builder = literal("config");
|
LiteralArgumentBuilder<CommandSourceStack> builder = literal("config");
|
||||||
HashSet<String> addedCommands = new HashSet<>();
|
HashSet<String> addedCommands = new HashSet<>();
|
||||||
|
|
||||||
for (AbstractConfigType<?, ?> type : ConfigBase.INSTANCE.entries)
|
for (AbstractConfigBase<?> type : ConfigHandler.INSTANCE.configBaseList)
|
||||||
{
|
{
|
||||||
// Skip non-config entries
|
// Skip non-config entries
|
||||||
if (!(type instanceof ConfigEntry))
|
if (!(type instanceof ConfigEntry))
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ public class CrashCommand extends AbstractCommand
|
|||||||
.requires(this::isPlayerSource)
|
.requires(this::isPlayerSource)
|
||||||
.then(literal("encode")
|
.then(literal("encode")
|
||||||
.executes(c -> {
|
.executes(c -> {
|
||||||
assert SharedApi.getIDhServerWorld() != null;
|
assert SharedApi.tryGetDhServerWorld() != null;
|
||||||
|
|
||||||
ServerPlayerState serverPlayerState = SharedApi.getIDhServerWorld().getServerPlayerStateManager()
|
ServerPlayerState serverPlayerState = SharedApi.tryGetDhServerWorld().getServerPlayerStateManager()
|
||||||
.getConnectedPlayer(this.getSourcePlayer(c));
|
.getConnectedPlayer(this.getSourcePlayer(c));
|
||||||
if (serverPlayerState != null)
|
if (serverPlayerState != null)
|
||||||
{
|
{
|
||||||
@@ -29,9 +29,9 @@ public class CrashCommand extends AbstractCommand
|
|||||||
}))
|
}))
|
||||||
.then(literal("decode")
|
.then(literal("decode")
|
||||||
.executes(c -> {
|
.executes(c -> {
|
||||||
assert SharedApi.getIDhServerWorld() != null;
|
assert SharedApi.tryGetDhServerWorld() != null;
|
||||||
|
|
||||||
ServerPlayerState serverPlayerState = SharedApi.getIDhServerWorld().getServerPlayerStateManager()
|
ServerPlayerState serverPlayerState = SharedApi.tryGetDhServerWorld().getServerPlayerStateManager()
|
||||||
.getConnectedPlayer(this.getSourcePlayer(c));
|
.getConnectedPlayer(this.getSourcePlayer(c));
|
||||||
if (serverPlayerState != null)
|
if (serverPlayerState != null)
|
||||||
{
|
{
|
||||||
|
|||||||
+88
@@ -0,0 +1,88 @@
|
|||||||
|
package com.seibel.distanthorizons.common.commonMixins;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.api.enums.config.EDhApiUpdateBranch;
|
||||||
|
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.wrapperInterfaces.IVersionConstants;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.gui.screens.TitleScreen;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class DhUpdateScreenBase
|
||||||
|
{
|
||||||
|
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
|
|
||||||
|
private static final Minecraft MC = Minecraft.getInstance();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
MC.setScreen(new UpdateModScreen(
|
||||||
|
new TitleScreen(false),
|
||||||
|
versionId
|
||||||
|
));
|
||||||
|
}
|
||||||
|
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.info("Unable to show DH update screen, reason: ["+e.getMessage()+"].");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
runnable.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+6
-7
@@ -4,6 +4,7 @@ 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.wrapperInterfaces.world.IServerLevelWrapper;
|
||||||
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 org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
@@ -13,8 +14,10 @@ public class MixinChunkMapCommon
|
|||||||
|
|
||||||
public static void onChunkSave(ServerLevel level, ChunkAccess chunk, CallbackInfoReturnable<Boolean> ci)
|
public static void onChunkSave(ServerLevel level, ChunkAccess chunk, CallbackInfoReturnable<Boolean> ci)
|
||||||
{
|
{
|
||||||
|
IServerLevelWrapper levelWrapper = ServerLevelWrapper.getWrapper(level);
|
||||||
|
|
||||||
// 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, chunk.getPos().x, chunk.getPos().z))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -29,10 +32,6 @@ public class MixinChunkMapCommon
|
|||||||
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 //
|
||||||
@@ -77,8 +76,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
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+330
@@ -0,0 +1,330 @@
|
|||||||
|
/*
|
||||||
|
* 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.buffers.Std140Builder;
|
||||||
|
import com.mojang.blaze3d.buffers.Std140SizeCalculator;
|
||||||
|
import com.mojang.blaze3d.pipeline.RenderPipeline;
|
||||||
|
import com.mojang.blaze3d.platform.DepthTestFunction;
|
||||||
|
import com.mojang.blaze3d.platform.PolygonMode;
|
||||||
|
import com.mojang.blaze3d.shaders.UniformType;
|
||||||
|
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.util.BlazeUniformUtil;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.util.BlazeDhVertexFormatUtil;
|
||||||
|
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.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 net.minecraft.resources.Identifier;
|
||||||
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
import java.util.OptionalDouble;
|
||||||
|
import java.util.OptionalInt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
|
||||||
|
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
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// rendering setup
|
||||||
|
private boolean init = false;
|
||||||
|
|
||||||
|
private RenderPipeline pipeline;
|
||||||
|
|
||||||
|
private GpuBuffer boxVertexBuffer;
|
||||||
|
private GpuBuffer boxIndexBuffer;
|
||||||
|
|
||||||
|
private GpuBuffer uniformBuffer;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public BlazeDebugWireframeRenderer() { }
|
||||||
|
|
||||||
|
public void init()
|
||||||
|
{
|
||||||
|
if (this.init)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.init = true;
|
||||||
|
|
||||||
|
this.createPipelines();
|
||||||
|
this.createBuffers();
|
||||||
|
|
||||||
|
}
|
||||||
|
private void createPipelines()
|
||||||
|
{
|
||||||
|
VertexFormat vertexFormat = VertexFormat.builder()
|
||||||
|
.add("vPosition", BlazeDhVertexFormatUtil.FLOAT_XYZ_POS)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
RenderPipeline.Builder pipelineBuilder = RenderPipeline.builder();
|
||||||
|
{
|
||||||
|
pipelineBuilder.withCull(false);
|
||||||
|
pipelineBuilder.withDepthWrite(false);
|
||||||
|
pipelineBuilder.withDepthTestFunction(DepthTestFunction.LESS_DEPTH_TEST);
|
||||||
|
pipelineBuilder.withColorWrite(true);
|
||||||
|
pipelineBuilder.withoutBlend();
|
||||||
|
pipelineBuilder.withPolygonMode(PolygonMode.WIREFRAME);
|
||||||
|
pipelineBuilder.withLocation(Identifier.parse("distanthorizons:debug_wireframe_renderer"));
|
||||||
|
|
||||||
|
pipelineBuilder.withVertexShader(Identifier.fromNamespaceAndPath("distanthorizons", "debug/blaze/vert"));
|
||||||
|
pipelineBuilder.withFragmentShader(Identifier.fromNamespaceAndPath("distanthorizons", "debug/blaze/frag"));
|
||||||
|
|
||||||
|
pipelineBuilder.withUniform("uniformBlock", UniformType.UNIFORM_BUFFER);
|
||||||
|
|
||||||
|
pipelineBuilder.withVertexFormat(vertexFormat, VertexFormat.Mode.DEBUG_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:McDebugWireframeBox", 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 render(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
|
||||||
|
{
|
||||||
|
int uniformBufferSize = new Std140SizeCalculator()
|
||||||
|
.putMat4f() // uTransform
|
||||||
|
.putVec4() // uColor
|
||||||
|
.get();
|
||||||
|
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
|
||||||
|
Mat4f transformMatrix = this.dhMvmProjMatrixThisFrame.copy();
|
||||||
|
transformMatrix.multiply(boxTransform);
|
||||||
|
|
||||||
|
|
||||||
|
// upload data //
|
||||||
|
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocateDirect(uniformBufferSize);
|
||||||
|
buffer.order(ByteOrder.nativeOrder());
|
||||||
|
buffer = Std140Builder.intoBuffer(buffer)
|
||||||
|
.putMat4f(transformMatrix.createJomlMatrix()) // uTransform
|
||||||
|
.putVec4(
|
||||||
|
box.color.getRed() / 255.0f,
|
||||||
|
box.color.getGreen() / 255.0f,
|
||||||
|
box.color.getBlue() / 255.0f,
|
||||||
|
box.color.getAlpha() / 255.0f) // uColor
|
||||||
|
.get()
|
||||||
|
;
|
||||||
|
|
||||||
|
this.uniformBuffer = BlazeUniformUtil.createBuffer("uniformBlock", uniformBufferSize, this.uniformBuffer);
|
||||||
|
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.uniformBuffer, 0, uniformBufferSize);
|
||||||
|
|
||||||
|
commandEncoder.writeToBuffer(bufferSlice, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// render //
|
||||||
|
|
||||||
|
try (RenderPass renderPass = commandEncoder.createRenderPass(
|
||||||
|
this::getRenderPassName,
|
||||||
|
BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.textureView,
|
||||||
|
/*optionalClearColorAsInt*/ OptionalInt.empty(),
|
||||||
|
BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureView,
|
||||||
|
/*optionalDepthValueAsDouble*/ OptionalDouble.empty()))
|
||||||
|
{
|
||||||
|
// Bind instance data //
|
||||||
|
renderPass.setUniform("uniformBlock", this.uniformBuffer);
|
||||||
|
|
||||||
|
renderPass.setPipeline(this.pipeline);
|
||||||
|
renderPass.setIndexBuffer(this.boxIndexBuffer, VertexFormat.IndexType.INT);
|
||||||
|
|
||||||
|
renderPass.setVertexBuffer(0, this.boxVertexBuffer);
|
||||||
|
|
||||||
|
renderPass.drawIndexed(
|
||||||
|
/*indexStart*/ 0,
|
||||||
|
/*firstIndex*/0,
|
||||||
|
/*indexCount*/BOX_OUTLINE_INDICES.length,
|
||||||
|
/*instanceCount*/1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private String getRenderPassName() { return "distantHorizons:McDebugRenderer"; }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+630
@@ -0,0 +1,630 @@
|
|||||||
|
/*
|
||||||
|
* 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.buffers.GpuBuffer;
|
||||||
|
import com.mojang.blaze3d.buffers.GpuBufferSlice;
|
||||||
|
import com.mojang.blaze3d.buffers.Std140Builder;
|
||||||
|
import com.mojang.blaze3d.buffers.Std140SizeCalculator;
|
||||||
|
import com.mojang.blaze3d.pipeline.BlendFunction;
|
||||||
|
import com.mojang.blaze3d.pipeline.RenderPipeline;
|
||||||
|
import com.mojang.blaze3d.platform.DepthTestFunction;
|
||||||
|
import com.mojang.blaze3d.platform.PolygonMode;
|
||||||
|
import com.mojang.blaze3d.shaders.UniformType;
|
||||||
|
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.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.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.texture.BlazeTextureViewWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.util.BlazeUniformUtil;
|
||||||
|
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.RenderParams;
|
||||||
|
import com.seibel.distanthorizons.core.render.renderer.GenericRenderObjectFactory;
|
||||||
|
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 net.minecraft.resources.Identifier;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.OptionalDouble;
|
||||||
|
import java.util.OptionalInt;
|
||||||
|
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 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 final ConcurrentHashMap<Long, RenderableBoxGroup> boxGroupById = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
|
||||||
|
// rendering setup
|
||||||
|
private boolean init = false;
|
||||||
|
|
||||||
|
private VertexFormat vertexFormat;
|
||||||
|
|
||||||
|
private RenderPipeline opaquePipeline;
|
||||||
|
private RenderPipeline transparentPipeline;
|
||||||
|
|
||||||
|
private GpuBuffer vertUniformBuffer;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public BlazeDhGenericObjectRenderer() { }
|
||||||
|
|
||||||
|
public void init()
|
||||||
|
{
|
||||||
|
if (this.init)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.init = true;
|
||||||
|
|
||||||
|
this.vertexFormat = VertexFormat.builder()
|
||||||
|
.add("vPosition", BlazeDhVertexFormatUtil.FLOAT_XYZ_POS)
|
||||||
|
.add("aColor", BlazeDhVertexFormatUtil.RGBA_UBYTE_COLOR)
|
||||||
|
.add("aMaterial", BlazeDhVertexFormatUtil.IRIS_MATERIAL)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
this.createPipelines();
|
||||||
|
|
||||||
|
if (RENDER_DEBUG_OBJECTS)
|
||||||
|
{
|
||||||
|
this.addGenericDebugObjects();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void createPipelines()
|
||||||
|
{
|
||||||
|
RenderPipeline.Builder pipelineBuilder = RenderPipeline.builder();
|
||||||
|
{
|
||||||
|
pipelineBuilder.withCull(true);
|
||||||
|
pipelineBuilder.withDepthWrite(true);
|
||||||
|
pipelineBuilder.withDepthTestFunction(DepthTestFunction.LESS_DEPTH_TEST);
|
||||||
|
pipelineBuilder.withColorWrite(true);
|
||||||
|
pipelineBuilder.withPolygonMode(PolygonMode.FILL);
|
||||||
|
pipelineBuilder.withLocation(Identifier.parse("distanthorizons:generic"));
|
||||||
|
|
||||||
|
pipelineBuilder.withVertexShader(Identifier.fromNamespaceAndPath("distanthorizons", "generic/blaze/vert"));
|
||||||
|
pipelineBuilder.withFragmentShader(Identifier.fromNamespaceAndPath("distanthorizons", "generic/blaze/frag"));
|
||||||
|
|
||||||
|
pipelineBuilder.withSampler("uLightMap");
|
||||||
|
|
||||||
|
pipelineBuilder.withUniform("vertUniformBlock", UniformType.UNIFORM_BUFFER);
|
||||||
|
|
||||||
|
pipelineBuilder.withVertexFormat(this.vertexFormat, VertexFormat.Mode.TRIANGLES);
|
||||||
|
}
|
||||||
|
|
||||||
|
// opaque
|
||||||
|
{
|
||||||
|
pipelineBuilder.withoutBlend();
|
||||||
|
this.opaquePipeline = pipelineBuilder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
// transparent
|
||||||
|
{
|
||||||
|
pipelineBuilder.withBlend(BlendFunction.TRANSLUCENT);
|
||||||
|
this.transparentPipeline = 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;
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
//==============//
|
||||||
|
// render setup //
|
||||||
|
//==============//
|
||||||
|
//#region
|
||||||
|
|
||||||
|
profiler.push("setup");
|
||||||
|
|
||||||
|
this.init();
|
||||||
|
|
||||||
|
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericRenderSetupEvent.class, renderEventParam);
|
||||||
|
|
||||||
|
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
|
||||||
|
boolean cancelRendering = ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericObjectRenderEvent.class, new DhApiBeforeGenericObjectRenderEvent.EventParam(renderEventParam, boxGroup));
|
||||||
|
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
|
||||||
|
{
|
||||||
|
int uniformBufferSize = new Std140SizeCalculator()
|
||||||
|
.putIVec3() // uOffsetChunk
|
||||||
|
.putVec3() // uOffsetSubChunk
|
||||||
|
.putIVec3() // uCameraPosChunk
|
||||||
|
.putVec3() // uCameraPosSubChunk
|
||||||
|
|
||||||
|
.putVec3() // aTranslateChunk
|
||||||
|
.putVec3() // aTranslateSubChunk
|
||||||
|
|
||||||
|
.putMat4f() // uProjectionMvm
|
||||||
|
.putInt() // uSkyLight
|
||||||
|
.putInt() // uBlockLight
|
||||||
|
|
||||||
|
.putFloat() // uNorthShading
|
||||||
|
.putFloat() // uSouthShading
|
||||||
|
.putFloat() // uEastShading
|
||||||
|
.putFloat() // uWestShading
|
||||||
|
.putFloat() // uTopShading
|
||||||
|
.putFloat() // uBottomShading
|
||||||
|
.get();
|
||||||
|
|
||||||
|
|
||||||
|
// create data //
|
||||||
|
|
||||||
|
Mat4f projectionMvmMatrix = new Mat4f(renderEventParam.dhProjectionMatrix);
|
||||||
|
projectionMvmMatrix.multiply(renderEventParam.dhModelViewMatrix);
|
||||||
|
|
||||||
|
|
||||||
|
// upload data //
|
||||||
|
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocateDirect(uniformBufferSize);
|
||||||
|
buffer.order(ByteOrder.nativeOrder());
|
||||||
|
buffer = Std140Builder.intoBuffer(buffer)
|
||||||
|
.putIVec3(
|
||||||
|
LodUtil.getChunkPosFromDouble(boxGroup.getOriginBlockPos().x),
|
||||||
|
LodUtil.getChunkPosFromDouble(boxGroup.getOriginBlockPos().y),
|
||||||
|
LodUtil.getChunkPosFromDouble(boxGroup.getOriginBlockPos().z)
|
||||||
|
) // uOffsetChunk
|
||||||
|
.putVec3(
|
||||||
|
LodUtil.getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().x),
|
||||||
|
LodUtil.getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().y),
|
||||||
|
LodUtil.getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().z)
|
||||||
|
) // uOffsetSubChunk
|
||||||
|
.putIVec3(
|
||||||
|
LodUtil.getChunkPosFromDouble(camPos.x),
|
||||||
|
LodUtil.getChunkPosFromDouble(camPos.y),
|
||||||
|
LodUtil.getChunkPosFromDouble(camPos.z)
|
||||||
|
) // uCameraPosChunk
|
||||||
|
.putVec3(
|
||||||
|
LodUtil.getSubChunkPosFromDouble(camPos.x),
|
||||||
|
LodUtil.getSubChunkPosFromDouble(camPos.y),
|
||||||
|
LodUtil.getSubChunkPosFromDouble(camPos.z)
|
||||||
|
) // uCameraPosSubChunk
|
||||||
|
|
||||||
|
.putMat4f(projectionMvmMatrix.createJomlMatrix()) // 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)
|
||||||
|
|
||||||
|
.get()
|
||||||
|
;
|
||||||
|
|
||||||
|
this.vertUniformBuffer = BlazeUniformUtil.createBuffer("vertUniformBlock", uniformBufferSize, this.vertUniformBuffer);
|
||||||
|
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.vertUniformBuffer, 0, uniformBufferSize);
|
||||||
|
|
||||||
|
COMMAND_ENCODER.writeToBuffer(bufferSlice, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// render //
|
||||||
|
|
||||||
|
profiler.popPush("rendering");
|
||||||
|
profiler.push(boxGroup.getResourceLocationNamespace());
|
||||||
|
profiler.push(boxGroup.getResourceLocationPath());
|
||||||
|
|
||||||
|
try (RenderPass renderPass = COMMAND_ENCODER.createRenderPass(
|
||||||
|
this::getRenderPassName,
|
||||||
|
BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.textureView,
|
||||||
|
/*optionalClearColorAsInt*/ OptionalInt.empty(),
|
||||||
|
BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureView,
|
||||||
|
/*optionalDepthValueAsDouble*/ OptionalDouble.empty()))
|
||||||
|
{
|
||||||
|
this.renderBoxGroupInstanced(renderPass, renderEventParam, boxGroup, camPos, profiler);
|
||||||
|
}
|
||||||
|
|
||||||
|
profiler.pop(); // resource path
|
||||||
|
profiler.pop(); // resource namespace
|
||||||
|
|
||||||
|
boxGroup.postRender(renderEventParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//==========//
|
||||||
|
// clean up //
|
||||||
|
//==========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
profiler.popPush("cleanup");
|
||||||
|
|
||||||
|
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericRenderCleanupEvent.class, renderEventParam);
|
||||||
|
|
||||||
|
profiler.pop();
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
}
|
||||||
|
private String getRenderPassName() { return "distantHorizons:McGenericObjectRenderer"; }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=====================//
|
||||||
|
// instanced rendering //
|
||||||
|
//=====================//
|
||||||
|
//region
|
||||||
|
|
||||||
|
private void renderBoxGroupInstanced(
|
||||||
|
RenderPass renderPass, RenderParams renderEventParam,
|
||||||
|
RenderableBoxGroup boxGroup, Vec3d camPos,
|
||||||
|
IProfilerWrapper profiler)
|
||||||
|
{
|
||||||
|
// update instance data //
|
||||||
|
|
||||||
|
profiler.push("vertex setup");
|
||||||
|
|
||||||
|
BlazeGenericObjectVertexContainer container = (BlazeGenericObjectVertexContainer) boxGroup.vertexBufferContainer;
|
||||||
|
|
||||||
|
LightMapWrapper lightMapWrapper = (LightMapWrapper) renderEventParam.lightmap;
|
||||||
|
BlazeTextureViewWrapper lightmapTextureViewWrapper = lightMapWrapper.getTextureViewWrapper();
|
||||||
|
renderPass.bindTexture("uLightMap", lightmapTextureViewWrapper.textureView, lightmapTextureViewWrapper.textureSampler);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Bind instance data //
|
||||||
|
profiler.popPush("binding");
|
||||||
|
|
||||||
|
|
||||||
|
renderPass.setUniform("vertUniformBlock", this.vertUniformBuffer);
|
||||||
|
|
||||||
|
// set pipeline
|
||||||
|
renderPass.setPipeline(this.opaquePipeline); // TODO
|
||||||
|
renderPass.setIndexBuffer(container.indexGpuBuffer, VertexFormat.IndexType.INT);
|
||||||
|
|
||||||
|
renderPass.setVertexBuffer(0, container.vboGpuBuffer);
|
||||||
|
|
||||||
|
// Draw instanced
|
||||||
|
profiler.popPush("render");
|
||||||
|
if (container.uploadedBoxCount > 0)
|
||||||
|
{
|
||||||
|
renderPass.drawIndexed(
|
||||||
|
/*indexStart*/ 0,
|
||||||
|
/*firstIndex*/0,
|
||||||
|
/*indexCount*/container.uploadedBoxCount * 24, // TODO?
|
||||||
|
/*instanceCount*/1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
profiler.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
//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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+94
@@ -0,0 +1,94 @@
|
|||||||
|
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.common.render.blaze.apply.BlazeDhApplyRenderer;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.render.RenderParams;
|
||||||
|
import com.seibel.distanthorizons.core.util.ColorUtil;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhMetaRenderer;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
|
||||||
|
public class BlazeDhMetaRenderer implements IDhMetaRenderer
|
||||||
|
{
|
||||||
|
public static final BlazeDhMetaRenderer INSTANCE = new BlazeDhMetaRenderer();
|
||||||
|
|
||||||
|
|
||||||
|
private BlazeDhApplyRenderer applyRenderer;
|
||||||
|
|
||||||
|
public final BlazeTextureWrapper dhDepthTextureWrapper = BlazeTextureWrapper.createDepth("DhDepthTexture");
|
||||||
|
public final BlazeTextureWrapper dhColorTextureWrapper = BlazeTextureWrapper.createColor("DhColorTexture");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
private BlazeDhMetaRenderer()
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
// textures
|
||||||
|
this.dhDepthTextureWrapper.tryCreateOrResize();
|
||||||
|
this.dhColorTextureWrapper.tryCreateOrResize();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void runRenderPassCleanup(RenderParams renderParams) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void applyToMcTexture(RenderParams renderParams)
|
||||||
|
{
|
||||||
|
GpuTexture mcColorTexture = Minecraft.getInstance().getMainRenderTarget().getColorTexture();
|
||||||
|
this.applyRenderer.render(this.dhColorTextureWrapper.texture, this.dhDepthTextureWrapper.texture, mcColorTexture);
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// clear textures //
|
||||||
|
//================//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearDhDepthAndColorTextures(RenderParams renderParams)
|
||||||
|
{
|
||||||
|
// TODO use for clear color
|
||||||
|
//IMinecraftRenderWrapper r;
|
||||||
|
//r.getSkyColor()
|
||||||
|
|
||||||
|
this.dhDepthTextureWrapper.clearDepth(1.0f);
|
||||||
|
this.dhColorTextureWrapper.clearColor(ColorUtil.argbToInt(1, 1, 1, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+71
@@ -0,0 +1,71 @@
|
|||||||
|
package com.seibel.distanthorizons.common.render.blaze;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_21_10
|
||||||
|
public class BlazeDhRenderApiDefinition {}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
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.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 BlazeDhRenderApiDefinition extends AbstractDhRenderApiDefinition
|
||||||
|
{
|
||||||
|
//=========//
|
||||||
|
// getters //
|
||||||
|
//=========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public String getApiName() { return "Blaze3D"; }
|
||||||
|
|
||||||
|
//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
|
||||||
+394
@@ -0,0 +1,394 @@
|
|||||||
|
package com.seibel.distanthorizons.common.render.blaze;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_21_10
|
||||||
|
public class BlazeDhTerrainRenderer {}
|
||||||
|
|
||||||
|
#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.pipeline.BlendFunction;
|
||||||
|
import com.mojang.blaze3d.pipeline.RenderPipeline;
|
||||||
|
import com.mojang.blaze3d.platform.DepthTestFunction;
|
||||||
|
import com.mojang.blaze3d.platform.PolygonMode;
|
||||||
|
import com.mojang.blaze3d.shaders.UniformType;
|
||||||
|
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.api.methods.events.abstractEvents.DhApiBeforeBufferRenderEvent;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.util.BlazeDhVertexFormatUtil;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.util.BlazeUniformUtil;
|
||||||
|
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.wrappers.misc.LightMapWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.config.Config;
|
||||||
|
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodBufferContainer;
|
||||||
|
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodQuadBuilder;
|
||||||
|
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.common.render.openGl.glObject.enums.GLEnums;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.buffer.GlQuadElementBuffer;
|
||||||
|
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.renderPass.IDhTerrainRenderer;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IVertexBufferWrapper;
|
||||||
|
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
|
||||||
|
import net.minecraft.resources.Identifier;
|
||||||
|
import org.lwjgl.opengl.GL32;
|
||||||
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
import java.util.OptionalDouble;
|
||||||
|
import java.util.OptionalInt;
|
||||||
|
|
||||||
|
/** Renders rendering DH's LOD terrain. */
|
||||||
|
public class BlazeDhTerrainRenderer implements IDhTerrainRenderer
|
||||||
|
{
|
||||||
|
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 BlazeDhTerrainRenderer INSTANCE = new BlazeDhTerrainRenderer();
|
||||||
|
|
||||||
|
|
||||||
|
private RenderPipeline opaquePipeline;
|
||||||
|
private RenderPipeline transparentPipeline;
|
||||||
|
private boolean init = false;
|
||||||
|
|
||||||
|
private GpuBuffer indexBuffer;
|
||||||
|
|
||||||
|
private GpuBuffer fragUniformBuffer;
|
||||||
|
private GpuBuffer vertSharedUniformBuffer;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
private BlazeDhTerrainRenderer() { }
|
||||||
|
|
||||||
|
private void tryInit()
|
||||||
|
{
|
||||||
|
if (this.init)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.init = true; // todo only set when succeeded (in case of exception)
|
||||||
|
|
||||||
|
|
||||||
|
VertexFormat vertexFormat = VertexFormat.builder()
|
||||||
|
.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();
|
||||||
|
|
||||||
|
RenderPipeline.Builder pipelineBuilder = RenderPipeline.builder();
|
||||||
|
{
|
||||||
|
pipelineBuilder.withCull(true);
|
||||||
|
pipelineBuilder.withDepthWrite(true);
|
||||||
|
pipelineBuilder.withDepthTestFunction(DepthTestFunction.LESS_DEPTH_TEST);
|
||||||
|
pipelineBuilder.withColorWrite(true);
|
||||||
|
pipelineBuilder.withPolygonMode(PolygonMode.FILL);
|
||||||
|
pipelineBuilder.withLocation(Identifier.parse("distanthorizons:lod_render"));
|
||||||
|
|
||||||
|
pipelineBuilder.withVertexShader(Identifier.fromNamespaceAndPath("distanthorizons", "lod/blaze/vert"));
|
||||||
|
pipelineBuilder.withFragmentShader(Identifier.fromNamespaceAndPath("distanthorizons", "lod/blaze/frag"));
|
||||||
|
|
||||||
|
pipelineBuilder.withSampler("uLightMap");
|
||||||
|
|
||||||
|
pipelineBuilder.withUniform("vertUniqueUniformBlock", UniformType.UNIFORM_BUFFER);
|
||||||
|
pipelineBuilder.withUniform("vertSharedUniformBlock", UniformType.UNIFORM_BUFFER);
|
||||||
|
pipelineBuilder.withUniform("fragUniformBlock", UniformType.UNIFORM_BUFFER);
|
||||||
|
|
||||||
|
pipelineBuilder.withVertexFormat(vertexFormat, VertexFormat.Mode.TRIANGLES);
|
||||||
|
}
|
||||||
|
|
||||||
|
// opaque
|
||||||
|
{
|
||||||
|
pipelineBuilder.withoutBlend();
|
||||||
|
this.opaquePipeline = pipelineBuilder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
// transparent
|
||||||
|
{
|
||||||
|
pipelineBuilder.withBlend(BlendFunction.TRANSLUCENT);
|
||||||
|
this.transparentPipeline = pipelineBuilder.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//========//
|
||||||
|
// render //
|
||||||
|
//========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(
|
||||||
|
RenderParams renderEventParam,
|
||||||
|
boolean opaquePass,
|
||||||
|
SortedArraySet<LodBufferContainer> bufferContainers,
|
||||||
|
IProfilerWrapper profiler)
|
||||||
|
{
|
||||||
|
this.tryInit();
|
||||||
|
|
||||||
|
|
||||||
|
profiler.push("vert unique uniforms");
|
||||||
|
{
|
||||||
|
// create data //
|
||||||
|
|
||||||
|
for (int lodIndex = 0; lodIndex < bufferContainers.size(); lodIndex++)
|
||||||
|
{
|
||||||
|
LodBufferContainer bufferContainer = bufferContainers.get(lodIndex);
|
||||||
|
bufferContainer.uniformContainer.tryUpload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 uniformBufferSize = new Std140SizeCalculator()
|
||||||
|
.putInt() // uIsWhiteWorld
|
||||||
|
|
||||||
|
.putFloat() // uWorldYOffset
|
||||||
|
.putFloat() // uMircoOffset
|
||||||
|
.putFloat() // uEarthRadius
|
||||||
|
|
||||||
|
.putVec3() // uCameraPos
|
||||||
|
.putMat4f() // uCombinedMatrix
|
||||||
|
.get();
|
||||||
|
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocateDirect(uniformBufferSize);
|
||||||
|
buffer.order(ByteOrder.nativeOrder());
|
||||||
|
Std140Builder.intoBuffer(buffer)
|
||||||
|
.putInt(0) // uIsWhiteWorld
|
||||||
|
|
||||||
|
.putFloat((float) renderEventParam.worldYOffset) // uWorldYOffset
|
||||||
|
.putFloat(0.01f) // uMircoOffset // 0.01 block offset
|
||||||
|
.putFloat(earthCurveRatio) // uEarthRadius
|
||||||
|
|
||||||
|
.putVec3(
|
||||||
|
(float)renderEventParam.exactCameraPosition.x,
|
||||||
|
(float)renderEventParam.exactCameraPosition.y,
|
||||||
|
(float)renderEventParam.exactCameraPosition.z) // uCameraPos
|
||||||
|
.putMat4f(combinedMatrix.createJomlMatrix()) // uCombinedMatrix
|
||||||
|
.get();
|
||||||
|
|
||||||
|
this.vertSharedUniformBuffer = BlazeUniformUtil.createBuffer("vertSharedUniformBlock", uniformBufferSize, this.vertSharedUniformBuffer);
|
||||||
|
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.vertSharedUniformBuffer, 0, uniformBufferSize);
|
||||||
|
|
||||||
|
COMMAND_ENCODER.writeToBuffer(bufferSlice, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
profiler.popPush("set frag uniforms");
|
||||||
|
{
|
||||||
|
int uniformBufferSize = new Std140SizeCalculator()
|
||||||
|
.putFloat() // uClipDistance
|
||||||
|
.putFloat() // uNoiseIntensity
|
||||||
|
.putInt() // uNoiseSteps
|
||||||
|
.putInt() // uNoiseDropoff
|
||||||
|
.putInt() // uDitherDhRendering
|
||||||
|
.putInt() // uNoiseEnabled
|
||||||
|
.get();
|
||||||
|
|
||||||
|
|
||||||
|
// 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 //
|
||||||
|
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocateDirect(uniformBufferSize);
|
||||||
|
buffer.order(ByteOrder.nativeOrder());
|
||||||
|
buffer = Std140Builder.intoBuffer(buffer)
|
||||||
|
.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
|
||||||
|
.get()
|
||||||
|
;
|
||||||
|
|
||||||
|
this.fragUniformBuffer = BlazeUniformUtil.createBuffer("fragUniformBlock", uniformBufferSize, this.fragUniformBuffer);
|
||||||
|
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.fragUniformBuffer, 0, uniformBufferSize);
|
||||||
|
|
||||||
|
COMMAND_ENCODER.writeToBuffer(bufferSlice, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// create index buffer
|
||||||
|
{
|
||||||
|
if (this.indexBuffer == null)
|
||||||
|
{
|
||||||
|
ByteBuffer buffer = MemoryUtil.memAlloc(LodQuadBuilder.getMaxBufferByteSize() * GLEnums.getTypeSize(GL32.GL_UNSIGNED_INT) * 6);
|
||||||
|
GlQuadElementBuffer.buildBuffer(LodQuadBuilder.getMaxBufferByteSize(), buffer, GL32.GL_UNSIGNED_INT);
|
||||||
|
|
||||||
|
|
||||||
|
// create buffer if needed
|
||||||
|
if (this.indexBuffer == null
|
||||||
|
|| this.indexBuffer.size() < buffer.capacity())
|
||||||
|
{
|
||||||
|
int usage = GpuBuffer.USAGE_COPY_DST
|
||||||
|
| GpuBuffer.USAGE_VERTEX
|
||||||
|
| GpuBuffer.USAGE_INDEX
|
||||||
|
| GpuBuffer.USAGE_UNIFORM;
|
||||||
|
this.indexBuffer = GPU_DEVICE.createBuffer(this::getIndexBufferName, usage, buffer.capacity());
|
||||||
|
}
|
||||||
|
|
||||||
|
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.indexBuffer, /*offset*/ 0, buffer.capacity());
|
||||||
|
COMMAND_ENCODER.writeToBuffer(bufferSlice, buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// render pass setup
|
||||||
|
{
|
||||||
|
profiler.popPush("setup");
|
||||||
|
|
||||||
|
// create a render pass
|
||||||
|
OptionalInt optionalClearColorAsInt = OptionalInt.empty();
|
||||||
|
OptionalDouble optionalDepthValueAsDouble = OptionalDouble.empty();
|
||||||
|
|
||||||
|
try(RenderPass renderPass = COMMAND_ENCODER.createRenderPass(
|
||||||
|
this::getRenderPassName,
|
||||||
|
BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.textureView,
|
||||||
|
optionalClearColorAsInt,
|
||||||
|
BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureView, optionalDepthValueAsDouble)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// bind MC Lightmap
|
||||||
|
//renderPass.bindTexture("uLightMap", this.mcLightTextureViewWrapper.textureView, this.mcLightTextureViewWrapper.textureSampler);
|
||||||
|
LightMapWrapper lightMapWrapper = (LightMapWrapper) renderEventParam.lightmap;
|
||||||
|
BlazeTextureViewWrapper lightmapTextureViewWrapper = lightMapWrapper.getTextureViewWrapper();
|
||||||
|
renderPass.bindTexture("uLightMap", lightmapTextureViewWrapper.textureView, lightmapTextureViewWrapper.textureSampler);
|
||||||
|
|
||||||
|
// set pipeline
|
||||||
|
renderPass.setPipeline(opaquePass ? this.opaquePipeline : this.transparentPipeline);
|
||||||
|
renderPass.setIndexBuffer(this.indexBuffer, VertexFormat.IndexType.INT);
|
||||||
|
|
||||||
|
// shared uniforms
|
||||||
|
renderPass.setUniform("fragUniformBlock", this.fragUniformBuffer);
|
||||||
|
renderPass.setUniform("vertSharedUniformBlock", this.vertSharedUniformBuffer);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
for (int lodIndex = 0; lodIndex < bufferContainers.size(); lodIndex++)
|
||||||
|
{
|
||||||
|
profiler.popPush("binding");
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderPass.setUniform("vertUniqueUniformBlock", uniformWrapper.gpuBuffer);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
profiler.popPush("rendering");
|
||||||
|
|
||||||
|
// render each buffer
|
||||||
|
IVertexBufferWrapper[] bufferWrapperList = opaquePass ? bufferContainer.vbos : bufferContainer.vbosTransparent;
|
||||||
|
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;
|
||||||
|
Vec3f modelPos = new Vec3f(
|
||||||
|
(float) (bufferContainer.minCornerBlockPos.getX() - camPos.x),
|
||||||
|
(float) (bufferContainer.minCornerBlockPos.getY() - camPos.y),
|
||||||
|
(float) (bufferContainer.minCornerBlockPos.getZ() - camPos.z));
|
||||||
|
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeBufferRenderEvent.class, new DhApiBeforeBufferRenderEvent.EventParam(renderEventParam, modelPos));
|
||||||
|
}
|
||||||
|
|
||||||
|
renderPass.setVertexBuffer(0, bufferWrapper.vboGpuBuffer); // vertex buffer can only be "0" lol
|
||||||
|
|
||||||
|
if (!bufferWrapper.vboGpuBuffer.isClosed())
|
||||||
|
{
|
||||||
|
renderPass.drawIndexed(
|
||||||
|
/*indexStart*/ 0,
|
||||||
|
/*firstIndex*/0,
|
||||||
|
/*indexCount*/bufferWrapper.indexCount,
|
||||||
|
/*instanceCount*/1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
profiler.pop();
|
||||||
|
}
|
||||||
|
private String getIndexBufferName() { return "distantHorizons:LodIndexBuffer"; }
|
||||||
|
private String getRenderPassName() { return "distantHorizons:McLodRenderer"; }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+268
@@ -0,0 +1,268 @@
|
|||||||
|
/*
|
||||||
|
* 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.platform.DepthTestFunction;
|
||||||
|
import com.mojang.blaze3d.platform.PolygonMode;
|
||||||
|
import com.mojang.blaze3d.shaders.UniformType;
|
||||||
|
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.texture.BlazeTextureViewWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.util.BlazePostProcessUtil;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||||
|
import net.minecraft.resources.Identifier;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.OptionalDouble;
|
||||||
|
import java.util.OptionalInt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 GpuDevice GPU_DEVICE = RenderSystem.getDevice();
|
||||||
|
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
|
||||||
|
|
||||||
|
private RenderPipeline pipeline;
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 GpuBuffer[] uniformBuffers;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// 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.uniformBuffers = new GpuBuffer[this.uniformNames.length];
|
||||||
|
}
|
||||||
|
|
||||||
|
private void tryInit(
|
||||||
|
GpuTexture sourceColorTexture,
|
||||||
|
GpuTexture sourceDepthTexture,
|
||||||
|
GpuTexture destinationColorTexture)
|
||||||
|
{
|
||||||
|
this.createPipeline();
|
||||||
|
this.vboGpuBuffer = BlazePostProcessUtil.createAndUploadScreenVertexData(this.name);
|
||||||
|
|
||||||
|
this.sourceColorTextureViewWrapper.tryWrap(sourceColorTexture);
|
||||||
|
this.sourceDepthTextureViewWrapper.tryWrap(sourceDepthTexture);
|
||||||
|
|
||||||
|
this.destinationColorTextureViewWrapper.tryWrap(destinationColorTexture);
|
||||||
|
|
||||||
|
}
|
||||||
|
private void createPipeline()
|
||||||
|
{
|
||||||
|
if (this.pipeline != null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
VertexFormat vertexFormat = VertexFormat.builder()
|
||||||
|
.add("vPosition", BlazeDhVertexFormatUtil.SCREEN_POS)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
RenderPipeline.Builder pipelineBuilder = RenderPipeline.builder();
|
||||||
|
{
|
||||||
|
pipelineBuilder.withCull(false);
|
||||||
|
pipelineBuilder.withDepthWrite(false);
|
||||||
|
pipelineBuilder.withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST);
|
||||||
|
pipelineBuilder.withColorWrite(true);
|
||||||
|
|
||||||
|
if (this.blendFunction != null)
|
||||||
|
{
|
||||||
|
pipelineBuilder.withBlend(this.blendFunction);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pipelineBuilder.withoutBlend();
|
||||||
|
}
|
||||||
|
|
||||||
|
pipelineBuilder.withPolygonMode(PolygonMode.FILL);
|
||||||
|
pipelineBuilder.withLocation(Identifier.parse(this.identifierName)); // TODO will complain if capital letters are included
|
||||||
|
|
||||||
|
// TODO manually validate paths to confirm they exist and end with ".fsh" or ".vsh", MC silently fails if the files are missing/improperly named
|
||||||
|
pipelineBuilder.withVertexShader(Identifier.fromNamespaceAndPath("distanthorizons", this.vertexShaderPath));
|
||||||
|
pipelineBuilder.withFragmentShader(Identifier.fromNamespaceAndPath("distanthorizons", this.fragmentShaderPath));
|
||||||
|
|
||||||
|
for (int i = 0; i < this.uniformNames.length; i++)
|
||||||
|
{
|
||||||
|
String uniformName = this.uniformNames[i];
|
||||||
|
pipelineBuilder.withUniform(uniformName, UniformType.UNIFORM_BUFFER);
|
||||||
|
}
|
||||||
|
|
||||||
|
pipelineBuilder.withSampler("uSourceColorTexture");
|
||||||
|
pipelineBuilder.withSampler("uSourceDepthTexture");
|
||||||
|
|
||||||
|
pipelineBuilder.withVertexFormat(vertexFormat, VertexFormat.Mode.TRIANGLE_FAN);
|
||||||
|
}
|
||||||
|
this.pipeline = pipelineBuilder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//========//
|
||||||
|
// render //
|
||||||
|
//========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public void setUniform(String uniformName, GpuBuffer uniformBuffer)
|
||||||
|
{
|
||||||
|
// 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.uniformBuffers[i] = uniformBuffer;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void render(
|
||||||
|
GpuTexture sourceColorTexture,
|
||||||
|
GpuTexture sourceDepthTexture,
|
||||||
|
GpuTexture destinationColorTexture)
|
||||||
|
{
|
||||||
|
this.tryInit(sourceColorTexture, sourceDepthTexture, destinationColorTexture);
|
||||||
|
|
||||||
|
try (RenderPass renderPass = COMMAND_ENCODER.createRenderPass(
|
||||||
|
this::getIdentifierName,
|
||||||
|
this.destinationColorTextureViewWrapper.textureView,
|
||||||
|
/*optionalClearColorAsInt*/ OptionalInt.empty(),
|
||||||
|
/*depthTexture*/ null,
|
||||||
|
/*optionalDepthValueAsDouble*/ OptionalDouble.empty()))
|
||||||
|
{
|
||||||
|
renderPass.bindTexture("uSourceColorTexture", this.sourceColorTextureViewWrapper.textureView, this.sourceColorTextureViewWrapper.textureSampler);
|
||||||
|
renderPass.bindTexture("uSourceDepthTexture", this.sourceDepthTextureViewWrapper.textureView, this.sourceDepthTextureViewWrapper.textureSampler);
|
||||||
|
|
||||||
|
for (int i = 0; i < this.uniformNames.length; i++)
|
||||||
|
{
|
||||||
|
String uniformName = this.uniformNames[i];
|
||||||
|
GpuBuffer uniformBuffer = this.uniformBuffers[i];
|
||||||
|
if (uniformBuffer == null)
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("Missing uniform ["+uniformName+"], please set the uniform before rendering.");
|
||||||
|
}
|
||||||
|
|
||||||
|
renderPass.setUniform(uniformName, uniformBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderPass.setVertexBuffer(0, this.vboGpuBuffer);
|
||||||
|
renderPass.setPipeline(this.pipeline);
|
||||||
|
|
||||||
|
renderPass.draw(/*indexStart*/ 0, /*indexCount*/ 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.uniformBuffers, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+165
@@ -0,0 +1,165 @@
|
|||||||
|
/*
|
||||||
|
* 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.platform.DepthTestFunction;
|
||||||
|
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.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.core.logging.DhLogger;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import net.minecraft.resources.Identifier;
|
||||||
|
|
||||||
|
import java.util.OptionalDouble;
|
||||||
|
import java.util.OptionalInt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
private BlazeDhCopyRenderer() { }
|
||||||
|
|
||||||
|
private void tryInit()
|
||||||
|
{
|
||||||
|
if (this.init)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.init = true;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
RenderPipeline.Builder pipelineBuilder = RenderPipeline.builder();
|
||||||
|
{
|
||||||
|
pipelineBuilder.withCull(false);
|
||||||
|
pipelineBuilder.withDepthWrite(false);
|
||||||
|
pipelineBuilder.withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST);
|
||||||
|
pipelineBuilder.withColorWrite(true);
|
||||||
|
pipelineBuilder.withoutBlend();
|
||||||
|
pipelineBuilder.withPolygonMode(PolygonMode.FILL);
|
||||||
|
pipelineBuilder.withLocation(Identifier.parse("distanthorizons:copy_render"));
|
||||||
|
|
||||||
|
pipelineBuilder.withVertexShader(Identifier.fromNamespaceAndPath("distanthorizons", "copy/blaze/vert"));
|
||||||
|
pipelineBuilder.withFragmentShader(Identifier.fromNamespaceAndPath("distanthorizons", "copy/blaze/frag"));
|
||||||
|
|
||||||
|
pipelineBuilder.withSampler("uCopyTexture");
|
||||||
|
|
||||||
|
pipelineBuilder.withVertexFormat(BlazePostProcessUtil.createVertexFormat(), VertexFormat.Mode.TRIANGLE_FAN);
|
||||||
|
}
|
||||||
|
this.pipeline = pipelineBuilder.build();
|
||||||
|
|
||||||
|
|
||||||
|
this.vboGpuBuffer = BlazePostProcessUtil.createAndUploadScreenVertexData("McCopyRenderer");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//========//
|
||||||
|
// render //
|
||||||
|
//========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public void render(
|
||||||
|
BlazeTextureWrapper sourceColorTextureWrapper,
|
||||||
|
BlazeTextureViewWrapper destinationColorTextureWrapper)
|
||||||
|
{
|
||||||
|
this.render(
|
||||||
|
sourceColorTextureWrapper.textureView, sourceColorTextureWrapper.textureSampler,
|
||||||
|
destinationColorTextureWrapper.textureView);
|
||||||
|
}
|
||||||
|
public void render(
|
||||||
|
BlazeTextureWrapper sourceColorTextureWrapper,
|
||||||
|
BlazeTextureWrapper destinationColorTextureWrapper)
|
||||||
|
{
|
||||||
|
this.render(
|
||||||
|
sourceColorTextureWrapper.textureView, sourceColorTextureWrapper.textureSampler,
|
||||||
|
destinationColorTextureWrapper.textureView);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void render(
|
||||||
|
GpuTextureView sourceTextureView,
|
||||||
|
GpuSampler sourceTextureSampler,
|
||||||
|
GpuTextureView destinationTextureView)
|
||||||
|
{
|
||||||
|
this.tryInit();
|
||||||
|
|
||||||
|
try (RenderPass renderPass = COMMAND_ENCODER.createRenderPass(
|
||||||
|
this::getRenderPassName,
|
||||||
|
destinationTextureView,
|
||||||
|
/*optionalClearColorAsInt*/ OptionalInt.empty(),
|
||||||
|
/*depthTexture*/ null,
|
||||||
|
/*optionalDepthValueAsDouble*/ OptionalDouble.empty()))
|
||||||
|
{
|
||||||
|
renderPass.bindTexture("uCopyTexture", sourceTextureView, sourceTextureSampler);
|
||||||
|
|
||||||
|
renderPass.setVertexBuffer(0, this.vboGpuBuffer); // vertex buffer can only be "0" lol
|
||||||
|
|
||||||
|
renderPass.setPipeline(this.pipeline);
|
||||||
|
renderPass.draw(/*indexStart*/ 0, /*indexCount*/ 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getRenderPassName() { return "distantHorizons:McCopyRenderer"; }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+285
@@ -0,0 +1,285 @@
|
|||||||
|
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.core.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
|
||||||
|
|
||||||
|
public void updateVertexData(List<DhApiRenderableBox> uploadBoxList)
|
||||||
|
{
|
||||||
|
int boxCount = uploadBoxList.size();
|
||||||
|
if (boxCount == 0)
|
||||||
|
{
|
||||||
|
return; // TODO done just to fix a buffer empty crash
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
// TODO make sure this all is a multiple of 4 like LodQuadBuilder (might cause issues with AMD/Mac otherwise)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.vertexBuffer.flip();
|
||||||
|
this.indexBuffer.flip();
|
||||||
|
|
||||||
|
|
||||||
|
this.state = BlazeGenericObjectVertexContainer.EState.READY_TO_UPLOAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int vertexBufferSize()
|
||||||
|
{
|
||||||
|
int faceCount = this.uploadedBoxCount * 6;
|
||||||
|
int vertexCount = faceCount * 6;
|
||||||
|
|
||||||
|
int byteSize = vertexCount * 3 * Float.BYTES; // x,y,z
|
||||||
|
byteSize += vertexCount * 4; // r,g,b,a
|
||||||
|
byteSize += 1; // material
|
||||||
|
return byteSize;
|
||||||
|
}
|
||||||
|
private int indexBufferSize()
|
||||||
|
{
|
||||||
|
int quadCount = this.uploadedBoxCount * 36;
|
||||||
|
int byteSize = quadCount * GLEnums.getTypeSize(GL32.GL_UNSIGNED_INT) * 6;
|
||||||
|
return byteSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void uploadDataToGpu()
|
||||||
|
{
|
||||||
|
// vertex
|
||||||
|
{
|
||||||
|
int totalVertexByteSize = this.vertexBufferSize();
|
||||||
|
if (this.vboGpuBuffer == null
|
||||||
|
|| this.vboGpuBuffer.size() < totalVertexByteSize)
|
||||||
|
{
|
||||||
|
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
|
||||||
|
|| this.indexGpuBuffer.size() < totalVertexByteSize)
|
||||||
|
{
|
||||||
|
int usage = GpuBuffer.USAGE_COPY_DST
|
||||||
|
| GpuBuffer.USAGE_VERTEX
|
||||||
|
| GpuBuffer.USAGE_INDEX
|
||||||
|
| GpuBuffer.USAGE_UNIFORM;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.state = EState.RENDER;
|
||||||
|
}
|
||||||
|
private String getVertexBufferName() { return "distantHorizons:GenericVertexBuffer"; }
|
||||||
|
private String getIndexBufferName() { return "distantHorizons:GenericIndexBuffer"; }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// base overrides //
|
||||||
|
//================//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close()
|
||||||
|
{
|
||||||
|
RenderThreadTaskHandler.INSTANCE.queueRunningOnRenderThread(() ->
|
||||||
|
{
|
||||||
|
if (this.vboGpuBuffer != null)
|
||||||
|
{
|
||||||
|
this.vboGpuBuffer.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.indexGpuBuffer != null)
|
||||||
|
{
|
||||||
|
this.indexGpuBuffer.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+235
@@ -0,0 +1,235 @@
|
|||||||
|
/*
|
||||||
|
* 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.buffers.GpuBufferSlice;
|
||||||
|
import com.mojang.blaze3d.buffers.Std140Builder;
|
||||||
|
import com.mojang.blaze3d.buffers.Std140SizeCalculator;
|
||||||
|
import com.mojang.blaze3d.pipeline.RenderPipeline;
|
||||||
|
import com.mojang.blaze3d.platform.DepthTestFunction;
|
||||||
|
import com.mojang.blaze3d.platform.PolygonMode;
|
||||||
|
import com.mojang.blaze3d.shaders.UniformType;
|
||||||
|
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.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.util.BlazeUniformUtil;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureViewWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureWrapper;
|
||||||
|
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.util.RenderUtil;
|
||||||
|
import com.seibel.distanthorizons.core.util.math.Mat4f;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhFarFadeRenderer;
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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();
|
||||||
|
|
||||||
|
public static final BlazeDhFarFadeRenderer INSTANCE = new BlazeDhFarFadeRenderer();
|
||||||
|
|
||||||
|
private RenderPipeline pipeline;
|
||||||
|
private boolean init = false;
|
||||||
|
|
||||||
|
private GpuBuffer fragUniformBuffer;
|
||||||
|
|
||||||
|
private GpuBuffer vboGpuBuffer;
|
||||||
|
|
||||||
|
public final BlazeTextureWrapper dhFadeColorTextureWrapper = BlazeTextureWrapper.createColor("DhFadeColorTexture");
|
||||||
|
public final BlazeTextureViewWrapper mcColorTextureViewWrapper = new BlazeTextureViewWrapper();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
private BlazeDhFarFadeRenderer() { }
|
||||||
|
|
||||||
|
private void tryInit()
|
||||||
|
{
|
||||||
|
if (this.init)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.init = true;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
RenderPipeline.Builder pipelineBuilder = RenderPipeline.builder();
|
||||||
|
{
|
||||||
|
pipelineBuilder.withCull(false);
|
||||||
|
pipelineBuilder.withDepthWrite(false);
|
||||||
|
pipelineBuilder.withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST);
|
||||||
|
pipelineBuilder.withColorWrite(true);
|
||||||
|
pipelineBuilder.withoutBlend();
|
||||||
|
pipelineBuilder.withPolygonMode(PolygonMode.FILL);
|
||||||
|
pipelineBuilder.withLocation(Identifier.parse("distanthorizons:far_fade"));
|
||||||
|
|
||||||
|
pipelineBuilder.withVertexShader(Identifier.fromNamespaceAndPath("distanthorizons", "fade/blaze/vert"));
|
||||||
|
pipelineBuilder.withFragmentShader(Identifier.fromNamespaceAndPath("distanthorizons", "fade/blaze/dh_fade"));
|
||||||
|
|
||||||
|
pipelineBuilder.withSampler("uMcColorTexture");
|
||||||
|
|
||||||
|
pipelineBuilder.withSampler("uDhDepthTexture");
|
||||||
|
pipelineBuilder.withSampler("uDhColorTexture");
|
||||||
|
|
||||||
|
pipelineBuilder.withUniform("fragUniformBlock", UniformType.UNIFORM_BUFFER);
|
||||||
|
|
||||||
|
pipelineBuilder.withVertexFormat(BlazePostProcessUtil.createVertexFormat(), VertexFormat.Mode.TRIANGLE_FAN);
|
||||||
|
}
|
||||||
|
this.pipeline = pipelineBuilder.build();
|
||||||
|
|
||||||
|
|
||||||
|
this.vboGpuBuffer = BlazePostProcessUtil.createAndUploadScreenVertexData("McFadeRenderer");
|
||||||
|
}
|
||||||
|
|
||||||
|
//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(Minecraft.getInstance().getMainRenderTarget().getColorTexture());
|
||||||
|
|
||||||
|
{
|
||||||
|
int uniformBufferSize = new Std140SizeCalculator()
|
||||||
|
.putFloat() // uStartFadeBlockDistance
|
||||||
|
.putFloat() // uEndFadeBlockDistance
|
||||||
|
.putMat4f() // uDhInvMvmProj
|
||||||
|
.get();
|
||||||
|
|
||||||
|
|
||||||
|
// create data //
|
||||||
|
|
||||||
|
float dhFarClipDistance = RenderUtil.getFarClipPlaneDistanceInBlocks();
|
||||||
|
float fadeStartDistance = dhFarClipDistance * 0.5f;
|
||||||
|
float fadeEndDistance = dhFarClipDistance * 0.9f;
|
||||||
|
|
||||||
|
|
||||||
|
Mat4f dhProjectionMatrix = RenderUtil.createLodProjectionMatrix(renderParams.mcProjectionMatrix);
|
||||||
|
Mat4f dhModelViewMatrix = RenderUtil.createLodModelViewMatrix(renderParams.mcModelViewMatrix);
|
||||||
|
|
||||||
|
Mat4f inverseDhMvmProjMatrix = new Mat4f(dhProjectionMatrix);
|
||||||
|
inverseDhMvmProjMatrix.multiply(dhModelViewMatrix);
|
||||||
|
inverseDhMvmProjMatrix.invert();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// upload data //
|
||||||
|
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocateDirect(uniformBufferSize);
|
||||||
|
buffer.order(ByteOrder.nativeOrder());
|
||||||
|
buffer = Std140Builder.intoBuffer(buffer)
|
||||||
|
.putFloat(fadeStartDistance) // uStartFadeBlockDistance
|
||||||
|
.putFloat(fadeEndDistance) // uEndFadeBlockDistance
|
||||||
|
.putMat4f(inverseDhMvmProjMatrix.createJomlMatrix()) // uDhInvMvmProj
|
||||||
|
.get()
|
||||||
|
;
|
||||||
|
|
||||||
|
this.fragUniformBuffer = BlazeUniformUtil.createBuffer("fragUniformBlock", uniformBufferSize, this.fragUniformBuffer);
|
||||||
|
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.fragUniformBuffer, 0, uniformBufferSize);
|
||||||
|
|
||||||
|
COMMAND_ENCODER.writeToBuffer(bufferSlice, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
this.renderFadeToTexture();
|
||||||
|
BlazeDhCopyRenderer.INSTANCE.render(this.dhFadeColorTextureWrapper, BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderFadeToTexture()
|
||||||
|
{
|
||||||
|
try (RenderPass renderPass = COMMAND_ENCODER.createRenderPass(
|
||||||
|
this::getRenderPassName,
|
||||||
|
this.dhFadeColorTextureWrapper.textureView,
|
||||||
|
/*optionalClearColorAsInt*/ OptionalInt.empty(),
|
||||||
|
/*depthTexture*/ null,
|
||||||
|
/*optionalDepthValueAsDouble*/ OptionalDouble.empty()))
|
||||||
|
{
|
||||||
|
// MC texture
|
||||||
|
renderPass.bindTexture("uMcColorTexture", this.mcColorTextureViewWrapper.textureView, this.mcColorTextureViewWrapper.textureSampler);
|
||||||
|
|
||||||
|
// DH textures
|
||||||
|
renderPass.bindTexture("uDhDepthTexture", BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureView, BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureSampler);
|
||||||
|
renderPass.bindTexture("uDhColorTexture", BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.textureView, BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.textureSampler);
|
||||||
|
|
||||||
|
renderPass.setUniform("fragUniformBlock", this.fragUniformBuffer);
|
||||||
|
|
||||||
|
renderPass.setVertexBuffer(0, this.vboGpuBuffer); // vertex buffer can only be "0" lol
|
||||||
|
renderPass.setPipeline(this.pipeline);
|
||||||
|
|
||||||
|
renderPass.draw(/*indexStart*/ 0, /*indexCount*/ 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private String getRenderPassName() { return "distantHorizons:McFadeRenderer"; }
|
||||||
|
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+363
@@ -0,0 +1,363 @@
|
|||||||
|
/*
|
||||||
|
* 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.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.pipeline.BlendFunction;
|
||||||
|
import com.mojang.blaze3d.pipeline.RenderPipeline;
|
||||||
|
import com.mojang.blaze3d.platform.DepthTestFunction;
|
||||||
|
import com.mojang.blaze3d.platform.DestFactor;
|
||||||
|
import com.mojang.blaze3d.platform.PolygonMode;
|
||||||
|
import com.mojang.blaze3d.platform.SourceFactor;
|
||||||
|
import com.mojang.blaze3d.shaders.UniformType;
|
||||||
|
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.api.enums.rendering.EDhApiFogColorMode;
|
||||||
|
import com.seibel.distanthorizons.api.enums.rendering.EDhApiHeightFogDirection;
|
||||||
|
import com.seibel.distanthorizons.api.enums.rendering.EDhApiHeightFogMixMode;
|
||||||
|
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.texture.BlazeTextureWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.util.BlazePostProcessUtil;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.util.BlazeUniformUtil;
|
||||||
|
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.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.renderPass.IDhFogRenderer;
|
||||||
|
import net.minecraft.resources.Identifier;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
import java.util.OptionalDouble;
|
||||||
|
import java.util.OptionalInt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 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 GpuBuffer fragUniformBuffer;
|
||||||
|
|
||||||
|
private GpuBuffer vboGpuBuffer;
|
||||||
|
|
||||||
|
public BlazeTextureWrapper fogColorTextureWrapper = BlazeTextureWrapper.createColor("DhFogColorTexture");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
private BlazeDhFogRenderer() { }
|
||||||
|
|
||||||
|
private void tryInit()
|
||||||
|
{
|
||||||
|
if (this.init)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.init = true;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
this.applyRenderer = new BlazeDhApplyRenderer(
|
||||||
|
"fog_apply_to_dh",
|
||||||
|
new BlendFunction(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ONE_MINUS_SRC_ALPHA),
|
||||||
|
"apply/blaze/vert", "apply/blaze/frag"
|
||||||
|
);
|
||||||
|
|
||||||
|
RenderPipeline.Builder pipelineBuilder = RenderPipeline.builder();
|
||||||
|
{
|
||||||
|
pipelineBuilder.withCull(false);
|
||||||
|
pipelineBuilder.withDepthWrite(false);
|
||||||
|
pipelineBuilder.withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST);
|
||||||
|
pipelineBuilder.withColorWrite(true);
|
||||||
|
pipelineBuilder.withoutBlend();
|
||||||
|
pipelineBuilder.withPolygonMode(PolygonMode.FILL);
|
||||||
|
pipelineBuilder.withLocation(Identifier.parse("distanthorizons:fog_render"));
|
||||||
|
|
||||||
|
pipelineBuilder.withVertexShader(Identifier.fromNamespaceAndPath("distanthorizons", "fog/blaze/vert"));
|
||||||
|
pipelineBuilder.withFragmentShader(Identifier.fromNamespaceAndPath("distanthorizons", "fog/blaze/frag"));
|
||||||
|
|
||||||
|
pipelineBuilder.withSampler("uDhDepthTexture");
|
||||||
|
|
||||||
|
pipelineBuilder.withUniform("fragUniformBlock", UniformType.UNIFORM_BUFFER);
|
||||||
|
|
||||||
|
pipelineBuilder.withVertexFormat(BlazePostProcessUtil.createVertexFormat(), VertexFormat.Mode.TRIANGLE_FAN);
|
||||||
|
}
|
||||||
|
this.pipeline = pipelineBuilder.build();
|
||||||
|
|
||||||
|
|
||||||
|
this.vboGpuBuffer = BlazePostProcessUtil.createAndUploadScreenVertexData("McFogRenderer");
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//========//
|
||||||
|
// render //
|
||||||
|
//========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(RenderParams renderParams)
|
||||||
|
{
|
||||||
|
this.tryInit();
|
||||||
|
|
||||||
|
|
||||||
|
if (BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.isEmpty()
|
||||||
|
|| BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.isEmpty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
this.fogColorTextureWrapper.tryCreateOrResize();
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
int uniformBufferSize = new Std140SizeCalculator()
|
||||||
|
|
||||||
|
// fog uniforms
|
||||||
|
.putVec4() // uFogColor
|
||||||
|
.putFloat() //uFogScale
|
||||||
|
.putFloat() //uFogVerticalScale
|
||||||
|
// only used for debugging
|
||||||
|
.putInt() //uFogDebugMode // 1 = render everything with fog color // 7 = use debug rendering
|
||||||
|
.putInt() //uFogFalloffType
|
||||||
|
|
||||||
|
// fog config
|
||||||
|
.putFloat() // uFarFogStart
|
||||||
|
.putFloat() // uFarFogLength
|
||||||
|
.putFloat() // uFarFogMin
|
||||||
|
.putFloat() // uFarFogRange
|
||||||
|
.putFloat() // uFarFogDensity
|
||||||
|
|
||||||
|
// height fog config
|
||||||
|
.putFloat() // uHeightFogStart
|
||||||
|
.putFloat() // uHeightFogLength
|
||||||
|
.putFloat() // uHeightFogMin
|
||||||
|
.putFloat() // uHeightFogRange
|
||||||
|
.putFloat() // uHeightFogDensity
|
||||||
|
|
||||||
|
// ??
|
||||||
|
.putInt() // uHeightFogEnabled
|
||||||
|
.putInt() // uHeightFogFalloffType
|
||||||
|
.putInt() // uHeightBasedOnCamera
|
||||||
|
.putFloat() // uHeightFogBaseHeight
|
||||||
|
.putInt() // uHeightFogAppliesUp
|
||||||
|
.putInt() // uHeightFogAppliesDown
|
||||||
|
.putInt() // uUseSphericalFog
|
||||||
|
.putInt() // uHeightFogMixingMode
|
||||||
|
.putFloat() // uCameraBlockYPos
|
||||||
|
|
||||||
|
.putMat4f() // uInvMvmProj
|
||||||
|
|
||||||
|
.get();
|
||||||
|
|
||||||
|
|
||||||
|
// create data //
|
||||||
|
|
||||||
|
|
||||||
|
int lodDrawDistance = Config.Client.Advanced.Graphics.Quality.lodChunkRenderDistanceRadius.get() * LodUtil.CHUNK_WIDTH;
|
||||||
|
|
||||||
|
|
||||||
|
Mat4f inverseMvmProjMatrix = new Mat4f(renderParams.dhMvmProjMatrix);
|
||||||
|
inverseMvmProjMatrix.invert();
|
||||||
|
|
||||||
|
if (renderParams.dhMvmProjMatrix == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Color fogColor = this.getFogColor(renderParams.partialTicks);
|
||||||
|
|
||||||
|
// fog config
|
||||||
|
float farFogStart = Config.Client.Advanced.Graphics.Fog.farFogStart.get();
|
||||||
|
float farFogEnd = Config.Client.Advanced.Graphics.Fog.farFogEnd.get();
|
||||||
|
float farFogMin = Config.Client.Advanced.Graphics.Fog.farFogMin.get();
|
||||||
|
float farFogMax = Config.Client.Advanced.Graphics.Fog.farFogMax.get();
|
||||||
|
float farFogDensity = Config.Client.Advanced.Graphics.Fog.farFogDensity.get();
|
||||||
|
|
||||||
|
// override fog if underwater
|
||||||
|
if (MC_RENDER.isFogStateSpecial())
|
||||||
|
{
|
||||||
|
// hide everything behind fog
|
||||||
|
farFogStart = 0.0f;
|
||||||
|
farFogEnd = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// height config
|
||||||
|
EDhApiHeightFogMixMode heightFogMixingMode = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogMixMode.get();
|
||||||
|
boolean heightFogEnabled = heightFogMixingMode != EDhApiHeightFogMixMode.SPHERICAL && heightFogMixingMode != EDhApiHeightFogMixMode.CYLINDRICAL;
|
||||||
|
boolean useSphericalFog = heightFogMixingMode == EDhApiHeightFogMixMode.SPHERICAL;
|
||||||
|
EDhApiHeightFogDirection heightFogCameraDirection = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogDirection.get();
|
||||||
|
|
||||||
|
float heightFogStart = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogStart.get();
|
||||||
|
float heightFogEnd = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogEnd.get();
|
||||||
|
float heightFogMin = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogMin.get();
|
||||||
|
float heightFogMax = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogMax.get();
|
||||||
|
float heightFogDensity = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogDensity.get();
|
||||||
|
|
||||||
|
|
||||||
|
// upload data //
|
||||||
|
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocateDirect(uniformBufferSize);
|
||||||
|
buffer.order(ByteOrder.nativeOrder());
|
||||||
|
buffer = Std140Builder.intoBuffer(buffer)
|
||||||
|
|
||||||
|
// fog uniforms
|
||||||
|
.putVec4(
|
||||||
|
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
|
||||||
|
// only used for debugging
|
||||||
|
.putInt(0) //uFogDebugMode // 1 = render everything with fog color // 7 = use debug rendering
|
||||||
|
.putInt(Config.Client.Advanced.Graphics.Fog.farFogFalloff.get().value) //uFogFalloffType
|
||||||
|
|
||||||
|
// fog config
|
||||||
|
.putFloat(farFogStart) // uFarFogStart
|
||||||
|
.putFloat(farFogEnd - farFogStart) // uFarFogLength
|
||||||
|
.putFloat(farFogMin) // uFarFogMin
|
||||||
|
.putFloat(farFogMax - farFogMin) // uFarFogRange
|
||||||
|
.putFloat(farFogDensity) // uFarFogDensity
|
||||||
|
|
||||||
|
// height fog config
|
||||||
|
.putFloat(heightFogStart) // uHeightFogStart
|
||||||
|
.putFloat(heightFogEnd - heightFogStart) // uHeightFogLength
|
||||||
|
.putFloat(heightFogMin) // uHeightFogMin
|
||||||
|
.putFloat(heightFogMax - heightFogMin) // uHeightFogRange
|
||||||
|
.putFloat(heightFogDensity) // uHeightFogDensity
|
||||||
|
|
||||||
|
// ??
|
||||||
|
.putInt(heightFogEnabled ? 1 : 0) // uHeightFogEnabled
|
||||||
|
.putInt(Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogFalloff.get().value) // uHeightFogFalloffType
|
||||||
|
.putInt(heightFogCameraDirection.basedOnCamera ? 1 : 0) // uHeightBasedOnCamera
|
||||||
|
.putFloat(Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogBaseHeight.get()) // uHeightFogBaseHeight
|
||||||
|
.putInt(heightFogCameraDirection.fogAppliesUp ? 1 : 0) // uHeightFogAppliesUp
|
||||||
|
.putInt(heightFogCameraDirection.fogAppliesDown ? 1 : 0) // uHeightFogAppliesDown
|
||||||
|
.putInt(useSphericalFog ? 1 : 0) // uUseSphericalFog
|
||||||
|
.putInt(heightFogMixingMode.value) // uHeightFogMixingMode
|
||||||
|
.putFloat((float)MC_RENDER.getCameraExactPosition().y) // uCameraBlockYPos
|
||||||
|
|
||||||
|
.putMat4f(inverseMvmProjMatrix.createJomlMatrix()) // uInvMvmProj
|
||||||
|
|
||||||
|
.get()
|
||||||
|
;
|
||||||
|
|
||||||
|
this.fragUniformBuffer = BlazeUniformUtil.createBuffer("fragUniformBlock", uniformBufferSize, this.fragUniformBuffer);
|
||||||
|
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.fragUniformBuffer, 0, uniformBufferSize);
|
||||||
|
|
||||||
|
COMMAND_ENCODER.writeToBuffer(bufferSlice, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
this.renderFogToTexture();
|
||||||
|
this.applyRenderer.render(this.fogColorTextureWrapper.texture, BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.texture, BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.texture);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private Color getFogColor(float partialTicks)
|
||||||
|
{
|
||||||
|
Color fogColor;
|
||||||
|
|
||||||
|
if (Config.Client.Advanced.Graphics.Fog.colorMode.get() == EDhApiFogColorMode.USE_SKY_COLOR)
|
||||||
|
{
|
||||||
|
fogColor = MC_RENDER.getSkyColor();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fogColor = MC_RENDER.getFogColor(partialTicks);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fogColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderFogToTexture()
|
||||||
|
{
|
||||||
|
try (RenderPass renderPass = COMMAND_ENCODER.createRenderPass(
|
||||||
|
this::getRenderPassName,
|
||||||
|
this.fogColorTextureWrapper.textureView,
|
||||||
|
/*optionalClearColorAsInt*/ OptionalInt.empty(),
|
||||||
|
/*depthTexture*/ null,
|
||||||
|
/*optionalDepthValueAsDouble*/ OptionalDouble.empty()))
|
||||||
|
{
|
||||||
|
renderPass.bindTexture("uDhDepthTexture", BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureView, BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureSampler);
|
||||||
|
|
||||||
|
renderPass.setUniform("fragUniformBlock", this.fragUniformBuffer);
|
||||||
|
|
||||||
|
renderPass.setVertexBuffer(0, this.vboGpuBuffer); // vertex buffer can only be "0" lol
|
||||||
|
renderPass.setPipeline(this.pipeline);
|
||||||
|
|
||||||
|
renderPass.draw(/*indexStart*/ 0, /*indexCount*/ 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private String getRenderPassName() { return "distantHorizons:McFogRenderer"; }
|
||||||
|
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+283
@@ -0,0 +1,283 @@
|
|||||||
|
/*
|
||||||
|
* 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.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.pipeline.BlendFunction;
|
||||||
|
import com.mojang.blaze3d.pipeline.RenderPipeline;
|
||||||
|
import com.mojang.blaze3d.platform.DepthTestFunction;
|
||||||
|
import com.mojang.blaze3d.platform.DestFactor;
|
||||||
|
import com.mojang.blaze3d.platform.PolygonMode;
|
||||||
|
import com.mojang.blaze3d.platform.SourceFactor;
|
||||||
|
import com.mojang.blaze3d.shaders.UniformType;
|
||||||
|
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.BlazeDhMetaRenderer;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.apply.BlazeDhApplyRenderer;
|
||||||
|
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.util.BlazeUniformUtil;
|
||||||
|
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.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.renderPass.IDhSsaoRenderer;
|
||||||
|
import net.minecraft.resources.Identifier;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
import java.util.OptionalDouble;
|
||||||
|
import java.util.OptionalInt;
|
||||||
|
|
||||||
|
/** 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 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 GpuBuffer fragUniformBuffer;
|
||||||
|
private GpuBuffer applyFragUniformBuffer;
|
||||||
|
|
||||||
|
private GpuBuffer vboGpuBuffer;
|
||||||
|
|
||||||
|
public BlazeTextureWrapper ssaoColorTextureWrapper = BlazeTextureWrapper.createColor("DhSsaoTexture");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
private BlazeDhSsaoRenderer() { }
|
||||||
|
|
||||||
|
private void tryInit()
|
||||||
|
{
|
||||||
|
if (this.init)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.init = true;
|
||||||
|
|
||||||
|
|
||||||
|
this.applyRenderer = new BlazeDhApplyRenderer(
|
||||||
|
"ssao_apply_to_dh",
|
||||||
|
new BlendFunction(SourceFactor.ZERO, DestFactor.SRC_ALPHA, SourceFactor.ZERO, DestFactor.ONE),
|
||||||
|
"apply/blaze/vert", "ssao/blaze/apply",
|
||||||
|
/*uniforms*/ new String[] { "applyFragUniformBlock" }
|
||||||
|
);
|
||||||
|
|
||||||
|
RenderPipeline.Builder pipelineBuilder = RenderPipeline.builder();
|
||||||
|
{
|
||||||
|
pipelineBuilder.withCull(false);
|
||||||
|
pipelineBuilder.withDepthWrite(false);
|
||||||
|
pipelineBuilder.withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST);
|
||||||
|
pipelineBuilder.withColorWrite(true);
|
||||||
|
pipelineBuilder.withoutBlend();
|
||||||
|
pipelineBuilder.withPolygonMode(PolygonMode.FILL);
|
||||||
|
pipelineBuilder.withLocation(Identifier.parse("distanthorizons:ssao_render"));
|
||||||
|
|
||||||
|
pipelineBuilder.withVertexShader(Identifier.fromNamespaceAndPath("distanthorizons", "ssao/blaze/vert"));
|
||||||
|
pipelineBuilder.withFragmentShader(Identifier.fromNamespaceAndPath("distanthorizons", "ssao/blaze/frag"));
|
||||||
|
|
||||||
|
pipelineBuilder.withSampler("uDhDepthTexture");
|
||||||
|
|
||||||
|
pipelineBuilder.withUniform("fragUniformBlock", UniformType.UNIFORM_BUFFER);
|
||||||
|
|
||||||
|
pipelineBuilder.withVertexFormat(BlazePostProcessUtil.createVertexFormat(), VertexFormat.Mode.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();
|
||||||
|
|
||||||
|
// frag uniforms
|
||||||
|
{
|
||||||
|
int uniformBufferSize = new Std140SizeCalculator()
|
||||||
|
.putInt() // uSampleCount\
|
||||||
|
|
||||||
|
.putFloat() // uRadius
|
||||||
|
.putFloat() // uStrength
|
||||||
|
.putFloat() // uMinLight
|
||||||
|
.putFloat() // uBias
|
||||||
|
.putFloat() // uFadeDistanceInBlocks
|
||||||
|
|
||||||
|
.putMat4f() // uInvProj
|
||||||
|
.putMat4f() // uProj
|
||||||
|
.get();
|
||||||
|
|
||||||
|
|
||||||
|
// create data //
|
||||||
|
|
||||||
|
Mat4f projMatrix = new Mat4f(renderParams.dhProjectionMatrix);
|
||||||
|
Mat4f invertedProjMatrix = new Mat4f(renderParams.dhProjectionMatrix);
|
||||||
|
invertedProjMatrix.invert();
|
||||||
|
|
||||||
|
|
||||||
|
// upload data //
|
||||||
|
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocateDirect(uniformBufferSize);
|
||||||
|
buffer.order(ByteOrder.nativeOrder());
|
||||||
|
buffer = Std140Builder.intoBuffer(buffer)
|
||||||
|
.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.createJomlMatrix())
|
||||||
|
.putMat4f(projMatrix.createJomlMatrix())
|
||||||
|
.get()
|
||||||
|
;
|
||||||
|
|
||||||
|
this.fragUniformBuffer = BlazeUniformUtil.createBuffer("fragUniformBlock", uniformBufferSize, this.fragUniformBuffer);
|
||||||
|
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.fragUniformBuffer, 0, uniformBufferSize);
|
||||||
|
|
||||||
|
COMMAND_ENCODER.writeToBuffer(bufferSlice, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// apply frag uniforms
|
||||||
|
{
|
||||||
|
int uniformBufferSize = new Std140SizeCalculator()
|
||||||
|
.putVec2() // uViewSize
|
||||||
|
.putInt() // uBlurRadius
|
||||||
|
.putFloat() // uNearClipPlane
|
||||||
|
.putFloat() // uFarClipPlane
|
||||||
|
.get();
|
||||||
|
|
||||||
|
|
||||||
|
// create data //
|
||||||
|
|
||||||
|
float viewWidth = (float)MC_RENDER.getTargetFramebufferViewportWidth();
|
||||||
|
float viewHeight = (float)MC_RENDER.getTargetFramebufferViewportHeight();
|
||||||
|
|
||||||
|
float nearClipPlane = RenderUtil.getNearClipPlaneInBlocks();
|
||||||
|
float farClipPlane = RenderUtil.getFarClipPlaneDistanceInBlocks();
|
||||||
|
|
||||||
|
|
||||||
|
// upload data //
|
||||||
|
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocateDirect(uniformBufferSize);
|
||||||
|
buffer.order(ByteOrder.nativeOrder());
|
||||||
|
buffer = Std140Builder.intoBuffer(buffer)
|
||||||
|
.putVec2(viewWidth, viewHeight) // uViewSize
|
||||||
|
.putInt(2) // uBlurRadius
|
||||||
|
.putFloat(nearClipPlane) // uNearClipPlane
|
||||||
|
.putFloat(farClipPlane) // uFarClipPlane
|
||||||
|
.get()
|
||||||
|
;
|
||||||
|
|
||||||
|
this.applyFragUniformBuffer = BlazeUniformUtil.createBuffer("applyFragUniformBlock", uniformBufferSize, this.applyFragUniformBuffer);
|
||||||
|
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.applyFragUniformBuffer, 0, uniformBufferSize);
|
||||||
|
|
||||||
|
COMMAND_ENCODER.writeToBuffer(bufferSlice, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
this.renderSsaoToTexture();
|
||||||
|
|
||||||
|
this.applyRenderer.setUniform("applyFragUniformBlock", this.applyFragUniformBuffer);
|
||||||
|
this.applyRenderer.render(this.ssaoColorTextureWrapper.texture, BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.texture, BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.texture);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderSsaoToTexture()
|
||||||
|
{
|
||||||
|
try (RenderPass renderPass = COMMAND_ENCODER.createRenderPass(
|
||||||
|
this::getRenderPassName,
|
||||||
|
this.ssaoColorTextureWrapper.textureView,
|
||||||
|
/*optionalClearColorAsInt*/ OptionalInt.empty(),
|
||||||
|
/*depthTexture*/ null,
|
||||||
|
/*optionalDepthValueAsDouble*/ OptionalDouble.empty()))
|
||||||
|
{
|
||||||
|
renderPass.bindTexture("uDhDepthTexture", BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureView, BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureSampler);
|
||||||
|
|
||||||
|
renderPass.setUniform("fragUniformBlock", this.fragUniformBuffer);
|
||||||
|
|
||||||
|
renderPass.setVertexBuffer(0, this.vboGpuBuffer); // vertex buffer can only be "0" lol
|
||||||
|
|
||||||
|
renderPass.setPipeline(this.pipeline);
|
||||||
|
renderPass.draw(/*indexStart*/ 0, /*indexCount*/ 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private String getRenderPassName() { return "distantHorizons:McSsaoRenderer"; }
|
||||||
|
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+262
@@ -0,0 +1,262 @@
|
|||||||
|
/*
|
||||||
|
* 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.buffers.GpuBufferSlice;
|
||||||
|
import com.mojang.blaze3d.buffers.Std140Builder;
|
||||||
|
import com.mojang.blaze3d.buffers.Std140SizeCalculator;
|
||||||
|
import com.mojang.blaze3d.pipeline.RenderPipeline;
|
||||||
|
import com.mojang.blaze3d.platform.DepthTestFunction;
|
||||||
|
import com.mojang.blaze3d.platform.PolygonMode;
|
||||||
|
import com.mojang.blaze3d.shaders.UniformType;
|
||||||
|
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.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.util.BlazeUniformUtil;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureViewWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureWrapper;
|
||||||
|
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.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.renderPass.IDhVanillaFadeRenderer;
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 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 GpuBuffer fragUniformBuffer;
|
||||||
|
|
||||||
|
private GpuBuffer vboGpuBuffer;
|
||||||
|
|
||||||
|
public final BlazeTextureWrapper fadeColorTextureWrapper = BlazeTextureWrapper.createColor("DhVanillaFadeTexture");
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
RenderPipeline.Builder pipelineBuilder = RenderPipeline.builder();
|
||||||
|
{
|
||||||
|
pipelineBuilder.withCull(false);
|
||||||
|
pipelineBuilder.withDepthWrite(false);
|
||||||
|
pipelineBuilder.withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST);
|
||||||
|
pipelineBuilder.withColorWrite(true);
|
||||||
|
pipelineBuilder.withoutBlend();
|
||||||
|
pipelineBuilder.withPolygonMode(PolygonMode.FILL);
|
||||||
|
pipelineBuilder.withLocation(Identifier.parse("distanthorizons:mc_vanilla_fade_render"));
|
||||||
|
|
||||||
|
pipelineBuilder.withVertexShader(Identifier.fromNamespaceAndPath("distanthorizons", "fade/blaze/vert"));
|
||||||
|
pipelineBuilder.withFragmentShader(Identifier.fromNamespaceAndPath("distanthorizons", "fade/blaze/vanilla_fade"));
|
||||||
|
|
||||||
|
pipelineBuilder.withSampler("uMcDepthTexture");
|
||||||
|
pipelineBuilder.withSampler("uCombinedMcDhColorTexture");
|
||||||
|
|
||||||
|
pipelineBuilder.withSampler("uDhDepthTexture");
|
||||||
|
pipelineBuilder.withSampler("uDhColorTexture");
|
||||||
|
|
||||||
|
pipelineBuilder.withUniform("fragUniformBlock", UniformType.UNIFORM_BUFFER);
|
||||||
|
|
||||||
|
pipelineBuilder.withVertexFormat(BlazePostProcessUtil.createVertexFormat(), VertexFormat.Mode.TRIANGLE_FAN);
|
||||||
|
}
|
||||||
|
this.pipeline = pipelineBuilder.build();
|
||||||
|
|
||||||
|
|
||||||
|
this.vboGpuBuffer = BlazePostProcessUtil.createAndUploadScreenVertexData("McFadeRenderer");
|
||||||
|
}
|
||||||
|
|
||||||
|
//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.mcDepthTextureWrapper.tryWrap(Minecraft.getInstance().getMainRenderTarget().getDepthTexture());
|
||||||
|
this.mcColorTextureWrapper.tryWrap(Minecraft.getInstance().getMainRenderTarget().getColorTexture());
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
int uniformBufferSize = new Std140SizeCalculator()
|
||||||
|
.putInt() // uOnlyRenderLods
|
||||||
|
.putFloat() // uStartFadeBlockDistance
|
||||||
|
.putFloat() // uEndFadeBlockDistance
|
||||||
|
.putFloat() // uMaxLevelHeight
|
||||||
|
.putMat4f() // uDhInvMvmProj
|
||||||
|
.putMat4f() // uMcInvMvmProj
|
||||||
|
.get();
|
||||||
|
|
||||||
|
|
||||||
|
// 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 dhProjectionMatrix = RenderUtil.createLodProjectionMatrix(renderParams.mcProjectionMatrix);
|
||||||
|
Mat4f dhModelViewMatrix = RenderUtil.createLodModelViewMatrix(renderParams.mcModelViewMatrix);
|
||||||
|
|
||||||
|
Mat4f inverseDhModelViewProjectionMatrix = new Mat4f(dhProjectionMatrix);
|
||||||
|
inverseDhModelViewProjectionMatrix.multiply(dhModelViewMatrix);
|
||||||
|
inverseDhModelViewProjectionMatrix.invert();
|
||||||
|
Mat4f inverseDhMvmProjMatrix = inverseDhModelViewProjectionMatrix;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// upload data //
|
||||||
|
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocateDirect(uniformBufferSize);
|
||||||
|
buffer.order(ByteOrder.nativeOrder());
|
||||||
|
buffer = Std140Builder.intoBuffer(buffer)
|
||||||
|
.putInt(Config.Client.Advanced.Debugging.lodOnlyMode.get() ? 1 : 0) // uOnlyRenderLods
|
||||||
|
.putFloat(fadeStartDistance) // uStartFadeBlockDistance
|
||||||
|
.putFloat(fadeEndDistance) // uEndFadeBlockDistance
|
||||||
|
.putFloat(renderParams.clientLevelWrapper.getMaxHeight()) // uMaxLevelHeight
|
||||||
|
.putMat4f(inverseDhMvmProjMatrix.createJomlMatrix()) // uDhInvMvmProj
|
||||||
|
.putMat4f(inverseMcMvmProjMatrix.createJomlMatrix()) // uMcInvMvmProj
|
||||||
|
.get()
|
||||||
|
;
|
||||||
|
|
||||||
|
this.fragUniformBuffer = BlazeUniformUtil.createBuffer("fragUniformBlock", uniformBufferSize, this.fragUniformBuffer);
|
||||||
|
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.fragUniformBuffer, 0, uniformBufferSize);
|
||||||
|
|
||||||
|
COMMAND_ENCODER.writeToBuffer(bufferSlice, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
this.renderFadeToTexture();
|
||||||
|
BlazeDhCopyRenderer.INSTANCE.render(this.fadeColorTextureWrapper, this.mcColorTextureWrapper);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderFadeToTexture()
|
||||||
|
{
|
||||||
|
try (RenderPass renderPass = COMMAND_ENCODER.createRenderPass(
|
||||||
|
this::getRenderPassName,
|
||||||
|
this.fadeColorTextureWrapper.textureView,
|
||||||
|
/*optionalClearColorAsInt*/ OptionalInt.empty(),
|
||||||
|
/*depthTexture*/ null,
|
||||||
|
/*optionalDepthValueAsDouble*/ OptionalDouble.empty()))
|
||||||
|
{
|
||||||
|
renderPass.bindTexture("uMcDepthTexture", this.mcDepthTextureWrapper.textureView, this.mcDepthTextureWrapper.textureSampler);
|
||||||
|
renderPass.bindTexture("uCombinedMcDhColorTexture", this.mcColorTextureWrapper.textureView, this.mcColorTextureWrapper.textureSampler);
|
||||||
|
|
||||||
|
renderPass.bindTexture("uDhDepthTexture", BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureView, BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureSampler);
|
||||||
|
renderPass.bindTexture("uDhColorTexture", BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.textureView, BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.textureSampler);
|
||||||
|
|
||||||
|
renderPass.setUniform("fragUniformBlock", this.fragUniformBuffer);
|
||||||
|
|
||||||
|
renderPass.setVertexBuffer(0, this.vboGpuBuffer); // vertex buffer can only be "0" lol
|
||||||
|
|
||||||
|
renderPass.setPipeline(this.pipeline);
|
||||||
|
renderPass.draw(/*indexStart*/ 0, /*indexCount*/ 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private String getRenderPassName() { return "distantHorizons:McFadeRenderer"; }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+192
@@ -0,0 +1,192 @@
|
|||||||
|
/*
|
||||||
|
* 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.DepthTestFunction;
|
||||||
|
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.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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
private GpuTextureView mcColorTextureView;
|
||||||
|
|
||||||
|
private GpuBuffer vboGpuBuffer;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
private BlazeDhTestTriangleRenderer() { }
|
||||||
|
|
||||||
|
private void tryInit()
|
||||||
|
{
|
||||||
|
if (this.init)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.init = true;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
VertexFormat vertexFormat = VertexFormat.builder()
|
||||||
|
.add("vPosition", BlazeDhVertexFormatUtil.SCREEN_POS)
|
||||||
|
.add("vColor", BlazeDhVertexFormatUtil.RGBA_FLOAT_COLOR)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
//int breakpointOne = 0;
|
||||||
|
// needs to manually be set if the VertexFormatElement isn't registered
|
||||||
|
//this.vertexFormat.getOffsetsByElement()[this.posForm.id()] = 0;
|
||||||
|
//this.vertexFormat.getOffsetsByElement()[this.colForm.id()] = Float.BYTES * 2;
|
||||||
|
//
|
||||||
|
//int breakpointTwo = 0;
|
||||||
|
|
||||||
|
|
||||||
|
RenderPipeline.Builder pipelineBuilder = RenderPipeline.builder();
|
||||||
|
{
|
||||||
|
pipelineBuilder.withCull(false);
|
||||||
|
pipelineBuilder.withDepthWrite(false);
|
||||||
|
pipelineBuilder.withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST);
|
||||||
|
pipelineBuilder.withColorWrite(true);
|
||||||
|
pipelineBuilder.withoutBlend();
|
||||||
|
pipelineBuilder.withPolygonMode(PolygonMode.FILL);
|
||||||
|
pipelineBuilder.withLocation(Identifier.parse("distanthorizons:test_render"));
|
||||||
|
|
||||||
|
pipelineBuilder.withVertexShader(Identifier.fromNamespaceAndPath("distanthorizons", "test/blaze/vert"));
|
||||||
|
pipelineBuilder.withFragmentShader(Identifier.fromNamespaceAndPath("distanthorizons", "test/blaze/frag"));
|
||||||
|
|
||||||
|
pipelineBuilder.withVertexFormat(vertexFormat, VertexFormat.Mode.TRIANGLES);
|
||||||
|
}
|
||||||
|
this.pipeline = pipelineBuilder.build();
|
||||||
|
|
||||||
|
|
||||||
|
this.mcColorTextureView = GPU_DEVICE.createTextureView(Minecraft.getInstance().getMainRenderTarget().getColorTexture());
|
||||||
|
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
try (RenderPass renderPass = COMMAND_ENCODER.createRenderPass(
|
||||||
|
this::getRenderPassName,
|
||||||
|
this.mcColorTextureView,
|
||||||
|
/*optionalClearColorAsInt*/ OptionalInt.empty(),
|
||||||
|
/*mcDepthTextureView*/ null,
|
||||||
|
/*optionalDepthValueAsDouble*/ OptionalDouble.empty()))
|
||||||
|
{
|
||||||
|
renderPass.setVertexBuffer(0, this.vboGpuBuffer);
|
||||||
|
renderPass.setPipeline(this.pipeline);
|
||||||
|
renderPass.draw(/*indexStart*/ 0, /*indexCount*/ 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private String getRenderPassName() { return "distantHorizons:DhTestRenderer"; }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+105
@@ -0,0 +1,105 @@
|
|||||||
|
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.EDhApiRenderApi;
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see LodQuadBuilder
|
||||||
|
*/
|
||||||
|
public class BlazeDhVertexFormatUtil
|
||||||
|
{
|
||||||
|
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static final VertexFormatElement SCREEN_POS;
|
||||||
|
public static final VertexFormatElement RGBA_FLOAT_COLOR;
|
||||||
|
|
||||||
|
public static final VertexFormatElement SHORT_XYZ_POS;
|
||||||
|
public static final VertexFormatElement BYTE_PAD;
|
||||||
|
/** contains light and micro-offset */
|
||||||
|
public static final VertexFormatElement META;
|
||||||
|
public static final VertexFormatElement RGBA_UBYTE_COLOR;
|
||||||
|
public static final VertexFormatElement IRIS_MATERIAL;
|
||||||
|
public static final VertexFormatElement IRIS_NORMAL;
|
||||||
|
|
||||||
|
public static final VertexFormatElement FLOAT_XYZ_POS;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static
|
||||||
|
{
|
||||||
|
EDhApiRenderApi renderingApi = Config.Client.Advanced.Graphics.Experimental.renderingApi.get();
|
||||||
|
if (renderingApi == EDhApiRenderApi.AUTO)
|
||||||
|
{
|
||||||
|
IVersionConstants versionConstants = SingletonInjector.INSTANCE.get(IVersionConstants.class);
|
||||||
|
renderingApi = versionConstants.getDefaultRenderingApi();
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean register = (renderingApi == EDhApiRenderApi.BLAZE_3D);
|
||||||
|
if (register)
|
||||||
|
{
|
||||||
|
LOGGER.debug("Attempting to register ["+VertexFormatElement.class.getSimpleName()+"]...");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
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
|
||||||
|
{
|
||||||
|
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
|
||||||
+81
@@ -0,0 +1,81 @@
|
|||||||
|
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 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 = VertexFormat.builder()
|
||||||
|
.add("vPosition", BlazeDhVertexFormatUtil.SCREEN_POS)
|
||||||
|
.build();
|
||||||
|
return vertexFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+38
@@ -0,0 +1,38 @@
|
|||||||
|
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;
|
||||||
|
|
||||||
|
public class BlazeUniformUtil
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
// GpuBuffer.USAGE_UNIFORM = 128
|
||||||
|
int usage = GpuBuffer.USAGE_COPY_DST
|
||||||
|
| GpuBuffer.USAGE_VERTEX
|
||||||
|
| GpuBuffer.USAGE_UNIFORM;
|
||||||
|
vboGpuBuffer = GPU_DEVICE.createBuffer(() -> uniformName, usage, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return vboGpuBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+90
@@ -0,0 +1,90 @@
|
|||||||
|
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.wrapperInterfaces.render.objects.IVertexBufferWrapper;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
public class BlazeVertexBufferWrapper implements IVertexBufferWrapper
|
||||||
|
{
|
||||||
|
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
|
||||||
|
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
|
||||||
|
|
||||||
|
|
||||||
|
public final String name;
|
||||||
|
public String getName() { return this.name; }
|
||||||
|
|
||||||
|
public GpuBuffer vboGpuBuffer = null;
|
||||||
|
public int vertexCount = -1;
|
||||||
|
public int indexCount = -1;
|
||||||
|
public boolean uploaded = false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public BlazeVertexBufferWrapper(String name) { this.name = name; }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//========//
|
||||||
|
// upload //
|
||||||
|
//========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void upload(ByteBuffer buffer, int 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;
|
||||||
|
|
||||||
|
|
||||||
|
int usage = GpuBuffer.USAGE_COPY_DST
|
||||||
|
| GpuBuffer.USAGE_VERTEX;
|
||||||
|
int byteSize = (buffer.limit() - buffer.position());
|
||||||
|
this.vboGpuBuffer = GPU_DEVICE.createBuffer(this::getName, usage, byteSize);
|
||||||
|
|
||||||
|
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.vboGpuBuffer, /*offset*/0, byteSize);
|
||||||
|
COMMAND_ENCODER.writeToBuffer(bufferSlice, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// base overrides //
|
||||||
|
//================//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close()
|
||||||
|
{
|
||||||
|
if (this.vboGpuBuffer != null)
|
||||||
|
{
|
||||||
|
this.vboGpuBuffer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+72
@@ -0,0 +1,72 @@
|
|||||||
|
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
|
||||||
|
{
|
||||||
|
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 GpuTextureView textureView = null;
|
||||||
|
public GpuSampler textureSampler = null;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=======//
|
||||||
|
// 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
|
||||||
+167
@@ -0,0 +1,167 @@
|
|||||||
|
package com.seibel.distanthorizons.common.render.blaze.wrappers.texture;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_21_10
|
||||||
|
public class BlazeTextureWrapper {}
|
||||||
|
|
||||||
|
#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.mojang.blaze3d.textures.*;
|
||||||
|
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.util.ColorUtil;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||||
|
|
||||||
|
import java.util.OptionalDouble;
|
||||||
|
|
||||||
|
public class BlazeTextureWrapper
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
public final TextureFormat textureFormat;
|
||||||
|
|
||||||
|
public GpuTexture texture = null;
|
||||||
|
public GpuTextureView textureView = null;
|
||||||
|
public GpuSampler textureSampler = null;
|
||||||
|
|
||||||
|
private int width = -1;
|
||||||
|
private int height = -1;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//==============//
|
||||||
|
// constructors //
|
||||||
|
//==============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public static BlazeTextureWrapper createDepth(String name) { return new BlazeTextureWrapper(name, TextureFormat.DEPTH32); }
|
||||||
|
public static BlazeTextureWrapper createColor(String name) { return new BlazeTextureWrapper(name, TextureFormat.RGBA8); }
|
||||||
|
|
||||||
|
private BlazeTextureWrapper(String name, TextureFormat 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 */
|
||||||
|
public void tryCreateOrResize()
|
||||||
|
{
|
||||||
|
this.tryCreateTexture();
|
||||||
|
this.tryCreateSampler();
|
||||||
|
}
|
||||||
|
private void tryCreateTexture()
|
||||||
|
{
|
||||||
|
int viewWidth = MC_RENDER.getTargetFramebufferViewportWidth();
|
||||||
|
int viewHeight = MC_RENDER.getTargetFramebufferViewportHeight();
|
||||||
|
|
||||||
|
if (this.texture == null
|
||||||
|
|| this.width != viewWidth
|
||||||
|
|| this.height != viewHeight)
|
||||||
|
{
|
||||||
|
if (this.texture != null)
|
||||||
|
{
|
||||||
|
this.texture.close();
|
||||||
|
this.textureView.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.width = viewWidth;
|
||||||
|
this.height = viewHeight;
|
||||||
|
|
||||||
|
int usage = GpuBuffer.USAGE_HINT_CLIENT_STORAGE
|
||||||
|
| GpuBuffer.USAGE_COPY_DST
|
||||||
|
| GpuBuffer.USAGE_VERTEX
|
||||||
|
| GpuBuffer.USAGE_UNIFORM;
|
||||||
|
this.texture = GPU_DEVICE.createTexture(this.name,
|
||||||
|
usage,
|
||||||
|
this.textureFormat,
|
||||||
|
viewWidth, viewHeight,
|
||||||
|
/*depthOrLayers*/ 1, /*mipLevels*/ 1
|
||||||
|
);
|
||||||
|
this.textureView = GPU_DEVICE.createTextureView(this.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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//==========//
|
||||||
|
// clearing //
|
||||||
|
//==========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will throw an exception if not a color texture.
|
||||||
|
* @see ColorUtil#argbToInt
|
||||||
|
*/
|
||||||
|
public void clearColor(int clearArgbColor)
|
||||||
|
{
|
||||||
|
if (this.texture != null)
|
||||||
|
{
|
||||||
|
COMMAND_ENCODER.clearColorTexture(this.texture, clearArgbColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 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
|
||||||
+76
@@ -0,0 +1,76 @@
|
|||||||
|
package com.seibel.distanthorizons.common.render.blaze.wrappers.uniform;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_21_10
|
||||||
|
public class BlazeLodUniformBufferWrapper {}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.buffers.Std140Builder;
|
||||||
|
import com.mojang.blaze3d.buffers.Std140SizeCalculator;
|
||||||
|
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;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
public class BlazeLodUniformBufferWrapper extends BlazeUniformBufferWrapper implements ILodContainerUniformBufferWrapper
|
||||||
|
{
|
||||||
|
|
||||||
|
private boolean uploaded = false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public BlazeLodUniformBufferWrapper() { super(BlazeLodUniformBufferWrapper.class.getName()); }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//========//
|
||||||
|
// ??? //
|
||||||
|
//========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createUniformData(LodBufferContainer bufferContainer)
|
||||||
|
{
|
||||||
|
Vec3f modelOffset = new Vec3f(
|
||||||
|
(float) (bufferContainer.minCornerBlockPos.getX()),
|
||||||
|
(float) (bufferContainer.minCornerBlockPos.getY()),
|
||||||
|
(float) (bufferContainer.minCornerBlockPos.getZ()));
|
||||||
|
|
||||||
|
// upload data //
|
||||||
|
|
||||||
|
int uniformBufferSize = new Std140SizeCalculator()
|
||||||
|
.putVec3() // uModelOffset
|
||||||
|
.get();
|
||||||
|
|
||||||
|
ByteBuffer buffer = this.getOrCreateBuffer(uniformBufferSize);
|
||||||
|
Std140Builder.intoBuffer(buffer)
|
||||||
|
.putVec3(modelOffset.x, modelOffset.y, modelOffset.z) // uModelOffset
|
||||||
|
.get();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tryUpload()
|
||||||
|
{
|
||||||
|
if (this.uploaded)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.upload();
|
||||||
|
|
||||||
|
this.uploaded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+130
@@ -0,0 +1,130 @@
|
|||||||
|
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.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;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IUniformBufferWrapper;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
|
||||||
|
public class BlazeUniformBufferWrapper implements IUniformBufferWrapper
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
|
||||||
|
private int cpuBufferSize = 0;
|
||||||
|
private int gpuBufferSize = 0;
|
||||||
|
|
||||||
|
private ByteBuffer cpuBuffer = null;
|
||||||
|
public GpuBuffer gpuBuffer = null;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public BlazeUniformBufferWrapper(String name) { this.name = name; }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//========//
|
||||||
|
// render //
|
||||||
|
//========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
protected ByteBuffer getOrCreateBuffer(int size)
|
||||||
|
{
|
||||||
|
if (this.cpuBuffer == null
|
||||||
|
|| this.cpuBufferSize != size)
|
||||||
|
{
|
||||||
|
this.cpuBuffer = ByteBuffer.allocateDirect(size);
|
||||||
|
this.cpuBuffer.order(ByteOrder.nativeOrder());
|
||||||
|
|
||||||
|
this.cpuBufferSize = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.cpuBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void upload() throws IllegalStateException
|
||||||
|
{
|
||||||
|
if (this.cpuBuffer == null)
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("Upload called before buffer was created");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.gpuBuffer == null
|
||||||
|
|| this.gpuBufferSize != this.cpuBufferSize)
|
||||||
|
{
|
||||||
|
if (this.gpuBuffer != null)
|
||||||
|
{
|
||||||
|
this.gpuBuffer.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
int usage = GpuBuffer.USAGE_COPY_DST
|
||||||
|
| GpuBuffer.USAGE_VERTEX
|
||||||
|
| GpuBuffer.USAGE_UNIFORM;
|
||||||
|
this.gpuBuffer = GPU_DEVICE.createBuffer(this::getBufferName, usage, this.cpuBufferSize);
|
||||||
|
|
||||||
|
this.gpuBufferSize = this.cpuBufferSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int byteSize = (this.cpuBuffer.limit() - this.cpuBuffer.position());
|
||||||
|
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.gpuBuffer, /*offset*/0, byteSize);
|
||||||
|
if (!bufferSlice.buffer().isClosed())
|
||||||
|
{
|
||||||
|
COMMAND_ENCODER.writeToBuffer(bufferSlice, this.cpuBuffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOGGER.warn("Uploading to buffer ["+this.name+"] failed due to already being closed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private String getBufferName() { return this.name; }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// base overrides //
|
||||||
|
//================//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close()
|
||||||
|
{
|
||||||
|
if (this.gpuBuffer != null)
|
||||||
|
{
|
||||||
|
this.gpuBuffer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//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.GLElementBuffer;
|
||||||
|
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 GLElementBuffer 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 GLElementBuffer(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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+474
@@ -0,0 +1,474 @@
|
|||||||
|
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.buffer.GlQuadElementBuffer;
|
||||||
|
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.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.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.AbstractOptifineAccessor;
|
||||||
|
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 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 = GlDhTerrainShaderProgram.INSTANCE;
|
||||||
|
IDhApiShaderProgram lodShaderProgramOverride = OverrideInjector.INSTANCE.get(IDhApiShaderProgram.class);
|
||||||
|
if (lodShaderProgramOverride != null && this.shaderProgramForThisFrame.overrideThisFrame())
|
||||||
|
{
|
||||||
|
this.shaderProgramForThisFrame = lodShaderProgramOverride;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
this.setGLState(renderParams, firstPass);
|
||||||
|
|
||||||
|
GlDhTerrainShaderProgram.INSTANCE.quadIBO.bind();
|
||||||
|
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");
|
||||||
|
|
||||||
|
GlDhTerrainShaderProgram.INSTANCE.quadIBO = new GlQuadElementBuffer();
|
||||||
|
GlDhTerrainShaderProgram.INSTANCE.quadIBO.reserve(LodQuadBuilder.getMaxBufferByteSize());
|
||||||
|
|
||||||
|
|
||||||
|
// create or get the frame buffer
|
||||||
|
if (AbstractOptifineAccessor.optifinePresent())
|
||||||
|
{
|
||||||
|
// 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();
|
||||||
|
GlDhTerrainShaderProgram.INSTANCE.quadIBO.unbind();
|
||||||
|
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);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// needs to be fired after all the textures have been created/bound
|
||||||
|
boolean clearTextures = !ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeTextureClearEvent.class, renderParams);
|
||||||
|
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
|
||||||
|
//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
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+66
@@ -0,0 +1,66 @@
|
|||||||
|
package com.seibel.distanthorizons.common.render.openGl;
|
||||||
|
|
||||||
|
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.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"; }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//============//
|
||||||
|
// singletons //
|
||||||
|
//============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override public IDhMetaRenderer getMetaRenderer() { return GlDhMetaRenderer.INSTANCE; }
|
||||||
|
@Override public IDhTerrainRenderer getTerrainRenderer() { return GlDhTerrainShaderProgram.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 GlGenericObjectRenderer.INSTANCE; }
|
||||||
|
|
||||||
|
@Override public IVertexBufferWrapper createVboWrapper(String name) { return new GLVertexBuffer(); }
|
||||||
|
@Override public ILodContainerUniformBufferWrapper createLodContainerUniformWrapper() { return new GlDummyUniformData(); }
|
||||||
|
@Override public IDhGenericObjectVertexBufferContainer createGenericVboContainer() { return new GlGenericObjectVertexContainer(); }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+387
@@ -0,0 +1,387 @@
|
|||||||
|
/*
|
||||||
|
* 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.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.objects.math.DhApiVec3f;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.GLProxy;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.buffer.GLVertexBuffer;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.buffer.GlQuadElementBuffer;
|
||||||
|
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.GlVertexAttributePostGL43;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.vertexAttribute.GlVertexAttributePreGL43;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.vertexAttribute.GlVertexPointer;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.util.vertexFormat.GlLodVertexFormat;
|
||||||
|
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.dataObjects.render.bufferBuilding.LodBufferContainer;
|
||||||
|
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodQuadBuilder;
|
||||||
|
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
|
||||||
|
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.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.modAccessor.IIrisAccessor;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IVertexBufferWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhTerrainRenderer;
|
||||||
|
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
|
||||||
|
import org.lwjgl.opengl.GL32;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles rendering the normal LOD terrain.
|
||||||
|
* @see LodQuadBuilder
|
||||||
|
*/
|
||||||
|
public class GlDhTerrainShaderProgram extends GlShaderProgram implements IDhApiShaderProgram, IDhTerrainRenderer
|
||||||
|
{
|
||||||
|
public static final DhLogger LOGGER = new DhLoggerBuilder()
|
||||||
|
.fileLevelConfig(Config.Common.Logging.logRendererEventToFile)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
public static final GlDhTerrainShaderProgram INSTANCE = new GlDhTerrainShaderProgram();
|
||||||
|
|
||||||
|
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
|
||||||
|
private static final IIrisAccessor IRIS_ACCESSOR = ModAccessorInjector.INSTANCE.get(IIrisAccessor.class);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public GlQuadElementBuffer quadIBO = null;
|
||||||
|
public final GlAbstractVertexAttribute vao;
|
||||||
|
|
||||||
|
// uniforms //
|
||||||
|
//region
|
||||||
|
|
||||||
|
public int uCombinedMatrix = -1;
|
||||||
|
public int uModelOffset = -1;
|
||||||
|
public int uWorldYOffset = -1;
|
||||||
|
|
||||||
|
public int uMircoOffset = -1;
|
||||||
|
public int uEarthRadius = -1;
|
||||||
|
public int uLightMap = -1;
|
||||||
|
|
||||||
|
// fragment shader uniforms
|
||||||
|
public int uClipDistance = -1;
|
||||||
|
public int uDitherDhRendering = -1;
|
||||||
|
|
||||||
|
// Noise Uniforms
|
||||||
|
public int uNoiseEnabled = -1;
|
||||||
|
public int uNoiseSteps = -1;
|
||||||
|
public int uNoiseIntensity = -1;
|
||||||
|
public int uNoiseDropoff = -1;
|
||||||
|
|
||||||
|
// Debug Uniform
|
||||||
|
public int uIsWhiteWorld = -1;
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
private GlDhTerrainShaderProgram()
|
||||||
|
{
|
||||||
|
super(
|
||||||
|
"assets/distanthorizons/shaders/shared/gl/standard.vert",
|
||||||
|
"assets/distanthorizons/shaders/shared/gl/flat_shaded.frag",
|
||||||
|
new String[]{"vPosition", "color"}
|
||||||
|
);
|
||||||
|
|
||||||
|
this.uCombinedMatrix = this.getUniformLocation("uCombinedMatrix");
|
||||||
|
this.uModelOffset = this.getUniformLocation("uModelOffset");
|
||||||
|
this.uWorldYOffset = this.getUniformLocation("uWorldYOffset");
|
||||||
|
this.uDitherDhRendering = this.getUniformLocation("uDitherDhRendering");
|
||||||
|
this.uMircoOffset = this.getUniformLocation("uMircoOffset");
|
||||||
|
this.uEarthRadius = this.getUniformLocation("uEarthRadius");
|
||||||
|
|
||||||
|
this.uLightMap = this.getUniformLocation("uLightMap");
|
||||||
|
|
||||||
|
// Fog/Clip Uniforms
|
||||||
|
this.uClipDistance = this.getUniformLocation("uClipDistance");
|
||||||
|
|
||||||
|
// Noise Uniforms
|
||||||
|
this.uNoiseEnabled = this.getUniformLocation("uNoiseEnabled");
|
||||||
|
this.uNoiseSteps = this.getUniformLocation("uNoiseSteps");
|
||||||
|
this.uNoiseIntensity = this.getUniformLocation("uNoiseIntensity");
|
||||||
|
this.uNoiseDropoff = this.getUniformLocation("uNoiseDropoff");
|
||||||
|
|
||||||
|
// Debug Uniform
|
||||||
|
this.uIsWhiteWorld = this.getUniformLocation("uIsWhiteWorld");
|
||||||
|
|
||||||
|
|
||||||
|
if (GLProxy.getInstance().vertexAttributeBufferBindingSupported)
|
||||||
|
{
|
||||||
|
this.vao = new GlVertexAttributePostGL43(); // also binds AbstractVertexAttribute
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.vao = new GlVertexAttributePreGL43(); // also binds AbstractVertexAttribute
|
||||||
|
}
|
||||||
|
this.vao.bind();
|
||||||
|
|
||||||
|
// short: x, y, z, meta
|
||||||
|
// meta: byte skylight, byte blocklight, byte microOffset
|
||||||
|
this.vao.setVertexAttribute(0, 0, GlVertexPointer.addUnsignedShortsPointer(4, false, true));
|
||||||
|
// byte: r, g, b, a
|
||||||
|
this.vao.setVertexAttribute(0, 1, GlVertexPointer.addUnsignedBytesPointer(4, true, false));
|
||||||
|
// byte: iris material ID, normal index, 2 spacers
|
||||||
|
this.vao.setVertexAttribute(0, 2, GlVertexPointer.addUnsignedBytesPointer(4, true, true));
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int vertexByteCount = GlLodVertexFormat.DH_VERTEX_FORMAT.getByteSize();
|
||||||
|
this.vao.completeAndCheck(vertexByteCount);
|
||||||
|
}
|
||||||
|
catch (RuntimeException e)
|
||||||
|
{
|
||||||
|
System.out.println(GlLodVertexFormat.DH_VERTEX_FORMAT);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// API methods //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bind()
|
||||||
|
{
|
||||||
|
super.bind();
|
||||||
|
this.vao.bind();
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void unbind()
|
||||||
|
{
|
||||||
|
super.unbind();
|
||||||
|
this.vao.unbind();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void free()
|
||||||
|
{
|
||||||
|
this.vao.free();
|
||||||
|
super.free();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bindVertexBuffer(int vbo) { this.vao.bindBufferToAllBindingPoints(vbo); }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fillUniformData(DhApiRenderParam renderParameters)
|
||||||
|
{
|
||||||
|
Mat4f combinedMatrix = new Mat4f(renderParameters.dhProjectionMatrix);
|
||||||
|
combinedMatrix.multiply(renderParameters.dhModelViewMatrix);
|
||||||
|
|
||||||
|
super.bind();
|
||||||
|
|
||||||
|
// uniforms
|
||||||
|
this.setUniform(this.uCombinedMatrix, combinedMatrix);
|
||||||
|
this.setUniform(this.uMircoOffset, 0.01f); // 0.01 block offset
|
||||||
|
|
||||||
|
this.setUniform(this.uLightMap, LightMapWrapper.GL_BOUND_INDEX);
|
||||||
|
|
||||||
|
this.setUniform(this.uWorldYOffset, (float) renderParameters.worldYOffset);
|
||||||
|
|
||||||
|
this.setUniform(this.uDitherDhRendering, Config.Client.Advanced.Graphics.Quality.ditherDhFade.get());
|
||||||
|
|
||||||
|
float curveRatio = Config.Client.Advanced.Graphics.Experimental.earthCurveRatio.get();
|
||||||
|
if (curveRatio < -1.0f || curveRatio > 1.0f)
|
||||||
|
{
|
||||||
|
curveRatio = /*6371KM*/ 6371000.0f / curveRatio;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// disable curvature if the config value is between -1 and 1
|
||||||
|
curveRatio = 0.0f;
|
||||||
|
}
|
||||||
|
this.setUniform(this.uEarthRadius, curveRatio);
|
||||||
|
|
||||||
|
// Noise Uniforms
|
||||||
|
this.setUniform(this.uNoiseEnabled, Config.Client.Advanced.Graphics.NoiseTexture.enableNoiseTexture.get());
|
||||||
|
this.setUniform(this.uNoiseSteps, Config.Client.Advanced.Graphics.NoiseTexture.noiseSteps.get());
|
||||||
|
this.setUniform(this.uNoiseIntensity, Config.Client.Advanced.Graphics.NoiseTexture.noiseIntensity.get());
|
||||||
|
this.setUniform(this.uNoiseDropoff, Config.Client.Advanced.Graphics.NoiseTexture.noiseDropoff.get());
|
||||||
|
|
||||||
|
// Debug
|
||||||
|
this.setUniform(this.uIsWhiteWorld, Config.Client.Advanced.Debugging.enableWhiteWorld.get());
|
||||||
|
|
||||||
|
// Clip Uniform
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
this.setUniform(this.uClipDistance, dhNearClipDistance);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setModelOffsetPos(DhApiVec3f modelOffsetPos) { this.setUniform(this.uModelOffset, new Vec3f(modelOffsetPos)); }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getId() { return this.id; }
|
||||||
|
|
||||||
|
/** The base DH render program should always render */
|
||||||
|
@Override
|
||||||
|
public boolean overrideThisFrame() { return true; }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//===========//
|
||||||
|
// rendering //
|
||||||
|
//===========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(RenderParams renderEventParam, boolean opaquePass, SortedArraySet<LodBufferContainer> bufferContainers, IProfilerWrapper profiler)
|
||||||
|
{
|
||||||
|
//=======================//
|
||||||
|
// debug wireframe setup //
|
||||||
|
//=======================//
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!opaquePass)
|
||||||
|
{
|
||||||
|
GLMC.enableBlend();
|
||||||
|
GLMC.enableDepthTest();
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GLMC.disableBlend();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//===========//
|
||||||
|
// rendering //
|
||||||
|
//===========//
|
||||||
|
|
||||||
|
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeRenderPassEvent.class, renderEventParam);
|
||||||
|
|
||||||
|
if (IRIS_ACCESSOR != null)
|
||||||
|
{
|
||||||
|
// done to fix a bug with Iris where face culling isn't properly set or reverted in the MC state manager
|
||||||
|
// which causes Sodium to render some water chunks with their normals inverted
|
||||||
|
// https://github.com/IrisShaders/Iris/issues/2582
|
||||||
|
// https://github.com/IrisShaders/Iris/blob/1.21.9/common/src/main/java/net/irisshaders/iris/compat/dh/LodRendererEvents.java#L346
|
||||||
|
GLMC.enableFaceCulling();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (bufferContainers != null)
|
||||||
|
{
|
||||||
|
for (int lodIndex = 0; lodIndex < bufferContainers.size(); lodIndex++)
|
||||||
|
{
|
||||||
|
LodBufferContainer bufferContainer = bufferContainers.get(lodIndex);
|
||||||
|
|
||||||
|
// set uniforms and fire events
|
||||||
|
{
|
||||||
|
Vec3d camPos = renderEventParam.exactCameraPosition;
|
||||||
|
Vec3f modelPos = new Vec3f(
|
||||||
|
(float) (bufferContainer.minCornerBlockPos.getX() - camPos.x),
|
||||||
|
(float) (bufferContainer.minCornerBlockPos.getY() - camPos.y),
|
||||||
|
(float) (bufferContainer.minCornerBlockPos.getZ() - camPos.z));
|
||||||
|
|
||||||
|
GlDhMetaRenderer.INSTANCE.shaderProgramForThisFrame.bind();
|
||||||
|
GlDhMetaRenderer.INSTANCE.shaderProgramForThisFrame.setModelOffsetPos(modelPos);
|
||||||
|
|
||||||
|
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeBufferRenderEvent.class, new DhApiBeforeBufferRenderEvent.EventParam(renderEventParam, modelPos));
|
||||||
|
}
|
||||||
|
|
||||||
|
IVertexBufferWrapper[] vertexBuffers = (opaquePass ? bufferContainer.vbos : bufferContainer.vbosTransparent);
|
||||||
|
for (int vboIndex = 0; vboIndex < vertexBuffers.length; vboIndex++)
|
||||||
|
{
|
||||||
|
GLVertexBuffer vbo = (GLVertexBuffer) vertexBuffers[vboIndex];
|
||||||
|
if (vbo == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vbo.getVertexCount() == 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4 vertices per face, but 6 indices (IE 2 triangles) per face, aka need to multiply by 1.5
|
||||||
|
int indexCount = (int)(vbo.getVertexCount() * 1.5);
|
||||||
|
|
||||||
|
vbo.bind();
|
||||||
|
GlDhMetaRenderer.INSTANCE.shaderProgramForThisFrame.bindVertexBuffer(vbo.getId());
|
||||||
|
GL32.glDrawElements(
|
||||||
|
GL32.GL_TRIANGLES,
|
||||||
|
indexCount,
|
||||||
|
this.quadIBO.getType(), 0);
|
||||||
|
vbo.unbind();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=========================//
|
||||||
|
// debug wireframe cleanup //
|
||||||
|
//=========================//
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+738
@@ -0,0 +1,738 @@
|
|||||||
|
/*
|
||||||
|
* 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.GLElementBuffer;
|
||||||
|
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();
|
||||||
|
|
||||||
|
|
||||||
|
public static final GlGenericObjectRenderer INSTANCE = new GlGenericObjectRenderer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 GLElementBuffer 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
|
||||||
|
|
||||||
|
private 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);
|
||||||
|
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 GLElementBuffer(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;
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
// render setup //
|
||||||
|
profiler.push("setup");
|
||||||
|
|
||||||
|
this.init();
|
||||||
|
|
||||||
|
boolean useInstancedRendering = this.instancedRenderingAvailable
|
||||||
|
&& Config.Client.Advanced.Graphics.GenericRendering.enableInstancedRendering.get();
|
||||||
|
|
||||||
|
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericRenderSetupEvent.class, renderEventParam);
|
||||||
|
|
||||||
|
|
||||||
|
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 = useInstancedRendering ? 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
|
||||||
|
boolean cancelRendering = ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericObjectRenderEvent.class, new DhApiBeforeGenericObjectRenderEvent.EventParam(renderEventParam, boxGroup));
|
||||||
|
if (cancelRendering)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update instanced data if needed
|
||||||
|
if (useInstancedRendering)
|
||||||
|
{
|
||||||
|
boxGroup.tryUpdateInstancedDataAsync();
|
||||||
|
|
||||||
|
// skip groups that haven't been uploaded yet
|
||||||
|
if (boxGroup.vertexBufferContainer.getState() != GlGenericObjectVertexContainer.EState.RENDER)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// render //
|
||||||
|
|
||||||
|
profiler.popPush("rendering");
|
||||||
|
profiler.push(boxGroup.getResourceLocationNamespace());
|
||||||
|
profiler.push(boxGroup.getResourceLocationPath());
|
||||||
|
if (useInstancedRendering)
|
||||||
|
{
|
||||||
|
this.renderBoxGroupInstanced(shaderProgram, renderEventParam, boxGroup, camPos, profiler);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.renderBoxGroupDirect(shaderProgram, renderEventParam, boxGroup, camPos, profiler);
|
||||||
|
}
|
||||||
|
profiler.pop(); // resource path
|
||||||
|
profiler.pop(); // resource namespace
|
||||||
|
|
||||||
|
boxGroup.postRender(renderEventParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//==========//
|
||||||
|
// clean up //
|
||||||
|
//==========//
|
||||||
|
|
||||||
|
profiler.popPush("cleanup");
|
||||||
|
|
||||||
|
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericRenderCleanupEvent.class, renderEventParam);
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
profiler.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=====================//
|
||||||
|
// instanced rendering //
|
||||||
|
//=====================//
|
||||||
|
//region
|
||||||
|
|
||||||
|
private void renderBoxGroupInstanced(
|
||||||
|
IDhApiGenericObjectShaderProgram shaderProgram, DhApiRenderParam renderEventParam,
|
||||||
|
RenderableBoxGroup boxGroup, Vec3d camPos,
|
||||||
|
IProfilerWrapper profiler)
|
||||||
|
{
|
||||||
|
// update instance data //
|
||||||
|
|
||||||
|
profiler.push("vertex setup");
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
profiler.pop();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
profiler.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
//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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+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; }
|
||||||
|
|
||||||
|
}
|
||||||
+180
@@ -0,0 +1,180 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.state = GlGenericObjectVertexContainer.EState.READY_TO_UPLOAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
this.state = EState.RENDER;
|
||||||
|
}
|
||||||
|
/** 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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+347
@@ -0,0 +1,347 @@
|
|||||||
|
/*
|
||||||
|
* 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.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.util.objects.GLMessages.*;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||||
|
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
|
||||||
|
{
|
||||||
|
public static final DhLogger LOGGER = new DhLoggerBuilder()
|
||||||
|
.fileLevelConfig(Config.Common.Logging.logRendererGLEventToFile)
|
||||||
|
.chatLevelConfig(Config.Common.Logging.logRendererGLEventToChat)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
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
|
||||||
|
{
|
||||||
|
// this must be created on minecraft's render context to work correctly
|
||||||
|
if (GLFW.glfwGetCurrentContext() == 0L)
|
||||||
|
{
|
||||||
|
throw new IllegalStateException(GLProxy.class.getSimpleName() + " was created outside the render thread!");
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
{
|
||||||
|
EDhApiGpuUploadMethod uploadOverride = Config.Client.Advanced.Debugging.OpenGl.glUploadMode.get();
|
||||||
|
if (uploadOverride == EDhApiGpuUploadMethod.AUTO)
|
||||||
|
{
|
||||||
|
return this.preferredUploadMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
return uploadOverride;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 msg)
|
||||||
|
{
|
||||||
|
EDhApiGLErrorHandlingMode errorHandlingMode = Config.Client.Advanced.Debugging.OpenGl.glErrorHandlingMode.get();
|
||||||
|
if (errorHandlingMode == EDhApiGLErrorHandlingMode.IGNORE)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
boolean onlyLogOnce = Config.Client.Advanced.Debugging.OpenGl.onlyLogGlErrorsOnce.get();
|
||||||
|
String errorMessage = "GL ERROR [" + msg.id + "] from [" + msg.source + "]: [" + msg.message + "]"+(onlyLogOnce ? " this message will only be logged once" : "")+".";
|
||||||
|
if (onlyLogOnce
|
||||||
|
&& !LOGGED_GL_MESSAGES.add(errorMessage))
|
||||||
|
{
|
||||||
|
// this message has already been logged
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// create an exception so we get a stacktrace of where the message was triggered from
|
||||||
|
RuntimeException exception = new RuntimeException(errorMessage);
|
||||||
|
|
||||||
|
if (msg.type == EGLMessageType.ERROR || msg.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 = msg.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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+259
@@ -0,0 +1,259 @@
|
|||||||
|
/*
|
||||||
|
* 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);
|
||||||
|
this.frameBufferDepthTexture = GL32.glGetFramebufferAttachmentParameteri(GL32.GL_FRAMEBUFFER, GL32.GL_DEPTH_ATTACHMENT, GL32.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_TEXTURE_2D, this.frameBufferTexture0, 0);
|
||||||
|
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT1, GL32.GL_TEXTURE_2D, this.frameBufferTexture1, 0);
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
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 createUniformData(LodBufferContainer bufferContainer) { }
|
||||||
|
@Override public void tryUpload() { }
|
||||||
|
@Override public void upload() { }
|
||||||
|
@Override public void close() { }
|
||||||
|
|
||||||
|
}
|
||||||
+367
@@ -0,0 +1,367 @@
|
|||||||
|
/*
|
||||||
|
* 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.logging.DhLogger;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import com.seibel.distanthorizons.core.render.RenderThreadTaskHandler;
|
||||||
|
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||||
|
import com.seibel.distanthorizons.core.util.ThreadUtil;
|
||||||
|
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.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
|
||||||
|
public static final double BUFFER_EXPANSION_MULTIPLIER = 1.3;
|
||||||
|
public static final double BUFFER_SHRINK_TRIGGER = BUFFER_EXPANSION_MULTIPLIER * BUFFER_EXPANSION_MULTIPLIER;
|
||||||
|
/** 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 ReferenceQueue<GLBuffer> PHANTOM_REFERENCE_QUEUE = new ReferenceQueue<>();
|
||||||
|
private static final ThreadPoolExecutor CLEANUP_THREAD = ThreadUtil.makeSingleDaemonThreadPool("GLBuffer Cleanup");
|
||||||
|
|
||||||
|
|
||||||
|
protected int id;
|
||||||
|
public final int getId() { return this.id; }
|
||||||
|
protected int size = 0;
|
||||||
|
public int getSize() { return this.size; }
|
||||||
|
protected boolean bufferStorage;
|
||||||
|
public final boolean isBufferStorage() { return this.bufferStorage; }
|
||||||
|
protected boolean isMapped = false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//==============//
|
||||||
|
// constructors //
|
||||||
|
//==============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
static { CLEANUP_THREAD.execute(() -> runPhantomReferenceCleanupLoop()); }
|
||||||
|
|
||||||
|
public GLBuffer(boolean isBufferStorage) { this.create(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 create(boolean asBufferStorage)
|
||||||
|
{
|
||||||
|
if (!GLProxy.runningOnRenderThread())
|
||||||
|
{
|
||||||
|
LodUtil.assertNotReach("Thread ["+Thread.currentThread()+"] tried to create a GLBuffer outside the MC render thread.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// destroy the old buffer if one is present
|
||||||
|
// (as of 2024-12-31 James didn't see this happen, but just in case)
|
||||||
|
if (this.id != 0)
|
||||||
|
{
|
||||||
|
destroyBufferIdAsync(this.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.id = GLMC.glGenBuffers();
|
||||||
|
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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void destroyAsync()
|
||||||
|
{
|
||||||
|
if (this.id == 0)
|
||||||
|
{
|
||||||
|
// the buffer has already been closed
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
destroyBufferIdAsync(this.id);
|
||||||
|
|
||||||
|
this.id = 0;
|
||||||
|
this.size = 0;
|
||||||
|
}
|
||||||
|
private static void destroyBufferIdAsync(int id)
|
||||||
|
{
|
||||||
|
// remove and clear the phantom reference if present
|
||||||
|
if (BUFFER_ID_TO_PHANTOM.containsKey(id))
|
||||||
|
{
|
||||||
|
Reference<? extends GLBuffer> phantom = BUFFER_ID_TO_PHANTOM.get(id);
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
|
||||||
|
PHANTOM_TO_BUFFER_ID.remove(phantom);
|
||||||
|
BUFFER_ID_TO_PHANTOM.remove(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderThreadTaskHandler.INSTANCE.queueRunningOnRenderThread(() ->
|
||||||
|
{
|
||||||
|
// destroy the buffer if it exists,
|
||||||
|
// the buffer may not exist if the destroy method is called twice
|
||||||
|
if (GL32.glIsBuffer(id))
|
||||||
|
{
|
||||||
|
GLMC.glDeleteBuffers(id);
|
||||||
|
bufferCount.decrementAndGet();
|
||||||
|
|
||||||
|
if (Config.Client.Advanced.Debugging.logBufferGarbageCollection.get())
|
||||||
|
{
|
||||||
|
LOGGER.info("destroyed buffer [" + id + "], remaining: [" + BUFFER_ID_TO_PHANTOM.size() + "]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure the buffer is ready for uploading
|
||||||
|
this.createOrChangeBufferTypeForUpload(uploadMethod);
|
||||||
|
|
||||||
|
switch (uploadMethod)
|
||||||
|
{
|
||||||
|
//case NONE:
|
||||||
|
// return;
|
||||||
|
case AUTO:
|
||||||
|
LodUtil.assertNotReach("GpuUploadMethod AUTO must be resolved before call to uploadBuffer()!");
|
||||||
|
case BUFFER_STORAGE:
|
||||||
|
this.uploadBufferStorage(bb, bufferHint);
|
||||||
|
break;
|
||||||
|
case DATA:
|
||||||
|
this.uploadBufferData(bb, bufferHint);
|
||||||
|
break;
|
||||||
|
case SUB_DATA:
|
||||||
|
this.uploadSubData(bb, maxExpansionSize, bufferHint);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LodUtil.assertNotReach("Unknown GpuUploadMethod!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/** Requires the buffer to be bound */
|
||||||
|
protected void uploadBufferStorage(ByteBuffer bb, int bufferStorageHint)
|
||||||
|
{
|
||||||
|
LodUtil.assertTrue(this.bufferStorage, "Buffer is not bufferStorage but its trying to use bufferStorage upload method!");
|
||||||
|
|
||||||
|
int bbSize = bb.limit() - bb.position();
|
||||||
|
this.destroyAsync();
|
||||||
|
this.create(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();
|
||||||
|
GL32.glBufferData(this.getBufferBindingTarget(), bb, bufferDataHint);
|
||||||
|
this.size = bbSize;
|
||||||
|
}
|
||||||
|
/** 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();
|
||||||
|
if (this.size < bbSize || this.size > bbSize * BUFFER_SHRINK_TRIGGER)
|
||||||
|
{
|
||||||
|
int newSize = (int) (bbSize * BUFFER_EXPANSION_MULTIPLIER);
|
||||||
|
if (newSize > maxExpansionSize) newSize = maxExpansionSize;
|
||||||
|
GL32.glBufferData(this.getBufferBindingTarget(), newSize, bufferDataHint);
|
||||||
|
this.size = newSize;
|
||||||
|
}
|
||||||
|
GL32.glBufferSubData(this.getBufferBindingTarget(), 0, bb);
|
||||||
|
}
|
||||||
|
|
||||||
|
//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.destroyAsync();
|
||||||
|
this.create(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.create(this.bufferStorage);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.bind();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// static cleanup //
|
||||||
|
//================//
|
||||||
|
//region
|
||||||
|
|
||||||
|
private static void runPhantomReferenceCleanupLoop()
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.sleep(PHANTOM_REF_CHECK_TIME_IN_MS);
|
||||||
|
}
|
||||||
|
catch (InterruptedException ignore) { }
|
||||||
|
|
||||||
|
|
||||||
|
Reference<? extends GLBuffer> phantomRef = PHANTOM_REFERENCE_QUEUE.poll();
|
||||||
|
while (phantomRef != null)
|
||||||
|
{
|
||||||
|
// destroy the buffer if it hasn't been cleared yet
|
||||||
|
if (PHANTOM_TO_BUFFER_ID.containsKey(phantomRef))
|
||||||
|
{
|
||||||
|
int id = PHANTOM_TO_BUFFER_ID.get(phantomRef);
|
||||||
|
destroyBufferIdAsync(id);
|
||||||
|
//LOGGER.warn("Buffer Phantom collected, ID: ["+id+"]");
|
||||||
|
}
|
||||||
|
|
||||||
|
phantomRef = PHANTOM_REFERENCE_QUEUE.poll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
LOGGER.error("Unexpected error in buffer cleanup thread: [" + e.getMessage() + "].", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+60
@@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a container for a OpenGL
|
||||||
|
* VBO (Vertex Buffer Object).
|
||||||
|
*
|
||||||
|
* @author James Seibel
|
||||||
|
* @version 11-20-2021
|
||||||
|
*/
|
||||||
|
public class GLElementBuffer 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;
|
||||||
|
public int getIndicesCount() { return this.indicesCount; }
|
||||||
|
protected int type = GL32.GL_UNSIGNED_INT;
|
||||||
|
public int getType() { return type; }
|
||||||
|
|
||||||
|
public GLElementBuffer(boolean isBufferStorage)
|
||||||
|
{
|
||||||
|
super(isBufferStorage);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroyAsync()
|
||||||
|
{
|
||||||
|
super.destroyAsync();
|
||||||
|
this.indicesCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBufferBindingTarget()
|
||||||
|
{
|
||||||
|
return GL32.GL_ELEMENT_ARRAY_BUFFER;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+112
@@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* 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.LodQuadBuilder;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IVertexBufferWrapper;
|
||||||
|
import org.lwjgl.opengl.GL32;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 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; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
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 upload(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)
|
||||||
|
{
|
||||||
|
boolean useBuffStorage = uploadMethod.useBufferStorage;
|
||||||
|
super.uploadBuffer(byteBuffer, uploadMethod, maxExpansionSize, useBuffStorage ? 0 : GL32.GL_STATIC_DRAW);
|
||||||
|
}
|
||||||
|
this.vertexCount = vertexCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() { this.destroyAsync(); }
|
||||||
|
@Override
|
||||||
|
public void destroyAsync()
|
||||||
|
{
|
||||||
|
super.destroyAsync();
|
||||||
|
this.vertexCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+192
@@ -0,0 +1,192 @@
|
|||||||
|
/*
|
||||||
|
* 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.logging.DhLogger;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import org.lwjgl.opengl.GL32;
|
||||||
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
/** AKA Index Buffer TODO RENAME */
|
||||||
|
public class GlQuadElementBuffer extends GLElementBuffer
|
||||||
|
{
|
||||||
|
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public GlQuadElementBuffer() { super(false); }
|
||||||
|
|
||||||
|
public void reserve(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;
|
||||||
|
}
|
||||||
|
int vertexCount = quadCount * 4; // 4 vertices per quad
|
||||||
|
|
||||||
|
if (vertexCount < 255)
|
||||||
|
{
|
||||||
|
// Reserve 1 for the reset index
|
||||||
|
this.type = GL32.GL_UNSIGNED_BYTE;
|
||||||
|
}
|
||||||
|
else if (vertexCount < 65535)
|
||||||
|
{
|
||||||
|
// Reserve 1 for the reset index
|
||||||
|
this.type = GL32.GL_UNSIGNED_SHORT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.type = GL32.GL_UNSIGNED_INT;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteBuffer buffer = MemoryUtil.memAlloc(this.indicesCount * GLEnums.getTypeSize(this.type));
|
||||||
|
buildBuffer(quadCount, buffer, this.type);
|
||||||
|
this.bind();
|
||||||
|
super.uploadBuffer(buffer, EDhApiGpuUploadMethod.DATA,
|
||||||
|
this.indicesCount * GLEnums.getTypeSize(this.type), GL32.GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
MemoryUtil.memFree(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=========//
|
||||||
|
// getters //
|
||||||
|
//=========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public int getCapacity() { return super.getSize() / GLEnums.getTypeSize(this.getType()); }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//==========//
|
||||||
|
// building //
|
||||||
|
//==========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public static void buildBuffer(int quadCount, ByteBuffer buffer, int type)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case GL32.GL_UNSIGNED_BYTE:
|
||||||
|
buildBufferByte(quadCount, buffer);
|
||||||
|
break;
|
||||||
|
case GL32.GL_UNSIGNED_SHORT:
|
||||||
|
buildBufferShort(quadCount, buffer);
|
||||||
|
break;
|
||||||
|
case GL32.GL_UNSIGNED_INT:
|
||||||
|
buildBufferInt(quadCount, buffer);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("Unknown buffer type: [" + type + "].");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void buildBufferByte(int quadCount, ByteBuffer buffer)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < quadCount; i++)
|
||||||
|
{
|
||||||
|
int vIndex = i * 4;
|
||||||
|
// First triangle
|
||||||
|
buffer.put((byte) (vIndex));
|
||||||
|
buffer.put((byte) (vIndex + 1));
|
||||||
|
buffer.put((byte) (vIndex + 2));
|
||||||
|
// Second triangle
|
||||||
|
buffer.put((byte) (vIndex + 2));
|
||||||
|
buffer.put((byte) (vIndex + 3));
|
||||||
|
buffer.put((byte) (vIndex));
|
||||||
|
}
|
||||||
|
if (buffer.hasRemaining())
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("QuadElementBuffer is not full somehow after building");
|
||||||
|
}
|
||||||
|
buffer.rewind();
|
||||||
|
}
|
||||||
|
private static void buildBufferShort(int quadCount, ByteBuffer buffer)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < quadCount; i++)
|
||||||
|
{
|
||||||
|
int vIndex = i * 4;
|
||||||
|
// First triangle
|
||||||
|
buffer.putShort((short) (vIndex));
|
||||||
|
buffer.putShort((short) (vIndex + 1));
|
||||||
|
buffer.putShort((short) (vIndex + 2));
|
||||||
|
// Second triangle
|
||||||
|
buffer.putShort((short) (vIndex + 2));
|
||||||
|
buffer.putShort((short) (vIndex + 3));
|
||||||
|
buffer.putShort((short) (vIndex));
|
||||||
|
}
|
||||||
|
if (buffer.hasRemaining())
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("QuadElementBuffer is not full somehow after building");
|
||||||
|
}
|
||||||
|
buffer.rewind();
|
||||||
|
}
|
||||||
|
private static void buildBufferInt(int quadCount, ByteBuffer buffer)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < quadCount; i++)
|
||||||
|
{
|
||||||
|
int vIndex = i * 4;
|
||||||
|
// First triangle
|
||||||
|
buffer.putInt(vIndex);
|
||||||
|
buffer.putInt(vIndex + 1);
|
||||||
|
buffer.putInt(vIndex + 2);
|
||||||
|
// Second triangle
|
||||||
|
buffer.putInt(vIndex + 2);
|
||||||
|
buffer.putInt(vIndex + 3);
|
||||||
|
buffer.putInt(vIndex);
|
||||||
|
}
|
||||||
|
if (buffer.hasRemaining())
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("QuadElementBuffer is not full somehow after building");
|
||||||
|
}
|
||||||
|
buffer.rewind();
|
||||||
|
}
|
||||||
|
|
||||||
|
//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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+225
@@ -0,0 +1,225 @@
|
|||||||
|
/*
|
||||||
|
* 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.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, Mat4f) */
|
||||||
|
public void trySetUniform(int location, DhApiVec3i value) { if (location != -1) { this.setUniform(location, value); } }
|
||||||
|
|
||||||
|
/** Requires a bound ShaderProgram. */
|
||||||
|
public void setUniform(int location, Mat4f value)
|
||||||
|
{
|
||||||
|
try (MemoryStack stack = MemoryStack.stackPush())
|
||||||
|
{
|
||||||
|
FloatBuffer buffer = stack.mallocFloat(4 * 4);
|
||||||
|
value.store(buffer);
|
||||||
|
GL32.glUniformMatrix4fv(location, false, buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/** @see GlShaderProgram#setUniform(int, Mat4f) */
|
||||||
|
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);
|
||||||
|
|
||||||
|
}
|
||||||
+155
@@ -0,0 +1,155 @@
|
|||||||
|
/*
|
||||||
|
* 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.core.config.Config;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import org.lwjgl.opengl.GL43;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In OpenGL 4.3 and later, Vertex Attribute got a make-over.
|
||||||
|
* Now it provides support for buffer binding points natively.
|
||||||
|
* This means that setting up the VAO is just use ONE native call when
|
||||||
|
* binding to a buffer. <br><br>
|
||||||
|
*
|
||||||
|
* Since I no longer need to implement binding points, I also no
|
||||||
|
* longer needs to keep track of Pointers.
|
||||||
|
*/
|
||||||
|
public final class GlVertexAttributePostGL43 extends GlAbstractVertexAttribute
|
||||||
|
{
|
||||||
|
private static final DhLogger LOGGER = new DhLoggerBuilder()
|
||||||
|
.fileLevelConfig(Config.Common.Logging.logRendererGLEventToFile)
|
||||||
|
.chatLevelConfig(Config.Common.Logging.logRendererGLEventToChat)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
|
||||||
|
int numberOfBindingPoints = 0;
|
||||||
|
int strideSize = 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
|
||||||
|
/** This will bind the {@link GlAbstractVertexAttribute} */
|
||||||
|
public GlVertexAttributePostGL43()
|
||||||
|
{
|
||||||
|
super(); // also bind AbstractVertexAttribute
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=========//
|
||||||
|
// binding //
|
||||||
|
//=========//
|
||||||
|
|
||||||
|
/** Requires both AbstractVertexAttribute and VertexBuffer to be bound */
|
||||||
|
@Override
|
||||||
|
public void bindBufferToAllBindingPoints(int buffer)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < this.numberOfBindingPoints; i++)
|
||||||
|
{
|
||||||
|
GL43.glBindVertexBuffer(i, buffer, 0, this.strideSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Requires both AbstractVertexAttribute and VertexBuffer to be bound */
|
||||||
|
@Override
|
||||||
|
public void bindBufferToBindingPoint(int buffer, int bindingPoint)
|
||||||
|
{
|
||||||
|
GL43.glBindVertexBuffer(bindingPoint, buffer, 0, this.strideSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//===========//
|
||||||
|
// unbinding //
|
||||||
|
//===========//
|
||||||
|
|
||||||
|
/** Requires AbstractVertexAttribute to be bound */
|
||||||
|
@Override
|
||||||
|
public void unbindBuffersFromAllBindingPoint()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < this.numberOfBindingPoints; i++)
|
||||||
|
{
|
||||||
|
GL43.glBindVertexBuffer(i, 0, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Requires AbstractVertexAttribute to be bound */
|
||||||
|
@Override
|
||||||
|
public void unbindBuffersFromBindingPoint(int bindingPoint)
|
||||||
|
{
|
||||||
|
GL43.glBindVertexBuffer(bindingPoint, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//==========================//
|
||||||
|
// manual attribute setting //
|
||||||
|
//==========================//
|
||||||
|
|
||||||
|
/** Requires AbstractVertexAttribute to be bound */
|
||||||
|
@Override
|
||||||
|
public void setVertexAttribute(int bindingPoint, int attributeIndex, GlVertexPointer attribute)
|
||||||
|
{
|
||||||
|
if (attribute.useInteger)
|
||||||
|
{
|
||||||
|
GL43.glVertexAttribIFormat(attributeIndex, attribute.elementCount, attribute.glType, this.strideSize);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GL43.glVertexAttribFormat(attributeIndex, attribute.elementCount, attribute.glType,
|
||||||
|
attribute.normalized, this.strideSize); // Here strideSize is new attrib offset
|
||||||
|
}
|
||||||
|
|
||||||
|
this.strideSize += attribute.byteSize;
|
||||||
|
if (this.numberOfBindingPoints <= bindingPoint)
|
||||||
|
{
|
||||||
|
this.numberOfBindingPoints = bindingPoint + 1;
|
||||||
|
}
|
||||||
|
GL43.glVertexAttribBinding(attributeIndex, bindingPoint);
|
||||||
|
GL43.glEnableVertexAttribArray(attributeIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//============//
|
||||||
|
// validation //
|
||||||
|
//============//
|
||||||
|
|
||||||
|
/** Requires AbstractVertexAttribute to be bound */
|
||||||
|
@Override
|
||||||
|
public void completeAndCheck(int expectedStrideSize)
|
||||||
|
{
|
||||||
|
if (this.strideSize != expectedStrideSize)
|
||||||
|
{
|
||||||
|
LOGGER.error("Vertex Attribute calculated stride size " + this.strideSize +
|
||||||
|
" does not match the provided expected stride size " + expectedStrideSize + "!");
|
||||||
|
throw new IllegalArgumentException("Vertex Attribute Incorrect Format");
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGGER.info("Vertex Attribute (GL43+) completed. It contains " + this.numberOfBindingPoints
|
||||||
|
+ " binding points and a stride size of " + this.strideSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+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.openGl.glObject.vertexAttribute;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.core.config.Config;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import org.lwjgl.opengl.GL32;
|
||||||
|
|
||||||
|
|
||||||
|
public final class GlVertexAttributePreGL43 extends GlAbstractVertexAttribute
|
||||||
|
{
|
||||||
|
private static final DhLogger LOGGER = new DhLoggerBuilder()
|
||||||
|
.fileLevelConfig(Config.Common.Logging.logRendererGLEventToFile)
|
||||||
|
.chatLevelConfig(Config.Common.Logging.logRendererGLEventToChat)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
|
||||||
|
// I tried to use raw arrays as much as possible since those lookups
|
||||||
|
// happen every frame, and the speed directly affects fps
|
||||||
|
int strideSize = 0;
|
||||||
|
int[][] bindingPointsToIndex;
|
||||||
|
GlVertexPointer[] pointers;
|
||||||
|
int[] pointersOffset;
|
||||||
|
|
||||||
|
TreeMap<Integer, TreeSet<Integer>> bindingPointsToIndexBuilder;
|
||||||
|
ArrayList<GlVertexPointer> pointersBuilder;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
|
||||||
|
/** This will bind the {@link GlAbstractVertexAttribute} */
|
||||||
|
public GlVertexAttributePreGL43()
|
||||||
|
{
|
||||||
|
super(); // also bind AbstractVertexAttribute
|
||||||
|
this.bindingPointsToIndexBuilder = new TreeMap<>();
|
||||||
|
this.pointersBuilder = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=========//
|
||||||
|
// binding //
|
||||||
|
//=========//
|
||||||
|
|
||||||
|
/** Requires both AbstractVertexAttribute and VertexBuffer to be bound */
|
||||||
|
@Override
|
||||||
|
public void bindBufferToAllBindingPoints(int buffer)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < this.pointers.length; i++)
|
||||||
|
{
|
||||||
|
GL32.glEnableVertexAttribArray(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < this.pointers.length; i++)
|
||||||
|
{
|
||||||
|
GlVertexPointer pointer = this.pointers[i];
|
||||||
|
if (pointer == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pointer.useInteger)
|
||||||
|
{
|
||||||
|
GL32.glVertexAttribIPointer(i, pointer.elementCount, pointer.glType,
|
||||||
|
this.strideSize, this.pointersOffset[i]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GL32.glVertexAttribPointer(i, pointer.elementCount, pointer.glType,
|
||||||
|
pointer.normalized, this.strideSize, this.pointersOffset[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Requires both AbstractVertexAttribute and VertexBuffer to be bound */
|
||||||
|
@Override
|
||||||
|
public void bindBufferToBindingPoint(int buffer, int bindingPoint)
|
||||||
|
{
|
||||||
|
int[] bindingPointIndexes = this.bindingPointsToIndex[bindingPoint];
|
||||||
|
|
||||||
|
for (int bindingPointIndex : bindingPointIndexes)
|
||||||
|
{
|
||||||
|
GL32.glEnableVertexAttribArray(bindingPointIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int bindingPointIndex : bindingPointIndexes)
|
||||||
|
{
|
||||||
|
GlVertexPointer pointer = this.pointers[bindingPointIndex];
|
||||||
|
if (pointer == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pointer.useInteger)
|
||||||
|
{
|
||||||
|
GL32.glVertexAttribIPointer(bindingPointIndex, pointer.elementCount, pointer.glType,
|
||||||
|
this.strideSize, this.pointersOffset[bindingPointIndex]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GL32.glVertexAttribPointer(bindingPointIndex, pointer.elementCount, pointer.glType,
|
||||||
|
pointer.normalized, this.strideSize, this.pointersOffset[bindingPointIndex]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//===========//
|
||||||
|
// unbinding //
|
||||||
|
//===========//
|
||||||
|
|
||||||
|
/** Requires AbstractVertexAttribute to be bound */
|
||||||
|
@Override
|
||||||
|
public void unbindBuffersFromAllBindingPoint()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < this.pointers.length; i++)
|
||||||
|
{
|
||||||
|
GL32.glDisableVertexAttribArray(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Requires AbstractVertexAttribute to be bound */
|
||||||
|
@Override
|
||||||
|
public void unbindBuffersFromBindingPoint(int bindingPoint)
|
||||||
|
{
|
||||||
|
int[] bindingPointIndexes = this.bindingPointsToIndex[bindingPoint];
|
||||||
|
for (int bindingPointIndex : bindingPointIndexes)
|
||||||
|
{
|
||||||
|
GL32.glDisableVertexAttribArray(bindingPointIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//==========================//
|
||||||
|
// manual attribute setting //
|
||||||
|
//==========================//
|
||||||
|
|
||||||
|
/** Requires AbstractVertexAttribute to be bound */
|
||||||
|
@Override
|
||||||
|
public void setVertexAttribute(int bindingPoint, int attributeIndex, GlVertexPointer attribute)
|
||||||
|
{
|
||||||
|
TreeSet<Integer> intArray = this.bindingPointsToIndexBuilder.computeIfAbsent(bindingPoint, k -> new TreeSet<>());
|
||||||
|
intArray.add(attributeIndex);
|
||||||
|
|
||||||
|
while (this.pointersBuilder.size() <= attributeIndex)
|
||||||
|
{
|
||||||
|
// This is dumb, but ArrayList doesn't have a resize, And this code
|
||||||
|
// should only be run when it's building the Vertex Attribute anyway.
|
||||||
|
this.pointersBuilder.add(null);
|
||||||
|
}
|
||||||
|
this.pointersBuilder.set(attributeIndex, attribute);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//============//
|
||||||
|
// validation //
|
||||||
|
//============//
|
||||||
|
|
||||||
|
/** Requires AbstractVertexAttribute to be bound */
|
||||||
|
@Override
|
||||||
|
public void completeAndCheck(int expectedStrideSize)
|
||||||
|
{
|
||||||
|
int maxBindPointNumber = this.bindingPointsToIndexBuilder.lastKey();
|
||||||
|
this.bindingPointsToIndex = new int[maxBindPointNumber + 1][];
|
||||||
|
|
||||||
|
this.bindingPointsToIndexBuilder.forEach((Integer i, TreeSet<Integer> set) ->
|
||||||
|
{
|
||||||
|
this.bindingPointsToIndex[i] = new int[set.size()];
|
||||||
|
Iterator<Integer> iter = set.iterator();
|
||||||
|
for (int j = 0; j < set.size(); j++)
|
||||||
|
{
|
||||||
|
this.bindingPointsToIndex[i][j] = iter.next();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.pointers = this.pointersBuilder.toArray(new GlVertexPointer[this.pointersBuilder.size()]);
|
||||||
|
this.pointersOffset = new int[this.pointers.length];
|
||||||
|
this.pointersBuilder = null; // Release the builder
|
||||||
|
this.bindingPointsToIndexBuilder = null; // Release the builder
|
||||||
|
|
||||||
|
// Check if all pointers are valid
|
||||||
|
int currentOffset = 0;
|
||||||
|
for (int i = 0; i < this.pointers.length; i++)
|
||||||
|
{
|
||||||
|
GlVertexPointer pointer = this.pointers[i];
|
||||||
|
if (pointer == null)
|
||||||
|
{
|
||||||
|
LOGGER.warn("Vertex Attribute index " + i + " is not set! No index should be skipped normally!");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
this.pointersOffset[i] = currentOffset;
|
||||||
|
currentOffset += pointer.byteSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentOffset != expectedStrideSize)
|
||||||
|
{
|
||||||
|
LOGGER.error("Vertex Attribute calculated stride size " + currentOffset +
|
||||||
|
" does not match the provided expected stride size " + expectedStrideSize + "!");
|
||||||
|
throw new IllegalArgumentException("Vertex Attribute Incorrect Format");
|
||||||
|
}
|
||||||
|
this.strideSize = currentOffset;
|
||||||
|
LOGGER.info("Vertex Attribute (pre GL43) completed.");
|
||||||
|
|
||||||
|
// Debug logging
|
||||||
|
LOGGER.debug("AttributeIndex: ElementCount, glType, normalized, strideSize, offset");
|
||||||
|
|
||||||
|
for (int i = 0; i < this.pointers.length; i++)
|
||||||
|
{
|
||||||
|
GlVertexPointer pointer = this.pointers[i];
|
||||||
|
if (pointer == null)
|
||||||
|
{
|
||||||
|
LOGGER.debug(i + ": Null!!!!");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOGGER.debug(i + ": " + pointer.elementCount + ", " +
|
||||||
|
pointer.glType + ", " + pointer.normalized + ", " + this.strideSize + ", " + this.pointersOffset[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+72
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* 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.coreapi.util.MathUtil;
|
||||||
|
import org.lwjgl.opengl.GL32;
|
||||||
|
|
||||||
|
public final class GlVertexPointer
|
||||||
|
{
|
||||||
|
public final int elementCount;
|
||||||
|
public final int glType;
|
||||||
|
public final boolean normalized;
|
||||||
|
public final int byteSize;
|
||||||
|
public final boolean useInteger;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// basic constructors //
|
||||||
|
|
||||||
|
public GlVertexPointer(int elementCount, int glType, boolean normalized, int byteSize, boolean useInteger)
|
||||||
|
{
|
||||||
|
this.elementCount = elementCount;
|
||||||
|
this.glType = glType;
|
||||||
|
this.normalized = normalized;
|
||||||
|
this.byteSize = byteSize;
|
||||||
|
this.useInteger = useInteger;
|
||||||
|
}
|
||||||
|
public GlVertexPointer(int elementCount, int glType, boolean normalized, int byteSize)
|
||||||
|
{
|
||||||
|
this(elementCount, glType, normalized, byteSize, false);
|
||||||
|
}
|
||||||
|
private static int _align(int bytes) { return MathUtil.ceilDiv(bytes, 4) * 4; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// named constructors //
|
||||||
|
|
||||||
|
public static GlVertexPointer addFloatPointer(boolean normalized) { return new GlVertexPointer(1, GL32.GL_FLOAT, normalized, Float.BYTES); }
|
||||||
|
public static GlVertexPointer addVec2Pointer(boolean normalized) { return new GlVertexPointer(2, GL32.GL_FLOAT, normalized, Float.BYTES * 2); }
|
||||||
|
public static GlVertexPointer addVec3Pointer(boolean normalized) { return new GlVertexPointer(3, GL32.GL_FLOAT, normalized, Float.BYTES * 3); }
|
||||||
|
public static GlVertexPointer addVec4Pointer(boolean normalized) { return new GlVertexPointer(4, GL32.GL_FLOAT, normalized, Float.BYTES * 4); }
|
||||||
|
/** Always aligned to 4 bytes */
|
||||||
|
public static GlVertexPointer addUnsignedBytePointer(boolean normalized, boolean useInteger) { return new GlVertexPointer(1, GL32.GL_UNSIGNED_BYTE, normalized, 4, useInteger); }
|
||||||
|
/** aligned to 4 bytes */
|
||||||
|
public static GlVertexPointer addUnsignedBytesPointer(int elementCount, boolean normalized, boolean useInteger)
|
||||||
|
{ return new GlVertexPointer(elementCount, GL32.GL_UNSIGNED_BYTE, normalized, _align(elementCount), useInteger); }
|
||||||
|
public static GlVertexPointer addUnsignedShortsPointer(int elementCount, boolean normalized, boolean useInteger)
|
||||||
|
{ return new GlVertexPointer(elementCount, GL32.GL_UNSIGNED_SHORT, normalized, _align(elementCount * 2), useInteger); }
|
||||||
|
public static GlVertexPointer addShortsPointer(int elementCount, boolean normalized, boolean useInteger) { return new GlVertexPointer(elementCount, GL32.GL_SHORT, normalized, _align(elementCount * 2), useInteger); }
|
||||||
|
public static GlVertexPointer addIntPointer(boolean normalized, boolean useInteger) { return new GlVertexPointer(1, GL32.GL_INT, normalized, 4, useInteger); }
|
||||||
|
public static GlVertexPointer addIVec2Pointer(boolean normalized, boolean useInteger) { return new GlVertexPointer(2, GL32.GL_INT, normalized, 8, useInteger); }
|
||||||
|
public static GlVertexPointer addIVec3Pointer(boolean normalized, boolean useInteger) { return new GlVertexPointer(3, GL32.GL_INT, normalized, 12, useInteger); }
|
||||||
|
public static GlVertexPointer addIVec4Pointer(boolean normalized, boolean useInteger) { return new GlVertexPointer(4, GL32.GL_INT, normalized, 16, useInteger); }
|
||||||
|
|
||||||
|
}
|
||||||
+116
@@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
* 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.postProcessing;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.buffer.GLVertexBuffer;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.vertexAttribute.GlAbstractVertexAttribute;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.vertexAttribute.GlVertexPointer;
|
||||||
|
import org.lwjgl.opengl.GL32;
|
||||||
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders a full-screen textured quad to the screen.
|
||||||
|
* Used in composite / deferred rendering (IE fog).
|
||||||
|
*/
|
||||||
|
public class GlScreenQuad
|
||||||
|
{
|
||||||
|
public static GlScreenQuad INSTANCE = new GlScreenQuad();
|
||||||
|
|
||||||
|
private static final float[] BOX_VERTICES = {
|
||||||
|
-1, -1,
|
||||||
|
1, -1,
|
||||||
|
1, 1,
|
||||||
|
|
||||||
|
-1, -1,
|
||||||
|
1, 1,
|
||||||
|
-1, 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
private GLVertexBuffer boxBuffer;
|
||||||
|
private GlAbstractVertexAttribute va;
|
||||||
|
private boolean init = false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
private GlScreenQuad() { }
|
||||||
|
|
||||||
|
public void init()
|
||||||
|
{
|
||||||
|
if (this.init) return;
|
||||||
|
this.init = true;
|
||||||
|
|
||||||
|
this.va = GlAbstractVertexAttribute.create();
|
||||||
|
this.va.bind();
|
||||||
|
|
||||||
|
// Pos
|
||||||
|
this.va.setVertexAttribute(0, 0, GlVertexPointer.addVec2Pointer(false));
|
||||||
|
this.va.completeAndCheck(Float.BYTES * 2);
|
||||||
|
|
||||||
|
// Framebuffer
|
||||||
|
this.createBuffer();
|
||||||
|
}
|
||||||
|
private void createBuffer()
|
||||||
|
{
|
||||||
|
ByteBuffer buffer = MemoryUtil.memAlloc(BOX_VERTICES.length * Float.BYTES);
|
||||||
|
buffer.asFloatBuffer().put(BOX_VERTICES);
|
||||||
|
buffer.rewind();
|
||||||
|
|
||||||
|
this.boxBuffer = new GLVertexBuffer(false);
|
||||||
|
this.boxBuffer.bind();
|
||||||
|
this.boxBuffer.uploadBuffer(buffer, BOX_VERTICES.length, EDhApiGpuUploadMethod.DATA, BOX_VERTICES.length * Float.BYTES);
|
||||||
|
MemoryUtil.memFree(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//===========//
|
||||||
|
// rendering //
|
||||||
|
//===========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public void render()
|
||||||
|
{
|
||||||
|
this.init();
|
||||||
|
|
||||||
|
this.boxBuffer.bind();
|
||||||
|
|
||||||
|
this.va.bind();
|
||||||
|
this.va.bindBufferToAllBindingPoints(this.boxBuffer.getId());
|
||||||
|
|
||||||
|
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_FILL);
|
||||||
|
|
||||||
|
GL32.glDrawArrays(GL32.GL_TRIANGLES, 0, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+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.openGl.postProcessing.apply;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.GlDhMetaRenderer;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.GLState;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.shader.GlShaderProgram;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.postProcessing.GlScreenQuad;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.util.GlAbstractShaderRenderer;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
import org.lwjgl.opengl.GL32;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies {@link com.seibel.distanthorizons.core.render.renderer.LodRenderer}'s currently active color and depth texture to Minecraft's framebuffer.
|
||||||
|
*/
|
||||||
|
public class GlDhApplyShader extends GlAbstractShaderRenderer
|
||||||
|
{
|
||||||
|
public static GlDhApplyShader INSTANCE = new GlDhApplyShader();
|
||||||
|
|
||||||
|
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
|
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
|
||||||
|
|
||||||
|
|
||||||
|
// uniforms
|
||||||
|
public int gDhColorTextureUniform;
|
||||||
|
public int gDepthMapUniform;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=======//
|
||||||
|
// setup //
|
||||||
|
//=======//
|
||||||
|
//region
|
||||||
|
|
||||||
|
private GlDhApplyShader() { }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInit()
|
||||||
|
{
|
||||||
|
this.shader = new GlShaderProgram(
|
||||||
|
"assets/distanthorizons/shaders/shared/gl/quadApply.vert",
|
||||||
|
"assets/distanthorizons/shaders/shared/gl/apply.frag",
|
||||||
|
"vPosition"
|
||||||
|
);
|
||||||
|
|
||||||
|
// uniform setup
|
||||||
|
this.gDhColorTextureUniform = this.shader.getUniformLocation("gDhColorTexture");
|
||||||
|
this.gDepthMapUniform = this.shader.getUniformLocation("gDhDepthTexture");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//========//
|
||||||
|
// render //
|
||||||
|
//========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onRender()
|
||||||
|
{
|
||||||
|
if (MC_RENDER.mcRendersToFrameBuffer())
|
||||||
|
{
|
||||||
|
this.renderToFrameBuffer();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.renderToMcTexture();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void renderToFrameBuffer()
|
||||||
|
{
|
||||||
|
int targetFrameBuffer = MC_RENDER.getTargetFramebuffer();
|
||||||
|
if (targetFrameBuffer == -1)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
try (GLState state = new GLState())
|
||||||
|
{
|
||||||
|
|
||||||
|
GLMC.disableDepthTest();
|
||||||
|
|
||||||
|
// blending isn't needed, we're manually merging the MC and DH textures
|
||||||
|
// Note: this prevents the sun/moon and stars from rendering through transparent LODs,
|
||||||
|
// however this also fixes transparent LODs from glowing when rendered against the sky during the day
|
||||||
|
GLMC.disableBlend();
|
||||||
|
|
||||||
|
// old blending logic in case it's ever needed:
|
||||||
|
//GLMC.enableBlend();
|
||||||
|
//GL32.glBlendEquation(GL32.GL_FUNC_ADD);
|
||||||
|
//GLMC.glBlendFunc(GL32.GL_ONE, GL32.GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
|
GLMC.glActiveTexture(GL32.GL_TEXTURE0);
|
||||||
|
GLMC.glBindTexture(GlDhMetaRenderer.INSTANCE.getActiveColorTextureId());
|
||||||
|
GL32.glUniform1i(this.gDhColorTextureUniform, 0);
|
||||||
|
|
||||||
|
GLMC.glActiveTexture(GL32.GL_TEXTURE1);
|
||||||
|
GLMC.glBindTexture(GlDhMetaRenderer.INSTANCE.getActiveDepthTextureId());
|
||||||
|
GL32.glUniform1i(this.gDepthMapUniform, 1);
|
||||||
|
|
||||||
|
// Copy to MC's framebuffer
|
||||||
|
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, targetFrameBuffer);
|
||||||
|
|
||||||
|
GlScreenQuad.INSTANCE.render();
|
||||||
|
}
|
||||||
|
// everything's been restored, except at this point the MC framebuffer should now be used instead
|
||||||
|
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, targetFrameBuffer);
|
||||||
|
|
||||||
|
}
|
||||||
|
private void renderToMcTexture()
|
||||||
|
{
|
||||||
|
int targetColorTextureId = MC_RENDER.getColorTextureId();
|
||||||
|
if (targetColorTextureId == -1)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dhFrameBufferId = GlDhMetaRenderer.INSTANCE.getActiveFramebufferId();
|
||||||
|
if (dhFrameBufferId == -1)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mcFrameBufferId = MC_RENDER.getTargetFramebuffer();
|
||||||
|
if (mcFrameBufferId == -1)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
try (GLState state = new GLState())
|
||||||
|
{
|
||||||
|
GLMC.disableDepthTest();
|
||||||
|
|
||||||
|
// blending isn't needed, we're just directly merging the MC and DH textures
|
||||||
|
// Note: this prevents the sun/moon and stars from rendering through transparent LODs,
|
||||||
|
// but it also resolves some other issues, so it's likely not an issue
|
||||||
|
GLMC.disableBlend();
|
||||||
|
|
||||||
|
GLMC.glActiveTexture(GL32.GL_TEXTURE0);
|
||||||
|
GLMC.glBindTexture(GlDhMetaRenderer.INSTANCE.getActiveColorTextureId());
|
||||||
|
GL32.glUniform1i(this.gDhColorTextureUniform, 0);
|
||||||
|
|
||||||
|
GLMC.glActiveTexture(GL32.GL_TEXTURE1);
|
||||||
|
GLMC.glBindTexture(GlDhMetaRenderer.INSTANCE.getActiveDepthTextureId());
|
||||||
|
GL32.glUniform1i(this.gDepthMapUniform, 1);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
GL32.glFramebufferTexture(GL32.GL_DRAW_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, targetColorTextureId, 0);
|
||||||
|
|
||||||
|
// Copy to MC's texture via MC's framebuffer
|
||||||
|
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, dhFrameBufferId);
|
||||||
|
|
||||||
|
GlScreenQuad.INSTANCE.render();
|
||||||
|
}
|
||||||
|
// everything's been restored, except at this point the MC framebuffer should now be used instead
|
||||||
|
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, mcFrameBufferId);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+116
@@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
* 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.postProcessing.fade;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.shader.GlShaderProgram;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.postProcessing.GlScreenQuad;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.util.GlAbstractShaderRenderer;
|
||||||
|
import com.seibel.distanthorizons.core.render.RenderParams;
|
||||||
|
import org.lwjgl.opengl.GL32;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws the Fade texture onto Minecraft's FrameBuffer. <br><br>
|
||||||
|
*
|
||||||
|
* See Also: <br>
|
||||||
|
* {@link GlVanillaFadeRenderer} - Parent to this shader. <br>
|
||||||
|
* {@link GlDhVanillaFadeShader} - draws the Fade texture. <br>
|
||||||
|
*/
|
||||||
|
public class GlDhFarFadeApplyShader extends GlAbstractShaderRenderer
|
||||||
|
{
|
||||||
|
public static GlDhFarFadeApplyShader INSTANCE = new GlDhFarFadeApplyShader();
|
||||||
|
|
||||||
|
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public int fadeTexture;
|
||||||
|
|
||||||
|
public int readFramebuffer;
|
||||||
|
public int drawFramebuffer;
|
||||||
|
|
||||||
|
// uniforms
|
||||||
|
public int uFadeColorTextureUniform = -1;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInit()
|
||||||
|
{
|
||||||
|
this.shader = new GlShaderProgram(
|
||||||
|
"assets/distanthorizons/shaders/shared/gl/quadApply.vert",
|
||||||
|
"assets/distanthorizons/shaders/fade/gl/apply.frag",
|
||||||
|
"vPosition"
|
||||||
|
);
|
||||||
|
|
||||||
|
// uniform setup
|
||||||
|
this.uFadeColorTextureUniform = this.shader.getUniformLocation("uFadeColorTextureUniform");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// render prep //
|
||||||
|
//=============//
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onApplyUniforms(RenderParams renderParams)
|
||||||
|
{
|
||||||
|
GLMC.glActiveTexture(GL32.GL_TEXTURE0);
|
||||||
|
GLMC.glBindTexture(this.fadeTexture);
|
||||||
|
GL32.glUniform1i(this.uFadeColorTextureUniform, 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//========//
|
||||||
|
// render //
|
||||||
|
//========//
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onRender()
|
||||||
|
{
|
||||||
|
GLMC.disableBlend();
|
||||||
|
|
||||||
|
// Depth testing must be disabled otherwise this application shader won't apply anything.
|
||||||
|
// setting this isn't necessary in vanilla, but some mods may change this, requiring it to be set manually,
|
||||||
|
// it should be automatically restored after rendering is complete.
|
||||||
|
GLMC.disableDepthTest();
|
||||||
|
|
||||||
|
|
||||||
|
// apply the rendered Fade to Minecraft's framebuffer
|
||||||
|
GLMC.glBindFramebuffer(GL32.GL_READ_FRAMEBUFFER, this.readFramebuffer);
|
||||||
|
GLMC.glBindFramebuffer(GL32.GL_DRAW_FRAMEBUFFER, this.drawFramebuffer);
|
||||||
|
|
||||||
|
GlScreenQuad.INSTANCE.render();
|
||||||
|
|
||||||
|
GLMC.enableDepthTest();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+165
@@ -0,0 +1,165 @@
|
|||||||
|
/*
|
||||||
|
* 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.postProcessing.fade;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.GlDhMetaRenderer;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
|
||||||
|
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.RenderParams;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhFarFadeRenderer;
|
||||||
|
import org.lwjgl.opengl.GL32;
|
||||||
|
import org.lwjgl.opengl.GL43C;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles fading MC and DH together via {@link GlDhFarFadeShader} and {@link GlDhFarFadeApplyShader}. <br><br>
|
||||||
|
*
|
||||||
|
* {@link GlDhFarFadeShader} - draws the Fade to a texture. <br>
|
||||||
|
* {@link GlDhFarFadeApplyShader} - draws the Fade texture to DH's framebuffer. <br>
|
||||||
|
*/
|
||||||
|
public class GlDhFarFadeRenderer implements IDhFarFadeRenderer
|
||||||
|
{
|
||||||
|
|
||||||
|
public static GlDhFarFadeRenderer INSTANCE = new GlDhFarFadeRenderer();
|
||||||
|
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 boolean init = false;
|
||||||
|
|
||||||
|
private int width = -1;
|
||||||
|
private int height = -1;
|
||||||
|
private int fadeFramebuffer = -1;
|
||||||
|
|
||||||
|
private int fadeTexture = -1;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
private GlDhFarFadeRenderer() { }
|
||||||
|
|
||||||
|
public void init()
|
||||||
|
{
|
||||||
|
if (this.init) return;
|
||||||
|
this.init = true;
|
||||||
|
|
||||||
|
GlDhFarFadeShader.INSTANCE.init();
|
||||||
|
GlDhFarFadeApplyShader.INSTANCE.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createFramebuffer(int width, int height)
|
||||||
|
{
|
||||||
|
if (this.fadeFramebuffer != -1)
|
||||||
|
{
|
||||||
|
GL32.glDeleteFramebuffers(this.fadeFramebuffer);
|
||||||
|
this.fadeFramebuffer = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.fadeFramebuffer = GL32.glGenFramebuffers();
|
||||||
|
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, this.fadeFramebuffer);
|
||||||
|
|
||||||
|
|
||||||
|
if (this.fadeTexture != -1)
|
||||||
|
{
|
||||||
|
GLMC.glDeleteTextures(this.fadeTexture);
|
||||||
|
this.fadeTexture = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.fadeTexture = GL32.glGenTextures();
|
||||||
|
{
|
||||||
|
GLMC.glBindTexture(this.fadeTexture);
|
||||||
|
GL32.glTexImage2D(GL32.GL_TEXTURE_2D, 0, GL32.GL_RGBA16, width, height, 0, GL32.GL_RGBA, GL32.GL_UNSIGNED_SHORT_4_4_4_4, (ByteBuffer) null);
|
||||||
|
GL32.glTexParameteri(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_MIN_FILTER, GL32.GL_LINEAR);
|
||||||
|
GL32.glTexParameteri(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_MAG_FILTER, GL32.GL_LINEAR);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_TEXTURE_2D, this.fadeTexture, 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//========//
|
||||||
|
// render //
|
||||||
|
//========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(RenderParams renderParams)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//profiler.push("Fade Generate");
|
||||||
|
|
||||||
|
this.init();
|
||||||
|
|
||||||
|
// resize the framebuffer if necessary
|
||||||
|
int width = MC_RENDER.getTargetFramebufferViewportWidth();
|
||||||
|
int height = MC_RENDER.getTargetFramebufferViewportHeight();
|
||||||
|
if (this.width != width || this.height != height)
|
||||||
|
{
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
this.createFramebuffer(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GlDhFarFadeShader.INSTANCE.frameBuffer = this.fadeFramebuffer;
|
||||||
|
GlDhFarFadeShader.INSTANCE.setProjectionMatrix(renderParams.mcModelViewMatrix, renderParams.mcProjectionMatrix);
|
||||||
|
GlDhFarFadeShader.INSTANCE.render(renderParams);
|
||||||
|
|
||||||
|
//profiler.popPush("Fade Apply");
|
||||||
|
|
||||||
|
GlDhFarFadeApplyShader.INSTANCE.fadeTexture = this.fadeTexture;
|
||||||
|
GlDhFarFadeApplyShader.INSTANCE.readFramebuffer = GlDhFarFadeShader.INSTANCE.frameBuffer;
|
||||||
|
GlDhFarFadeApplyShader.INSTANCE.drawFramebuffer = GlDhMetaRenderer.INSTANCE.getActiveFramebufferId();
|
||||||
|
GlDhFarFadeApplyShader.INSTANCE.render(renderParams);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
LOGGER.error("Unexpected error during fade render, error: ["+e.getMessage()+"].", e);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
//profiler.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//emdregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+167
@@ -0,0 +1,167 @@
|
|||||||
|
/*
|
||||||
|
* 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.postProcessing.fade;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.api.objects.math.DhApiMat4f;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.GlDhMetaRenderer;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.shader.GlShaderProgram;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.postProcessing.GlScreenQuad;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.util.GlAbstractShaderRenderer;
|
||||||
|
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 org.lwjgl.opengl.GL32;
|
||||||
|
|
||||||
|
public class GlDhFarFadeShader extends GlAbstractShaderRenderer
|
||||||
|
{
|
||||||
|
public static GlDhFarFadeShader INSTANCE = new GlDhFarFadeShader();
|
||||||
|
|
||||||
|
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
|
||||||
|
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
|
||||||
|
|
||||||
|
|
||||||
|
public int frameBuffer = -1;
|
||||||
|
|
||||||
|
private Mat4f inverseDhMvmProjMatrix;
|
||||||
|
|
||||||
|
|
||||||
|
// Uniforms
|
||||||
|
|
||||||
|
/** Inverted Model View Projection matrix */
|
||||||
|
public int uDhInvMvmProj = -1;
|
||||||
|
|
||||||
|
public int uDhDepthTexture = -1;
|
||||||
|
public int uMcColorTexture = -1;
|
||||||
|
public int uDhColorTexture = -1;
|
||||||
|
|
||||||
|
public int uStartFadeBlockDistance = -1;
|
||||||
|
public int uEndFadeBlockDistance = -1;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
|
||||||
|
public GlDhFarFadeShader() { }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInit()
|
||||||
|
{
|
||||||
|
this.shader = new GlShaderProgram(
|
||||||
|
"assets/distanthorizons/shaders/shared/gl/quadApply.vert",
|
||||||
|
"assets/distanthorizons/shaders/fade/gl/dhFade.frag",
|
||||||
|
"vPosition"
|
||||||
|
);
|
||||||
|
|
||||||
|
// all uniforms should be tryGet...
|
||||||
|
// because disabling fade can cause the GLSL to optimize out most (if not all) uniforms
|
||||||
|
|
||||||
|
// near fade
|
||||||
|
this.uDhInvMvmProj = this.shader.tryGetUniformLocation("uDhInvMvmProj");
|
||||||
|
|
||||||
|
this.uDhDepthTexture = this.shader.tryGetUniformLocation("uDhDepthTexture");
|
||||||
|
this.uMcColorTexture = this.shader.tryGetUniformLocation("uMcColorTexture");
|
||||||
|
this.uDhColorTexture = this.shader.tryGetUniformLocation("uDhColorTexture");
|
||||||
|
|
||||||
|
this.uStartFadeBlockDistance = this.shader.tryGetUniformLocation("uStartFadeBlockDistance");
|
||||||
|
this.uEndFadeBlockDistance = this.shader.tryGetUniformLocation("uEndFadeBlockDistance");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// render prep //
|
||||||
|
//=============//
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onApplyUniforms(RenderParams renderParams)
|
||||||
|
{
|
||||||
|
this.shader.setUniform(this.uDhInvMvmProj, this.inverseDhMvmProjMatrix);
|
||||||
|
|
||||||
|
|
||||||
|
float dhFarClipDistance = RenderUtil.getFarClipPlaneDistanceInBlocks();
|
||||||
|
float fadeStartDistance = dhFarClipDistance * 0.5f;
|
||||||
|
float fadeEndDistance = dhFarClipDistance * 0.9f;
|
||||||
|
|
||||||
|
this.shader.setUniform(this.uStartFadeBlockDistance, fadeStartDistance);
|
||||||
|
this.shader.setUniform(this.uEndFadeBlockDistance, fadeEndDistance);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProjectionMatrix(DhApiMat4f mcModelViewMatrix, DhApiMat4f mcProjectionMatrix)
|
||||||
|
{
|
||||||
|
Mat4f dhProjectionMatrix = RenderUtil.createLodProjectionMatrix(mcProjectionMatrix);
|
||||||
|
Mat4f dhModelViewMatrix = RenderUtil.createLodModelViewMatrix(mcModelViewMatrix);
|
||||||
|
|
||||||
|
Mat4f inverseDhModelViewProjectionMatrix = new Mat4f(dhProjectionMatrix);
|
||||||
|
inverseDhModelViewProjectionMatrix.multiply(dhModelViewMatrix);
|
||||||
|
inverseDhModelViewProjectionMatrix.invert();
|
||||||
|
this.inverseDhMvmProjMatrix = inverseDhModelViewProjectionMatrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//========//
|
||||||
|
// render //
|
||||||
|
//========//
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onRender()
|
||||||
|
{
|
||||||
|
int depthTextureId = GlDhMetaRenderer.INSTANCE.getActiveDepthTextureId();
|
||||||
|
int colorTextureId = GlDhMetaRenderer.INSTANCE.getActiveColorTextureId();
|
||||||
|
|
||||||
|
if (depthTextureId == -1
|
||||||
|
|| colorTextureId == -1)
|
||||||
|
{
|
||||||
|
// the renderer is currently being re-built and/or inactive,
|
||||||
|
// we don't need to/can't render fading
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, this.frameBuffer);
|
||||||
|
GLMC.disableScissorTest();
|
||||||
|
GLMC.disableDepthTest();
|
||||||
|
GLMC.disableBlend();
|
||||||
|
|
||||||
|
|
||||||
|
GLMC.glActiveTexture(GL32.GL_TEXTURE0);
|
||||||
|
GLMC.glBindTexture(depthTextureId);
|
||||||
|
GL32.glUniform1i(this.uDhDepthTexture, 0);
|
||||||
|
|
||||||
|
GLMC.glActiveTexture(GL32.GL_TEXTURE1);
|
||||||
|
GLMC.glBindTexture(MC_RENDER.getColorTextureId());
|
||||||
|
GL32.glUniform1i(this.uMcColorTexture, 1);
|
||||||
|
|
||||||
|
GLMC.glActiveTexture(GL32.GL_TEXTURE2);
|
||||||
|
GLMC.glBindTexture(colorTextureId);
|
||||||
|
GL32.glUniform1i(this.uDhColorTexture, 2);
|
||||||
|
|
||||||
|
|
||||||
|
GlScreenQuad.INSTANCE.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+211
@@ -0,0 +1,211 @@
|
|||||||
|
/*
|
||||||
|
* 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.postProcessing.fade;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.api.objects.math.DhApiMat4f;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.GlDhMetaRenderer;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.shader.GlShaderProgram;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.postProcessing.GlScreenQuad;
|
||||||
|
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.common.render.openGl.util.GlAbstractShaderRenderer;
|
||||||
|
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 org.lwjgl.opengl.GL32;
|
||||||
|
|
||||||
|
public class GlDhVanillaFadeShader extends GlAbstractShaderRenderer
|
||||||
|
{
|
||||||
|
public static GlDhVanillaFadeShader INSTANCE = new GlDhVanillaFadeShader();
|
||||||
|
|
||||||
|
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
|
||||||
|
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
|
||||||
|
|
||||||
|
|
||||||
|
public int frameBuffer = -1;
|
||||||
|
|
||||||
|
private Mat4f inverseMcMvmProjMatrix;
|
||||||
|
private Mat4f inverseDhMvmProjMatrix;
|
||||||
|
private float levelMaxHeight;
|
||||||
|
|
||||||
|
|
||||||
|
// Uniforms
|
||||||
|
public int uMcDepthTexture = -1;
|
||||||
|
public int uDhDepthTexture = -1;
|
||||||
|
public int uCombinedMcDhColorTexture = -1;
|
||||||
|
public int uDhColorTexture = -1;
|
||||||
|
|
||||||
|
/** Inverted Model View Projection matrix */
|
||||||
|
public int uDhInvMvmProj = -1;
|
||||||
|
public int uMcInvMvmProj = -1;
|
||||||
|
|
||||||
|
public int uStartFadeBlockDistance = -1;
|
||||||
|
public int uEndFadeBlockDistance = -1;
|
||||||
|
public int uMaxLevelHeight = -1;
|
||||||
|
|
||||||
|
public int uOnlyRenderLods = -1;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public GlDhVanillaFadeShader() { }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInit()
|
||||||
|
{
|
||||||
|
this.shader = new GlShaderProgram(
|
||||||
|
"assets/distanthorizons/shaders/shared/gl/quadApply.vert",
|
||||||
|
"assets/distanthorizons/shaders/fade/gl/vanillaFade.frag",
|
||||||
|
"vPosition"
|
||||||
|
);
|
||||||
|
|
||||||
|
// all uniforms should be tryGet...
|
||||||
|
// because disabling fade can cause the GLSL to optimize out most (if not all) uniforms
|
||||||
|
|
||||||
|
// near fade
|
||||||
|
this.uDhInvMvmProj = this.shader.tryGetUniformLocation("uDhInvMvmProj");
|
||||||
|
this.uMcInvMvmProj = this.shader.tryGetUniformLocation("uMcInvMvmProj");
|
||||||
|
|
||||||
|
this.uMcDepthTexture = this.shader.tryGetUniformLocation("uMcDepthTexture");
|
||||||
|
this.uDhDepthTexture = this.shader.tryGetUniformLocation("uDhDepthTexture");
|
||||||
|
this.uCombinedMcDhColorTexture = this.shader.tryGetUniformLocation("uCombinedMcDhColorTexture");
|
||||||
|
this.uDhColorTexture = this.shader.tryGetUniformLocation("uDhColorTexture");
|
||||||
|
|
||||||
|
this.uStartFadeBlockDistance = this.shader.tryGetUniformLocation("uStartFadeBlockDistance");
|
||||||
|
this.uEndFadeBlockDistance = this.shader.tryGetUniformLocation("uEndFadeBlockDistance");
|
||||||
|
this.uMaxLevelHeight = this.shader.tryGetUniformLocation("uMaxLevelHeight");
|
||||||
|
|
||||||
|
this.uOnlyRenderLods = this.shader.tryGetUniformLocation("uOnlyRenderLods");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// render prep //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onApplyUniforms(RenderParams renderParams)
|
||||||
|
{
|
||||||
|
this.shader.setUniform(this.uMcInvMvmProj, this.inverseMcMvmProjMatrix);
|
||||||
|
this.shader.setUniform(this.uDhInvMvmProj, this.inverseDhMvmProjMatrix);
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
this.shader.setUniform(this.uStartFadeBlockDistance, fadeStartDistance);
|
||||||
|
this.shader.setUniform(this.uEndFadeBlockDistance, fadeEndDistance);
|
||||||
|
|
||||||
|
this.shader.setUniform(this.uMaxLevelHeight, this.levelMaxHeight);
|
||||||
|
|
||||||
|
this.shader.setUniform(this.uOnlyRenderLods, Config.Client.Advanced.Debugging.lodOnlyMode.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProjectionMatrix(DhApiMat4f mcModelViewMatrix, DhApiMat4f mcProjectionMatrix)
|
||||||
|
{
|
||||||
|
Mat4f inverseMcModelViewProjectionMatrix = new Mat4f(mcProjectionMatrix);
|
||||||
|
inverseMcModelViewProjectionMatrix.multiply(mcModelViewMatrix);
|
||||||
|
inverseMcModelViewProjectionMatrix.invert();
|
||||||
|
this.inverseMcMvmProjMatrix = inverseMcModelViewProjectionMatrix;
|
||||||
|
|
||||||
|
|
||||||
|
Mat4f dhProjectionMatrix = RenderUtil.createLodProjectionMatrix(mcProjectionMatrix);
|
||||||
|
Mat4f dhModelViewMatrix = RenderUtil.createLodModelViewMatrix(mcModelViewMatrix);
|
||||||
|
|
||||||
|
Mat4f inverseDhModelViewProjectionMatrix = new Mat4f(dhProjectionMatrix);
|
||||||
|
inverseDhModelViewProjectionMatrix.multiply(dhModelViewMatrix);
|
||||||
|
inverseDhModelViewProjectionMatrix.invert();
|
||||||
|
this.inverseDhMvmProjMatrix = inverseDhModelViewProjectionMatrix;
|
||||||
|
}
|
||||||
|
public void setLevelMaxHeight(int levelMaxHeight) { this.levelMaxHeight = levelMaxHeight; }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//========//
|
||||||
|
// render //
|
||||||
|
//========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onRender()
|
||||||
|
{
|
||||||
|
int depthTextureId = GlDhMetaRenderer.INSTANCE.getActiveDepthTextureId();
|
||||||
|
int colorTextureId = GlDhMetaRenderer.INSTANCE.getActiveColorTextureId();
|
||||||
|
|
||||||
|
if (depthTextureId == -1
|
||||||
|
|| colorTextureId == -1)
|
||||||
|
{
|
||||||
|
// the renderer is currently being re-built and/or inactive,
|
||||||
|
// we don't need to/can't render fading
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, this.frameBuffer);
|
||||||
|
GLMC.disableScissorTest();
|
||||||
|
GLMC.disableDepthTest();
|
||||||
|
GLMC.disableBlend();
|
||||||
|
|
||||||
|
GLMC.glActiveTexture(GL32.GL_TEXTURE0);
|
||||||
|
GLMC.glBindTexture(MC_RENDER.getDepthTextureId());
|
||||||
|
GL32.glUniform1i(this.uMcDepthTexture, 0);
|
||||||
|
|
||||||
|
GLMC.glActiveTexture(GL32.GL_TEXTURE1);
|
||||||
|
GLMC.glBindTexture(depthTextureId);
|
||||||
|
GL32.glUniform1i(this.uDhDepthTexture, 1);
|
||||||
|
|
||||||
|
GLMC.glActiveTexture(GL32.GL_TEXTURE2);
|
||||||
|
GLMC.glBindTexture(MC_RENDER.getColorTextureId());
|
||||||
|
GL32.glUniform1i(this.uCombinedMcDhColorTexture, 2);
|
||||||
|
|
||||||
|
GLMC.glActiveTexture(GL32.GL_TEXTURE3);
|
||||||
|
GLMC.glBindTexture(colorTextureId);
|
||||||
|
GL32.glUniform1i(this.uDhColorTexture, 3);
|
||||||
|
|
||||||
|
|
||||||
|
GlScreenQuad.INSTANCE.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+203
@@ -0,0 +1,203 @@
|
|||||||
|
/*
|
||||||
|
* 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.postProcessing.fade;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.GlDhMetaRenderer;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.GLState;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import com.seibel.distanthorizons.core.render.RenderParams;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IProfilerWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhVanillaFadeRenderer;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
import org.lwjgl.opengl.GL32;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles fading MC and DH together via {@link GlDhVanillaFadeShader} and {@link GlDhFarFadeApplyShader}. <br><br>
|
||||||
|
*
|
||||||
|
* {@link GlDhVanillaFadeShader} - draws the Fade to a texture. <br>
|
||||||
|
* {@link GlDhFarFadeApplyShader} - draws the Fade texture to MC's FrameBuffer. <br>
|
||||||
|
*/
|
||||||
|
public class GlVanillaFadeRenderer implements IDhVanillaFadeRenderer
|
||||||
|
{
|
||||||
|
public static GlVanillaFadeRenderer INSTANCE = new GlVanillaFadeRenderer();
|
||||||
|
|
||||||
|
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
|
|
||||||
|
private static final IMinecraftClientWrapper MC_CLIENT = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
|
||||||
|
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
|
||||||
|
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
|
||||||
|
|
||||||
|
|
||||||
|
private boolean init = false;
|
||||||
|
|
||||||
|
private int width = -1;
|
||||||
|
private int height = -1;
|
||||||
|
private int fadeFramebuffer = -1;
|
||||||
|
|
||||||
|
private int fadeTexture = -1;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
private GlVanillaFadeRenderer() { }
|
||||||
|
|
||||||
|
public void init()
|
||||||
|
{
|
||||||
|
if (this.init) return;
|
||||||
|
this.init = true;
|
||||||
|
|
||||||
|
GlDhVanillaFadeShader.INSTANCE.init();
|
||||||
|
GlDhFarFadeApplyShader.INSTANCE.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createFramebuffer(int width, int height)
|
||||||
|
{
|
||||||
|
if (this.fadeFramebuffer != -1)
|
||||||
|
{
|
||||||
|
GL32.glDeleteFramebuffers(this.fadeFramebuffer);
|
||||||
|
this.fadeFramebuffer = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.fadeFramebuffer = GL32.glGenFramebuffers();
|
||||||
|
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, this.fadeFramebuffer);
|
||||||
|
|
||||||
|
|
||||||
|
// Applying the fade texture is only needed if MC is drawing to their own frame buffer,
|
||||||
|
// otherwise we can directly render to their texture
|
||||||
|
if (MC_RENDER.mcRendersToFrameBuffer())
|
||||||
|
{
|
||||||
|
if (this.fadeTexture != -1)
|
||||||
|
{
|
||||||
|
GLMC.glDeleteTextures(this.fadeTexture);
|
||||||
|
this.fadeTexture = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.fadeTexture = GL32.glGenTextures();
|
||||||
|
GLMC.glBindTexture(this.fadeTexture);
|
||||||
|
GL32.glTexImage2D(GL32.GL_TEXTURE_2D, 0, GL32.GL_RGBA16, width, height, 0, GL32.GL_RGBA, GL32.GL_UNSIGNED_SHORT_4_4_4_4, (ByteBuffer) null);
|
||||||
|
GL32.glTexParameteri(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_MIN_FILTER, GL32.GL_LINEAR);
|
||||||
|
GL32.glTexParameteri(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_MAG_FILTER, GL32.GL_LINEAR);
|
||||||
|
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_TEXTURE_2D, this.fadeTexture, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_TEXTURE_2D, MC_RENDER.getColorTextureId(), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//========//
|
||||||
|
// render //
|
||||||
|
//========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(RenderParams renderParams)
|
||||||
|
{
|
||||||
|
int depthTextureId = GlDhMetaRenderer.INSTANCE.getActiveDepthTextureId();
|
||||||
|
if (depthTextureId == -1)
|
||||||
|
{
|
||||||
|
// the renderer hasn't been set up yet
|
||||||
|
// trying to render fading may cause GL errors
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
IProfilerWrapper profiler = MC_CLIENT.getProfiler();
|
||||||
|
profiler.pop(); // get out of "terrain"
|
||||||
|
profiler.push("DH-Vanilla Fade");
|
||||||
|
|
||||||
|
|
||||||
|
try(GLState mcState = new GLState())
|
||||||
|
{
|
||||||
|
profiler.push("Vanilla Fade Generate");
|
||||||
|
|
||||||
|
this.init();
|
||||||
|
|
||||||
|
// resize the framebuffer if necessary
|
||||||
|
int width = MC_RENDER.getTargetFramebufferViewportWidth();
|
||||||
|
int height = MC_RENDER.getTargetFramebufferViewportHeight();
|
||||||
|
if (this.width != width || this.height != height)
|
||||||
|
{
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
this.createFramebuffer(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GlDhVanillaFadeShader.INSTANCE.frameBuffer = this.fadeFramebuffer;
|
||||||
|
GlDhVanillaFadeShader.INSTANCE.setProjectionMatrix(renderParams.mcModelViewMatrix, renderParams.mcProjectionMatrix);
|
||||||
|
GlDhVanillaFadeShader.INSTANCE.setLevelMaxHeight(renderParams.clientLevelWrapper.getMaxHeight());
|
||||||
|
GlDhVanillaFadeShader.INSTANCE.render(renderParams);
|
||||||
|
|
||||||
|
// Applying the fade texture is only needed if MC is drawing to their own frame buffer,
|
||||||
|
// otherwise we can directly render to their texture
|
||||||
|
if (MC_RENDER.mcRendersToFrameBuffer())
|
||||||
|
{
|
||||||
|
profiler.popPush("Vanilla Fade Apply");
|
||||||
|
|
||||||
|
GlDhFarFadeApplyShader.INSTANCE.fadeTexture = this.fadeTexture;
|
||||||
|
GlDhFarFadeApplyShader.INSTANCE.readFramebuffer = GlDhFarFadeShader.INSTANCE.frameBuffer;
|
||||||
|
GlDhFarFadeApplyShader.INSTANCE.drawFramebuffer = MC_RENDER.getTargetFramebuffer();
|
||||||
|
GlDhFarFadeApplyShader.INSTANCE.render(renderParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
profiler.pop();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
LOGGER.error("Unexpected error during fade render, error: ["+e.getMessage()+"].", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// base overrides //
|
||||||
|
//================//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public void free()
|
||||||
|
{
|
||||||
|
GlDhVanillaFadeShader.INSTANCE.free();
|
||||||
|
GlDhFarFadeApplyShader.INSTANCE.free();
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+118
@@ -0,0 +1,118 @@
|
|||||||
|
/*
|
||||||
|
* 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.postProcessing.fog;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.GlDhMetaRenderer;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.shader.GlShaderProgram;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.postProcessing.GlScreenQuad;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.util.GlAbstractShaderRenderer;
|
||||||
|
import com.seibel.distanthorizons.core.render.RenderParams;
|
||||||
|
import org.lwjgl.opengl.GL32;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws the Fog texture onto DH's FrameBuffer. <br><br>
|
||||||
|
*
|
||||||
|
* See Also: <br>
|
||||||
|
* {@link GlDhFogRenderer} - Parent to this shader. <br>
|
||||||
|
* {@link GlDhFogShader} - draws the Fog texture. <br>
|
||||||
|
*/
|
||||||
|
public class GlDhFogApplyShader extends GlAbstractShaderRenderer
|
||||||
|
{
|
||||||
|
public static GlDhFogApplyShader INSTANCE = new GlDhFogApplyShader();
|
||||||
|
|
||||||
|
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
|
||||||
|
|
||||||
|
|
||||||
|
public int fogTexture;
|
||||||
|
|
||||||
|
// uniforms
|
||||||
|
public int colorTextureUniform;
|
||||||
|
public int depthTextureUniform;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInit()
|
||||||
|
{
|
||||||
|
this.shader = new GlShaderProgram(
|
||||||
|
"assets/distanthorizons/shaders/shared/gl/quadApply.vert",
|
||||||
|
"assets/distanthorizons/shaders/fog/gl/apply.frag",
|
||||||
|
"vPosition"
|
||||||
|
);
|
||||||
|
|
||||||
|
// uniform setup
|
||||||
|
this.colorTextureUniform = this.shader.getUniformLocation("uColorTexture");
|
||||||
|
this.depthTextureUniform = this.shader.getUniformLocation("uDepthTexture");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// render prep //
|
||||||
|
//=============//
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onApplyUniforms(RenderParams renderParams)
|
||||||
|
{
|
||||||
|
GLMC.glActiveTexture(GL32.GL_TEXTURE0);
|
||||||
|
GLMC.glBindTexture(this.fogTexture);
|
||||||
|
GL32.glUniform1i(this.colorTextureUniform, 0);
|
||||||
|
|
||||||
|
GLMC.glActiveTexture(GL32.GL_TEXTURE1);
|
||||||
|
GLMC.glBindTexture(GlDhMetaRenderer.INSTANCE.getActiveDepthTextureId());
|
||||||
|
GL32.glUniform1i(this.depthTextureUniform, 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//========//
|
||||||
|
// render //
|
||||||
|
//========//
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onRender()
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
// Depth testing must be disabled otherwise this application shader won't apply anything.
|
||||||
|
// setting this isn't necessary in vanilla, but some mods may change this, requiring it to be set manually,
|
||||||
|
// it should be automatically restored after rendering is complete.
|
||||||
|
GLMC.disableDepthTest();
|
||||||
|
|
||||||
|
|
||||||
|
// apply the rendered Fog to DH's framebuffer
|
||||||
|
GLMC.glBindFramebuffer(GL32.GL_READ_FRAMEBUFFER, GlDhFogShader.INSTANCE.frameBuffer);
|
||||||
|
GLMC.glBindFramebuffer(GL32.GL_DRAW_FRAMEBUFFER, GlDhMetaRenderer.INSTANCE.getActiveFramebufferId());
|
||||||
|
|
||||||
|
GlScreenQuad.INSTANCE.render();
|
||||||
|
|
||||||
|
GLMC.glBindFramebuffer(GL32.GL_READ_FRAMEBUFFER, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+156
@@ -0,0 +1,156 @@
|
|||||||
|
/*
|
||||||
|
* 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.postProcessing.fog;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.GLState;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
|
import com.seibel.distanthorizons.core.render.RenderParams;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhFogRenderer;
|
||||||
|
import org.lwjgl.opengl.GL32;
|
||||||
|
import org.lwjgl.opengl.GL43C;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles adding SSAO via {@link GlDhFogShader} and {@link GlDhFogApplyShader}. <br><br>
|
||||||
|
*
|
||||||
|
* {@link GlDhFogShader} - draws the Fog to a texture. <br>
|
||||||
|
* {@link GlDhFogApplyShader} - draws the Fog texture to DH's FrameBuffer. <br>
|
||||||
|
*/
|
||||||
|
public class GlDhFogRenderer implements IDhFogRenderer
|
||||||
|
{
|
||||||
|
public static GlDhFogRenderer INSTANCE = new GlDhFogRenderer();
|
||||||
|
|
||||||
|
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
|
||||||
|
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
|
||||||
|
|
||||||
|
|
||||||
|
private boolean init = false;
|
||||||
|
|
||||||
|
private int width = -1;
|
||||||
|
private int height = -1;
|
||||||
|
private int fogFramebuffer = -1;
|
||||||
|
|
||||||
|
private int fogTexture = -1;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
|
||||||
|
private GlDhFogRenderer() { }
|
||||||
|
|
||||||
|
public void init()
|
||||||
|
{
|
||||||
|
if (this.init) return;
|
||||||
|
this.init = true;
|
||||||
|
|
||||||
|
GlDhFogShader.INSTANCE.init();
|
||||||
|
GlDhFogApplyShader.INSTANCE.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createFramebuffer(int width, int height)
|
||||||
|
{
|
||||||
|
if (this.fogFramebuffer != -1)
|
||||||
|
{
|
||||||
|
GL32.glDeleteFramebuffers(this.fogFramebuffer);
|
||||||
|
this.fogFramebuffer = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.fogTexture != -1)
|
||||||
|
{
|
||||||
|
GLMC.glDeleteTextures(this.fogTexture);
|
||||||
|
this.fogTexture = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.fogFramebuffer = GL32.glGenFramebuffers();
|
||||||
|
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, this.fogFramebuffer);
|
||||||
|
|
||||||
|
this.fogTexture = GLMC.glGenTextures();
|
||||||
|
{
|
||||||
|
GLMC.glBindTexture(this.fogTexture);
|
||||||
|
GL32.glTexImage2D(GL32.GL_TEXTURE_2D, 0, GL32.GL_RGBA16, width, height, 0, GL32.GL_RGBA, GL32.GL_UNSIGNED_SHORT_4_4_4_4, (ByteBuffer) null);
|
||||||
|
GL32.glTexParameteri(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_MIN_FILTER, GL32.GL_LINEAR);
|
||||||
|
GL32.glTexParameteri(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_MAG_FILTER, GL32.GL_LINEAR);
|
||||||
|
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_TEXTURE_2D, this.fogTexture, 0);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//========//
|
||||||
|
// render //
|
||||||
|
//========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(RenderParams renderParams)
|
||||||
|
{
|
||||||
|
// GLState needed in MC 1.16.5 probably due to MC not manually setting each GL state they need before the next rendering step
|
||||||
|
try (GLState state = new GLState())
|
||||||
|
{
|
||||||
|
this.init();
|
||||||
|
|
||||||
|
// resize the framebuffer if necessary
|
||||||
|
int width = MC_RENDER.getTargetFramebufferViewportWidth();
|
||||||
|
int height = MC_RENDER.getTargetFramebufferViewportHeight();
|
||||||
|
if (this.width != width || this.height != height)
|
||||||
|
{
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
this.createFramebuffer(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
GlDhFogShader.INSTANCE.frameBuffer = this.fogFramebuffer;
|
||||||
|
GlDhFogShader.INSTANCE.setProjectionMatrix(renderParams.dhMvmProjMatrix);
|
||||||
|
GlDhFogShader.INSTANCE.render(renderParams);
|
||||||
|
|
||||||
|
GlDhFogApplyShader.INSTANCE.fogTexture = this.fogTexture;
|
||||||
|
GlDhFogApplyShader.INSTANCE.render(renderParams);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// base overrides //
|
||||||
|
//================//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public void free()
|
||||||
|
{
|
||||||
|
GlDhFogShader.INSTANCE.free();
|
||||||
|
GlDhFogApplyShader.INSTANCE.free();
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+301
@@ -0,0 +1,301 @@
|
|||||||
|
/*
|
||||||
|
* 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.postProcessing.fog;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.api.enums.rendering.EDhApiFogColorMode;
|
||||||
|
import com.seibel.distanthorizons.api.enums.rendering.EDhApiHeightFogDirection;
|
||||||
|
import com.seibel.distanthorizons.api.enums.rendering.EDhApiHeightFogMixMode;
|
||||||
|
import com.seibel.distanthorizons.api.objects.math.DhApiMat4f;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.GlDhMetaRenderer;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.shader.GlShaderProgram;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.postProcessing.GlScreenQuad;
|
||||||
|
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.common.render.openGl.util.GlAbstractShaderRenderer;
|
||||||
|
import com.seibel.distanthorizons.core.render.RenderParams;
|
||||||
|
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.util.math.Mat4f;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||||
|
import org.lwjgl.opengl.GL32;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
public class GlDhFogShader extends GlAbstractShaderRenderer
|
||||||
|
{
|
||||||
|
public static final GlDhFogShader INSTANCE = new GlDhFogShader();
|
||||||
|
|
||||||
|
private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
|
||||||
|
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
|
||||||
|
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public int frameBuffer;
|
||||||
|
private Mat4f inverseMvmProjMatrix;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//==========//
|
||||||
|
// Uniforms //
|
||||||
|
//==========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public int uDepthMap;
|
||||||
|
/** Inverted Model View Projection matrix */
|
||||||
|
public int uInvMvmProj;
|
||||||
|
|
||||||
|
// fog uniforms
|
||||||
|
public int uFogColor;
|
||||||
|
public int uFogScale;
|
||||||
|
public int uFogVerticalScale;
|
||||||
|
public int uFogDebugMode;
|
||||||
|
public int uFogFalloffType;
|
||||||
|
|
||||||
|
// far fog
|
||||||
|
public int uFarFogStart;
|
||||||
|
public int uFarFogLength;
|
||||||
|
public int uFarFogMin;
|
||||||
|
public int uFarFogRange;
|
||||||
|
public int uFarFogDensity;
|
||||||
|
|
||||||
|
// height fog
|
||||||
|
public int uHeightFogStart;
|
||||||
|
public int uHeightFogLength;
|
||||||
|
public int uHeightFogMin;
|
||||||
|
public int uHeightFogRange;
|
||||||
|
public int uHeightFogDensity;
|
||||||
|
|
||||||
|
public int uHeightFogEnabled;
|
||||||
|
public int uHeightFogFalloffType;
|
||||||
|
public int uHeightBasedOnCamera;
|
||||||
|
public int uHeightFogBaseHeight;
|
||||||
|
public int uHeightFogAppliesUp;
|
||||||
|
public int uHeightFogAppliesDown;
|
||||||
|
public int uUseSphericalFog;
|
||||||
|
public int uHeightFogMixingMode;
|
||||||
|
public int uCameraBlockYPos;
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public GlDhFogShader() { }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInit()
|
||||||
|
{
|
||||||
|
this.shader = new GlShaderProgram(
|
||||||
|
"assets/distanthorizons/shaders/shared/gl/quadApply.vert",
|
||||||
|
"assets/distanthorizons/shaders/fog/gl/fog.frag",
|
||||||
|
"vPosition"
|
||||||
|
);
|
||||||
|
|
||||||
|
// all uniforms should be tryGet...
|
||||||
|
// because disabling fog can cause the GLSL to optimize out most (if not all) uniforms
|
||||||
|
|
||||||
|
this.uDepthMap = this.shader.getUniformLocation("uDepthMap");
|
||||||
|
this.uInvMvmProj = this.shader.getUniformLocation("uInvMvmProj");
|
||||||
|
|
||||||
|
// Fog uniforms
|
||||||
|
this.uFogScale = this.shader.getUniformLocation("uFogScale");
|
||||||
|
this.uFogVerticalScale = this.shader.getUniformLocation("uFogVerticalScale");
|
||||||
|
this.uFogColor = this.shader.getUniformLocation("uFogColor");
|
||||||
|
this.uFogDebugMode = this.shader.getUniformLocation("uFogDebugMode");
|
||||||
|
this.uFogFalloffType = this.shader.getUniformLocation("uFogFalloffType");
|
||||||
|
|
||||||
|
// fog config
|
||||||
|
this.uFarFogStart = this.shader.getUniformLocation("uFarFogStart");
|
||||||
|
this.uFarFogLength = this.shader.getUniformLocation("uFarFogLength");
|
||||||
|
this.uFarFogMin = this.shader.getUniformLocation("uFarFogMin");
|
||||||
|
this.uFarFogRange = this.shader.getUniformLocation("uFarFogRange");
|
||||||
|
this.uFarFogDensity = this.shader.getUniformLocation("uFarFogDensity");
|
||||||
|
|
||||||
|
// height fog
|
||||||
|
this.uHeightFogStart = this.shader.getUniformLocation("uHeightFogStart");
|
||||||
|
this.uHeightFogLength = this.shader.getUniformLocation("uHeightFogLength");
|
||||||
|
this.uHeightFogMin = this.shader.getUniformLocation("uHeightFogMin");
|
||||||
|
this.uHeightFogRange = this.shader.getUniformLocation("uHeightFogRange");
|
||||||
|
this.uHeightFogDensity = this.shader.getUniformLocation("uHeightFogDensity");
|
||||||
|
|
||||||
|
this.uHeightFogEnabled = this.shader.getUniformLocation("uHeightFogEnabled");
|
||||||
|
this.uHeightFogFalloffType = this.shader.getUniformLocation("uHeightFogFalloffType");
|
||||||
|
this.uHeightBasedOnCamera = this.shader.getUniformLocation("uHeightBasedOnCamera");
|
||||||
|
this.uHeightFogBaseHeight = this.shader.getUniformLocation("uHeightFogBaseHeight");
|
||||||
|
this.uHeightFogAppliesUp = this.shader.getUniformLocation("uHeightFogAppliesUp");
|
||||||
|
this.uHeightFogAppliesDown = this.shader.getUniformLocation("uHeightFogAppliesDown");
|
||||||
|
this.uUseSphericalFog = this.shader.getUniformLocation("uUseSphericalFog");
|
||||||
|
this.uHeightFogMixingMode = this.shader.getUniformLocation("uHeightFogMixingMode");
|
||||||
|
this.uCameraBlockYPos = this.shader.getUniformLocation("uCameraBlockYPos");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// render prep //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onApplyUniforms(RenderParams renderParams)
|
||||||
|
{
|
||||||
|
int lodDrawDistance = Config.Client.Advanced.Graphics.Quality.lodChunkRenderDistanceRadius.get() * LodUtil.CHUNK_WIDTH;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (this.inverseMvmProjMatrix != null)
|
||||||
|
{
|
||||||
|
this.shader.setUniform(this.uInvMvmProj, this.inverseMvmProjMatrix);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Fog uniforms
|
||||||
|
this.shader.setUniform(this.uFogColor, this.getFogColor(renderParams.partialTicks));
|
||||||
|
this.shader.setUniform(this.uFogScale, 1.f / lodDrawDistance);
|
||||||
|
this.shader.setUniform(this.uFogVerticalScale, 1.f / MC.getWrappedClientLevel().getMaxHeight());
|
||||||
|
// only used for debugging
|
||||||
|
this.shader.setUniform(this.uFogDebugMode, 0); // 1 = render everything with fog color // 7 = use debug rendering
|
||||||
|
this.shader.setUniform(this.uFogFalloffType, Config.Client.Advanced.Graphics.Fog.farFogFalloff.get().value);
|
||||||
|
|
||||||
|
|
||||||
|
// fog config
|
||||||
|
float farFogStart = Config.Client.Advanced.Graphics.Fog.farFogStart.get();
|
||||||
|
float farFogEnd = Config.Client.Advanced.Graphics.Fog.farFogEnd.get();
|
||||||
|
float farFogMin = Config.Client.Advanced.Graphics.Fog.farFogMin.get();
|
||||||
|
float farFogMax = Config.Client.Advanced.Graphics.Fog.farFogMax.get();
|
||||||
|
float farFogDensity = Config.Client.Advanced.Graphics.Fog.farFogDensity.get();
|
||||||
|
|
||||||
|
// override fog if underwater
|
||||||
|
if (MC_RENDER.isFogStateSpecial())
|
||||||
|
{
|
||||||
|
// hide everything behind fog
|
||||||
|
farFogStart = 0.0f;
|
||||||
|
farFogEnd = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.shader.setUniform(this.uFarFogStart, farFogStart);
|
||||||
|
this.shader.setUniform(this.uFarFogLength, farFogEnd - farFogStart);
|
||||||
|
this.shader.setUniform(this.uFarFogMin, farFogMin);
|
||||||
|
this.shader.setUniform(this.uFarFogRange, farFogMax - farFogMin);
|
||||||
|
this.shader.setUniform(this.uFarFogDensity, farFogDensity);
|
||||||
|
|
||||||
|
|
||||||
|
// height config
|
||||||
|
EDhApiHeightFogMixMode heightFogMixingMode = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogMixMode.get();
|
||||||
|
boolean heightFogEnabled = heightFogMixingMode != EDhApiHeightFogMixMode.SPHERICAL && heightFogMixingMode != EDhApiHeightFogMixMode.CYLINDRICAL;
|
||||||
|
boolean useSphericalFog = heightFogMixingMode == EDhApiHeightFogMixMode.SPHERICAL;
|
||||||
|
EDhApiHeightFogDirection heightFogCameraDirection = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogDirection.get();
|
||||||
|
|
||||||
|
float heightFogStart = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogStart.get();
|
||||||
|
float heightFogEnd = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogEnd.get();
|
||||||
|
float heightFogMin = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogMin.get();
|
||||||
|
float heightFogMax = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogMax.get();
|
||||||
|
float heightFogDensity = Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogDensity.get();
|
||||||
|
|
||||||
|
this.shader.setUniform(this.uHeightFogStart, heightFogStart);
|
||||||
|
this.shader.setUniform(this.uHeightFogLength, heightFogEnd - heightFogStart);
|
||||||
|
this.shader.setUniform(this.uHeightFogMin, heightFogMin);
|
||||||
|
this.shader.setUniform(this.uHeightFogRange, heightFogMax - heightFogMin);
|
||||||
|
this.shader.setUniform(this.uHeightFogDensity, heightFogDensity);
|
||||||
|
|
||||||
|
|
||||||
|
this.shader.setUniform(this.uHeightFogEnabled, heightFogEnabled);
|
||||||
|
this.shader.setUniform(this.uHeightFogFalloffType, Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogFalloff.get().value);
|
||||||
|
this.shader.setUniform(this.uHeightFogBaseHeight, Config.Client.Advanced.Graphics.Fog.HeightFog.heightFogBaseHeight.get());
|
||||||
|
this.shader.setUniform(this.uHeightBasedOnCamera, heightFogCameraDirection.basedOnCamera);
|
||||||
|
this.shader.setUniform(this.uHeightFogAppliesUp, heightFogCameraDirection.fogAppliesUp);
|
||||||
|
this.shader.setUniform(this.uHeightFogAppliesDown, heightFogCameraDirection.fogAppliesDown);
|
||||||
|
this.shader.setUniform(this.uUseSphericalFog, useSphericalFog);
|
||||||
|
this.shader.setUniform(this.uHeightFogMixingMode, heightFogMixingMode.value);
|
||||||
|
this.shader.setUniform(this.uCameraBlockYPos, (float)MC_RENDER.getCameraExactPosition().y);
|
||||||
|
|
||||||
|
}
|
||||||
|
private Color getFogColor(float partialTicks)
|
||||||
|
{
|
||||||
|
Color fogColor;
|
||||||
|
|
||||||
|
if (Config.Client.Advanced.Graphics.Fog.colorMode.get() == EDhApiFogColorMode.USE_SKY_COLOR)
|
||||||
|
{
|
||||||
|
fogColor = MC_RENDER.getSkyColor();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fogColor = MC_RENDER.getFogColor(partialTicks);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fogColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProjectionMatrix(DhApiMat4f modelViewProjectionMatrix)
|
||||||
|
{
|
||||||
|
this.inverseMvmProjMatrix = new Mat4f(modelViewProjectionMatrix);
|
||||||
|
this.inverseMvmProjMatrix.invert();
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//========//
|
||||||
|
// render //
|
||||||
|
//========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onRender()
|
||||||
|
{
|
||||||
|
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, this.frameBuffer);
|
||||||
|
GLMC.disableScissorTest();
|
||||||
|
GLMC.disableDepthTest();
|
||||||
|
GLMC.disableBlend();
|
||||||
|
|
||||||
|
GLMC.glActiveTexture(GL32.GL_TEXTURE0);
|
||||||
|
GLMC.glBindTexture(GlDhMetaRenderer.INSTANCE.getActiveDepthTextureId());
|
||||||
|
GL32.glUniform1i(this.uDepthMap, 0);
|
||||||
|
|
||||||
|
// this is necessary for MC 1.16 (IE Legacy OpenGL)
|
||||||
|
// otherwise the framebuffer isn't cleared correctly and the fog smears across the screen
|
||||||
|
if (MC_RENDER.runningLegacyOpenGL())
|
||||||
|
{
|
||||||
|
// in another part of the DH code we set the fog color to opaque, here it needs to be transparent
|
||||||
|
float[] clearColorValues = new float[4];
|
||||||
|
GL32.glGetFloatv(GL32.GL_COLOR_CLEAR_VALUE, clearColorValues);
|
||||||
|
GL32.glClearColor(clearColorValues[0], clearColorValues[1], clearColorValues[2], 0.0f);
|
||||||
|
|
||||||
|
GL32.glClear(GL32.GL_COLOR_BUFFER_BIT | GL32.GL_DEPTH_BUFFER_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GlScreenQuad.INSTANCE.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+146
@@ -0,0 +1,146 @@
|
|||||||
|
/*
|
||||||
|
* 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.postProcessing.ssao;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.GlDhMetaRenderer;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.shader.GlShaderProgram;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.postProcessing.GlScreenQuad;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.util.GlAbstractShaderRenderer;
|
||||||
|
import com.seibel.distanthorizons.core.render.RenderParams;
|
||||||
|
import com.seibel.distanthorizons.core.util.RenderUtil;
|
||||||
|
import org.lwjgl.opengl.GL32;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws the SSAO texture onto DH's FrameBuffer. <br><br>
|
||||||
|
*
|
||||||
|
* See Also: <br>
|
||||||
|
* {@link GlDhSSAORenderer} - Parent to this shader. <br>
|
||||||
|
* {@link GlDhSSAOShader} - draws the SSAO texture. <br>
|
||||||
|
*/
|
||||||
|
public class GlDhSSAOApplyShader extends GlAbstractShaderRenderer
|
||||||
|
{
|
||||||
|
public static GlDhSSAOApplyShader INSTANCE = new GlDhSSAOApplyShader();
|
||||||
|
|
||||||
|
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
|
||||||
|
|
||||||
|
|
||||||
|
public int ssaoTexture;
|
||||||
|
|
||||||
|
// uniforms
|
||||||
|
public int gSSAOMapUniform;
|
||||||
|
public int gDepthMapUniform;
|
||||||
|
public int gViewSizeUniform;
|
||||||
|
public int gBlurRadiusUniform;
|
||||||
|
public int gNearUniform;
|
||||||
|
public int gFarUniform;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInit()
|
||||||
|
{
|
||||||
|
this.shader = new GlShaderProgram(
|
||||||
|
"assets/distanthorizons/shaders/shared/gl/quadApply.vert",
|
||||||
|
"assets/distanthorizons/shaders/ssao/gl/apply.frag",
|
||||||
|
"vPosition"
|
||||||
|
);
|
||||||
|
|
||||||
|
// uniform setup
|
||||||
|
this.gSSAOMapUniform = this.shader.getUniformLocation("gSSAOMap");
|
||||||
|
this.gDepthMapUniform = this.shader.getUniformLocation("gDepthMap");
|
||||||
|
this.gViewSizeUniform = this.shader.tryGetUniformLocation("gViewSize");
|
||||||
|
this.gBlurRadiusUniform = this.shader.tryGetUniformLocation("gBlurRadius");
|
||||||
|
this.gNearUniform = this.shader.tryGetUniformLocation("gNear");
|
||||||
|
this.gFarUniform = this.shader.tryGetUniformLocation("gFar");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// render prep //
|
||||||
|
//=============//
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onApplyUniforms(RenderParams renderParams)
|
||||||
|
{
|
||||||
|
GLMC.glActiveTexture(GL32.GL_TEXTURE0);
|
||||||
|
GLMC.glBindTexture(GlDhMetaRenderer.INSTANCE.getActiveDepthTextureId());
|
||||||
|
GL32.glUniform1i(this.gDepthMapUniform, 0);
|
||||||
|
|
||||||
|
GLMC.glActiveTexture(GL32.GL_TEXTURE1);
|
||||||
|
GLMC.glBindTexture(this.ssaoTexture);
|
||||||
|
GL32.glUniform1i(this.gSSAOMapUniform, 1);
|
||||||
|
|
||||||
|
GL32.glUniform1i(this.gBlurRadiusUniform, 2);
|
||||||
|
|
||||||
|
if (this.gViewSizeUniform >= 0)
|
||||||
|
{
|
||||||
|
GL32.glUniform2f(this.gViewSizeUniform,
|
||||||
|
MC_RENDER.getTargetFramebufferViewportWidth(),
|
||||||
|
MC_RENDER.getTargetFramebufferViewportHeight());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.gNearUniform >= 0)
|
||||||
|
{
|
||||||
|
GL32.glUniform1f(this.gNearUniform,
|
||||||
|
RenderUtil.getNearClipPlaneInBlocks());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.gFarUniform >= 0)
|
||||||
|
{
|
||||||
|
float farClipPlane = RenderUtil.getFarClipPlaneDistanceInBlocks();
|
||||||
|
GL32.glUniform1f(this.gFarUniform, farClipPlane);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//========//
|
||||||
|
// render //
|
||||||
|
//========//
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onRender()
|
||||||
|
{
|
||||||
|
GLMC.enableBlend();
|
||||||
|
GL32.glBlendEquation(GL32.GL_FUNC_ADD);
|
||||||
|
GLMC.glBlendFuncSeparate(GL32.GL_ZERO, GL32.GL_SRC_ALPHA, GL32.GL_ZERO, GL32.GL_ONE);
|
||||||
|
|
||||||
|
// Depth testing must be disabled otherwise this application shader won't apply anything.
|
||||||
|
// setting this isn't necessary in vanilla, but some mods may change this, requiring it to be set manually,
|
||||||
|
// it should be automatically restored after rendering is complete.
|
||||||
|
GLMC.disableDepthTest();
|
||||||
|
|
||||||
|
// apply the rendered SSAO to the LODs
|
||||||
|
GLMC.glBindFramebuffer(GL32.GL_READ_FRAMEBUFFER, GlDhSSAOShader.INSTANCE.frameBuffer);
|
||||||
|
GLMC.glBindFramebuffer(GL32.GL_DRAW_FRAMEBUFFER, GlDhMetaRenderer.INSTANCE.getActiveFramebufferId());
|
||||||
|
|
||||||
|
|
||||||
|
GlScreenQuad.INSTANCE.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+156
@@ -0,0 +1,156 @@
|
|||||||
|
/*
|
||||||
|
* 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.postProcessing.ssao;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.GLState;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
|
import com.seibel.distanthorizons.core.render.RenderParams;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhSsaoRenderer;
|
||||||
|
import org.lwjgl.opengl.GL32;
|
||||||
|
import org.lwjgl.opengl.GL43C;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles adding SSAO via {@link GlDhSSAOShader} and {@link GlDhSSAOApplyShader}. <br><br>
|
||||||
|
*
|
||||||
|
* {@link GlDhSSAOShader} - draws the SSAO to a texture. <br>
|
||||||
|
* {@link GlDhSSAOApplyShader} - draws the SSAO texture to DH's FrameBuffer. <br>
|
||||||
|
*/
|
||||||
|
public class GlDhSSAORenderer implements IDhSsaoRenderer
|
||||||
|
{
|
||||||
|
public static GlDhSSAORenderer INSTANCE = new GlDhSSAORenderer();
|
||||||
|
|
||||||
|
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
|
||||||
|
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
|
||||||
|
|
||||||
|
|
||||||
|
private boolean init = false;
|
||||||
|
|
||||||
|
private int width = -1;
|
||||||
|
private int height = -1;
|
||||||
|
private int ssaoFramebuffer = -1;
|
||||||
|
|
||||||
|
private int ssaoTexture = -1;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
|
||||||
|
private GlDhSSAORenderer() { }
|
||||||
|
|
||||||
|
public void init()
|
||||||
|
{
|
||||||
|
if (this.init) return;
|
||||||
|
this.init = true;
|
||||||
|
|
||||||
|
GlDhSSAOShader.INSTANCE.init();
|
||||||
|
GlDhSSAOApplyShader.INSTANCE.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createFramebuffer(int width, int height)
|
||||||
|
{
|
||||||
|
if (this.ssaoFramebuffer != -1)
|
||||||
|
{
|
||||||
|
GL32.glDeleteFramebuffers(this.ssaoFramebuffer);
|
||||||
|
this.ssaoFramebuffer = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.ssaoTexture != -1)
|
||||||
|
{
|
||||||
|
GLMC.glDeleteTextures(this.ssaoTexture);
|
||||||
|
this.ssaoTexture = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.ssaoFramebuffer = GL32.glGenFramebuffers();
|
||||||
|
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, this.ssaoFramebuffer);
|
||||||
|
|
||||||
|
this.ssaoTexture = GLMC.glGenTextures();
|
||||||
|
{
|
||||||
|
GLMC.glBindTexture(this.ssaoTexture);
|
||||||
|
GL32.glTexImage2D(GL32.GL_TEXTURE_2D, 0, GL32.GL_R16F, width, height, 0, GL32.GL_RED, GL32.GL_HALF_FLOAT, (ByteBuffer) null);
|
||||||
|
GL32.glTexParameteri(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_MIN_FILTER, GL32.GL_LINEAR);
|
||||||
|
GL32.glTexParameteri(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_MAG_FILTER, GL32.GL_LINEAR);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
GL32.glFramebufferTexture2D(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_TEXTURE_2D, this.ssaoTexture, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//========//
|
||||||
|
// render //
|
||||||
|
//========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(RenderParams renderParams)
|
||||||
|
{
|
||||||
|
try(GLState state = new GLState())
|
||||||
|
{
|
||||||
|
this.init();
|
||||||
|
|
||||||
|
// resize the framebuffer if necessary
|
||||||
|
int width = MC_RENDER.getTargetFramebufferViewportWidth();
|
||||||
|
int height = MC_RENDER.getTargetFramebufferViewportHeight();
|
||||||
|
if (this.width != width || this.height != height)
|
||||||
|
{
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
this.createFramebuffer(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
GlDhSSAOShader.INSTANCE.frameBuffer = this.ssaoFramebuffer;
|
||||||
|
GlDhSSAOShader.INSTANCE.setProjectionMatrix(renderParams.dhProjectionMatrix);
|
||||||
|
GlDhSSAOShader.INSTANCE.render(renderParams);
|
||||||
|
|
||||||
|
GlDhSSAOApplyShader.INSTANCE.ssaoTexture = this.ssaoTexture;
|
||||||
|
GlDhSSAOApplyShader.INSTANCE.render(renderParams);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// base overrides //
|
||||||
|
//================//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public void free()
|
||||||
|
{
|
||||||
|
GlDhSSAOShader.INSTANCE.free();
|
||||||
|
GlDhSSAOApplyShader.INSTANCE.free();
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+144
@@ -0,0 +1,144 @@
|
|||||||
|
/*
|
||||||
|
* 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.postProcessing.ssao;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.api.objects.math.DhApiMat4f;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.GlDhMetaRenderer;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.shader.GlShaderProgram;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.postProcessing.GlScreenQuad;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.util.GlAbstractShaderRenderer;
|
||||||
|
import com.seibel.distanthorizons.core.render.RenderParams;
|
||||||
|
import com.seibel.distanthorizons.core.util.math.Mat4f;
|
||||||
|
import org.lwjgl.opengl.GL32;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws the SSAO to a texture. <br><br>
|
||||||
|
*
|
||||||
|
* See Also: <br>
|
||||||
|
* {@link GlDhSSAORenderer} - Parent to this shader. <br>
|
||||||
|
* {@link GlDhSSAOApplyShader} - draws the SSAO texture to DH's FrameBuffer. <br>
|
||||||
|
*/
|
||||||
|
public class GlDhSSAOShader extends GlAbstractShaderRenderer
|
||||||
|
{
|
||||||
|
public static GlDhSSAOShader INSTANCE = new GlDhSSAOShader();
|
||||||
|
|
||||||
|
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
|
||||||
|
|
||||||
|
|
||||||
|
public int frameBuffer;
|
||||||
|
|
||||||
|
private Mat4f projection;
|
||||||
|
private Mat4f invertedProjection;
|
||||||
|
|
||||||
|
|
||||||
|
// uniforms
|
||||||
|
public int uProj;
|
||||||
|
public int uInvProj;
|
||||||
|
public int uSampleCount;
|
||||||
|
public int uRadius;
|
||||||
|
public int uStrength;
|
||||||
|
public int uMinLight;
|
||||||
|
public int uBias;
|
||||||
|
public int uDepthMap;
|
||||||
|
public int uFadeDistanceInBlocks;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInit()
|
||||||
|
{
|
||||||
|
this.shader = new GlShaderProgram(
|
||||||
|
"assets/distanthorizons/shaders/shared/gl/quadApply.vert",
|
||||||
|
"assets/distanthorizons/shaders/ssao/gl/ao.frag",
|
||||||
|
"vPosition"
|
||||||
|
);
|
||||||
|
|
||||||
|
// uniform setup
|
||||||
|
this.uProj = this.shader.getUniformLocation("uProj");
|
||||||
|
this.uInvProj = this.shader.getUniformLocation("uInvProj");
|
||||||
|
this.uSampleCount = this.shader.getUniformLocation("uSampleCount");
|
||||||
|
this.uRadius = this.shader.getUniformLocation("uRadius");
|
||||||
|
this.uStrength = this.shader.getUniformLocation("uStrength");
|
||||||
|
this.uMinLight = this.shader.getUniformLocation("uMinLight");
|
||||||
|
this.uBias = this.shader.getUniformLocation("uBias");
|
||||||
|
this.uDepthMap = this.shader.getUniformLocation("uDepthMap");
|
||||||
|
this.uFadeDistanceInBlocks = this.shader.getUniformLocation("uFadeDistanceInBlocks");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// render prep //
|
||||||
|
//=============//
|
||||||
|
|
||||||
|
public void setProjectionMatrix(DhApiMat4f projectionMatrix)
|
||||||
|
{
|
||||||
|
this.projection = new Mat4f(projectionMatrix);
|
||||||
|
|
||||||
|
this.invertedProjection = new Mat4f(projectionMatrix);
|
||||||
|
this.invertedProjection.invert();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onApplyUniforms(RenderParams renderParams)
|
||||||
|
{
|
||||||
|
this.shader.setUniform(this.uProj, this.projection);
|
||||||
|
|
||||||
|
this.shader.setUniform(this.uInvProj, this.invertedProjection);
|
||||||
|
|
||||||
|
this.shader.setUniform(this.uSampleCount, 6);
|
||||||
|
this.shader.setUniform(this.uRadius, 4.0f);
|
||||||
|
this.shader.setUniform(this.uStrength, 0.2f);
|
||||||
|
this.shader.setUniform(this.uMinLight, 0.25f);
|
||||||
|
this.shader.setUniform(this.uBias, 0.02f);
|
||||||
|
this.shader.setUniform(this.uFadeDistanceInBlocks, 1_600.0f);
|
||||||
|
|
||||||
|
GL32.glUniform1i(this.uDepthMap, 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//========//
|
||||||
|
// render //
|
||||||
|
//========//
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onRender()
|
||||||
|
{
|
||||||
|
GLMC.glBindFramebuffer(GL32.GL_FRAMEBUFFER, this.frameBuffer);
|
||||||
|
GLMC.disableScissorTest();
|
||||||
|
GLMC.disableDepthTest();
|
||||||
|
GLMC.disableBlend();
|
||||||
|
|
||||||
|
GLMC.glActiveTexture(GL32.GL_TEXTURE0);
|
||||||
|
GLMC.glBindTexture(GlDhMetaRenderer.INSTANCE.getActiveDepthTextureId());
|
||||||
|
|
||||||
|
GlScreenQuad.INSTANCE.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+146
@@ -0,0 +1,146 @@
|
|||||||
|
/*
|
||||||
|
* 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.test;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.postProcessing.apply.GlDhApplyShader;
|
||||||
|
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
|
||||||
|
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.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.core.render.RenderParams;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhTestTriangleRenderer;
|
||||||
|
import org.lwjgl.opengl.GL32;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders a UV colored quad
|
||||||
|
* to the center of the screen to confirm DH's
|
||||||
|
* apply shader is running correctly
|
||||||
|
*/
|
||||||
|
public class GlTestTriangleRenderer implements IDhTestTriangleRenderer
|
||||||
|
{
|
||||||
|
public 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;
|
||||||
|
|
||||||
|
public static final GlTestTriangleRenderer INSTANCE = new GlTestTriangleRenderer();
|
||||||
|
|
||||||
|
// Render a square with uv color
|
||||||
|
private static final float[] VERTICES =
|
||||||
|
{
|
||||||
|
// 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,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
GlShaderProgram basicShader;
|
||||||
|
GLVertexBuffer vbo;
|
||||||
|
GlAbstractVertexAttribute va;
|
||||||
|
boolean init = false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
private GlTestTriangleRenderer() { }
|
||||||
|
|
||||||
|
public void init()
|
||||||
|
{
|
||||||
|
if (this.init)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGGER.info("init");
|
||||||
|
this.init = true;
|
||||||
|
this.va = GlAbstractVertexAttribute.create();
|
||||||
|
this.va.bind();
|
||||||
|
// Pos
|
||||||
|
this.va.setVertexAttribute(0, 0, GlVertexPointer.addVec2Pointer(false));
|
||||||
|
// Color
|
||||||
|
this.va.setVertexAttribute(0, 1, GlVertexPointer.addVec4Pointer(false));
|
||||||
|
this.va.completeAndCheck(Float.BYTES * 6);
|
||||||
|
this.basicShader = new GlShaderProgram(
|
||||||
|
"assets/distanthorizons/shaders/test/gl/vert.vert",
|
||||||
|
"assets/distanthorizons/shaders/test/gl/frag.frag",
|
||||||
|
new String[]{"vPosition", "color"});
|
||||||
|
|
||||||
|
this.createBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createBuffer()
|
||||||
|
{
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocateDirect(VERTICES.length * Float.BYTES);
|
||||||
|
// Fill buffer with vertices.
|
||||||
|
buffer.order(ByteOrder.nativeOrder());
|
||||||
|
buffer.asFloatBuffer().put(VERTICES);
|
||||||
|
buffer.rewind();
|
||||||
|
|
||||||
|
this.vbo = new GLVertexBuffer(false);
|
||||||
|
this.vbo.bind();
|
||||||
|
this.vbo.uploadBuffer(buffer, 3, EDhApiGpuUploadMethod.DATA, VERTICES.length * Float.BYTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//========//
|
||||||
|
// render //
|
||||||
|
//========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(RenderParams renderParams)
|
||||||
|
{
|
||||||
|
this.init();
|
||||||
|
|
||||||
|
this.basicShader.bind();
|
||||||
|
this.va.bind();
|
||||||
|
|
||||||
|
this.vbo.bind();
|
||||||
|
this.va.bindBufferToAllBindingPoints(this.vbo.getId());
|
||||||
|
|
||||||
|
GL32.glDrawArrays(GL32.GL_TRIANGLES, 0, 3);
|
||||||
|
|
||||||
|
GlDhApplyShader.INSTANCE.render(renderParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+112
@@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* 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.util;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.glObject.shader.GlShaderProgram;
|
||||||
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
|
import com.seibel.distanthorizons.core.render.RenderParams;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||||
|
import org.lwjgl.opengl.GL32;
|
||||||
|
|
||||||
|
public abstract class GlAbstractShaderRenderer
|
||||||
|
{
|
||||||
|
protected static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
|
||||||
|
|
||||||
|
|
||||||
|
protected GlShaderProgram shader;
|
||||||
|
protected boolean init = false;
|
||||||
|
|
||||||
|
|
||||||
|
//=======//
|
||||||
|
// setup //
|
||||||
|
//=======//
|
||||||
|
//region
|
||||||
|
|
||||||
|
protected GlAbstractShaderRenderer() {}
|
||||||
|
|
||||||
|
public void init()
|
||||||
|
{
|
||||||
|
if (this.init) return;
|
||||||
|
this.init = true;
|
||||||
|
|
||||||
|
this.onInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
//==================//
|
||||||
|
// abstract methods //
|
||||||
|
//==================//
|
||||||
|
//region
|
||||||
|
|
||||||
|
protected void onInit() {}
|
||||||
|
|
||||||
|
protected void onApplyUniforms(RenderParams renderParams) {}
|
||||||
|
|
||||||
|
protected void onRender() {}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//===========//
|
||||||
|
// rendering //
|
||||||
|
//===========//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public void render(RenderParams renderParams)
|
||||||
|
{
|
||||||
|
this.init();
|
||||||
|
|
||||||
|
this.shader.bind();
|
||||||
|
|
||||||
|
this.onApplyUniforms(renderParams);
|
||||||
|
|
||||||
|
int width = MC_RENDER.getTargetFramebufferViewportWidth();
|
||||||
|
int height = MC_RENDER.getTargetFramebufferViewportHeight();
|
||||||
|
GL32.glViewport(0, 0, width, height);
|
||||||
|
|
||||||
|
this.onRender();
|
||||||
|
|
||||||
|
this.shader.unbind();
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// base overrides //
|
||||||
|
//================//
|
||||||
|
//region
|
||||||
|
|
||||||
|
public void free()
|
||||||
|
{
|
||||||
|
if (this.shader != null)
|
||||||
|
{
|
||||||
|
this.shader.free();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+110
@@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
* 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.util.vertexFormat;
|
||||||
|
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is used to represent a single vertex
|
||||||
|
* stored in GPU memory,
|
||||||
|
* <p>
|
||||||
|
* A (almost) exact copy of Minecraft's
|
||||||
|
* VertexFormat class, several methods
|
||||||
|
* were commented out since we didn't need them.
|
||||||
|
*
|
||||||
|
* @author James Seibel
|
||||||
|
* @version 12-9-2021
|
||||||
|
*/
|
||||||
|
public class GlLodVertexFormat
|
||||||
|
{
|
||||||
|
/** the format of data stored in the GPU buffers */
|
||||||
|
public static final GlLodVertexFormat DH_VERTEX_FORMAT = GlVertexFormats.POSITION_COLOR_BLOCK_LIGHT_SKY_LIGHT_MATERIAL_ID_NORMAL_INDEX;
|
||||||
|
|
||||||
|
|
||||||
|
private final ImmutableList<GlLodVertexFormatElement> elements;
|
||||||
|
private final IntList offsets = new IntArrayList();
|
||||||
|
private final int byteSize;
|
||||||
|
|
||||||
|
public GlLodVertexFormat(ImmutableList<GlLodVertexFormatElement> elementList)
|
||||||
|
{
|
||||||
|
this.elements = elementList;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
for (GlLodVertexFormatElement LodVertexFormatElement : elementList)
|
||||||
|
{
|
||||||
|
this.offsets.add(i);
|
||||||
|
i += LodVertexFormatElement.getByteSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.byteSize = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getByteSize()
|
||||||
|
{
|
||||||
|
return this.byteSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImmutableList<GlLodVertexFormatElement> getElements()
|
||||||
|
{
|
||||||
|
return this.elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Forge added method
|
||||||
|
public int getOffset(int index)
|
||||||
|
{
|
||||||
|
return offsets.getInt(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() { return "format: " + this.elements.size() + " elements: " + this.elements.stream().map(Object::toString).collect(Collectors.joining(" ")); }
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj)
|
||||||
|
{
|
||||||
|
if (this == obj)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (obj != null && this.getClass() == obj.getClass())
|
||||||
|
{
|
||||||
|
GlLodVertexFormat vertexFormat = (GlLodVertexFormat) obj;
|
||||||
|
return this.byteSize == vertexFormat.byteSize && this.elements.equals(vertexFormat.elements);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() { return this.elements.hashCode(); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+168
@@ -0,0 +1,168 @@
|
|||||||
|
/*
|
||||||
|
* 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.util.vertexFormat;
|
||||||
|
|
||||||
|
import org.lwjgl.opengl.GL32;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This object is used to build LodVertexFormats.
|
||||||
|
* <p>
|
||||||
|
* A (almost) exact copy of Minecraft's
|
||||||
|
* VertexFormatElement class. <br>
|
||||||
|
* A number of things were removed from the original
|
||||||
|
* object since we didn't need them, specifically "usage".
|
||||||
|
*
|
||||||
|
* @author James Seibel
|
||||||
|
* @version 11-13-2021
|
||||||
|
*/
|
||||||
|
public class GlLodVertexFormatElement
|
||||||
|
{
|
||||||
|
private final GlLodVertexFormatElement.DataType dataType;
|
||||||
|
/** James isn't sure what index is for */
|
||||||
|
private final int index;
|
||||||
|
private final int count;
|
||||||
|
private final int byteSize;
|
||||||
|
private final boolean isPadding;
|
||||||
|
|
||||||
|
public GlLodVertexFormatElement(int newIndex, GlLodVertexFormatElement.DataType newType, int newCount, boolean isPadding)
|
||||||
|
{
|
||||||
|
this.dataType = newType;
|
||||||
|
this.index = newIndex;
|
||||||
|
this.count = newCount;
|
||||||
|
this.byteSize = newType.getSize() * this.count;
|
||||||
|
this.isPadding = isPadding;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final boolean getIsPadding()
|
||||||
|
{
|
||||||
|
return isPadding;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final GlLodVertexFormatElement.DataType getType()
|
||||||
|
{
|
||||||
|
return this.dataType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final int getIndex()
|
||||||
|
{
|
||||||
|
return this.index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final int getByteSize()
|
||||||
|
{
|
||||||
|
return this.byteSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
// added by Forge
|
||||||
|
public int getElementCount()
|
||||||
|
{
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public enum DataType
|
||||||
|
{
|
||||||
|
FLOAT(4, "Float", GL32.GL_FLOAT),
|
||||||
|
UBYTE(1, "Unsigned Byte", GL32.GL_UNSIGNED_BYTE),
|
||||||
|
BYTE(1, "Byte", GL32.GL_BYTE),
|
||||||
|
USHORT(2, "Unsigned Short", GL32.GL_UNSIGNED_SHORT),
|
||||||
|
SHORT(2, "Short", GL32.GL_SHORT),
|
||||||
|
UINT(4, "Unsigned Int", GL32.GL_UNSIGNED_INT),
|
||||||
|
INT(4, "Int", GL32.GL_INT);
|
||||||
|
|
||||||
|
private final int size;
|
||||||
|
private final String name;
|
||||||
|
private final int glType;
|
||||||
|
|
||||||
|
DataType(int sizeInBytes, String newName, int openGlDataType)
|
||||||
|
{
|
||||||
|
this.size = sizeInBytes;
|
||||||
|
this.name = newName;
|
||||||
|
this.glType = openGlDataType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSize()
|
||||||
|
{
|
||||||
|
return this.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName()
|
||||||
|
{
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getGlType()
|
||||||
|
{
|
||||||
|
return this.glType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode()
|
||||||
|
{
|
||||||
|
int i = this.dataType.hashCode();
|
||||||
|
i = 31 * i + this.index;
|
||||||
|
return 31 * i + this.count;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return this.count + "," + this.dataType.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj)
|
||||||
|
{
|
||||||
|
if (this == obj)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (obj != null && this.getClass() == obj.getClass())
|
||||||
|
{
|
||||||
|
GlLodVertexFormatElement LodVertexFormatElement = (GlLodVertexFormatElement) obj;
|
||||||
|
if (this.count != LodVertexFormatElement.count)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (this.index != LodVertexFormatElement.index)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (this.dataType != LodVertexFormatElement.dataType)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+50
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* 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.util.vertexFormat;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A (almost) exact copy of MC's
|
||||||
|
* DefaultVertexFormats class.
|
||||||
|
*/
|
||||||
|
public class GlVertexFormats
|
||||||
|
{
|
||||||
|
public static final GlLodVertexFormatElement ELEMENT_POSITION = new GlLodVertexFormatElement(3, GlLodVertexFormatElement.DataType.USHORT, 3, false);
|
||||||
|
public static final GlLodVertexFormatElement ELEMENT_COLOR = new GlLodVertexFormatElement(0, GlLodVertexFormatElement.DataType.UBYTE, 4, false);
|
||||||
|
public static final GlLodVertexFormatElement ELEMENT_BYTE_PADDING = new GlLodVertexFormatElement(0, GlLodVertexFormatElement.DataType.BYTE, 1, true);
|
||||||
|
|
||||||
|
public static final GlLodVertexFormatElement ELEMENT_LIGHT = new GlLodVertexFormatElement(0, GlLodVertexFormatElement.DataType.UBYTE, 1, false);
|
||||||
|
public static final GlLodVertexFormatElement ELEMENT_IRIS_MATERIAL_INDEX = new GlLodVertexFormatElement(0, GlLodVertexFormatElement.DataType.BYTE, 1, false);
|
||||||
|
public static final GlLodVertexFormatElement ELEMENT_IRIS_NORMAL_INDEX = new GlLodVertexFormatElement(0, GlLodVertexFormatElement.DataType.BYTE, 1, false);
|
||||||
|
|
||||||
|
|
||||||
|
public static final GlLodVertexFormat POSITION_COLOR_BLOCK_LIGHT_SKY_LIGHT_MATERIAL_ID_NORMAL_INDEX = new GlLodVertexFormat(ImmutableList.<GlLodVertexFormatElement>builder()
|
||||||
|
.add(ELEMENT_POSITION)
|
||||||
|
.add(ELEMENT_BYTE_PADDING)
|
||||||
|
.add(ELEMENT_LIGHT)
|
||||||
|
.add(ELEMENT_COLOR)
|
||||||
|
.add(ELEMENT_IRIS_MATERIAL_INDEX)
|
||||||
|
.add(ELEMENT_IRIS_NORMAL_INDEX)
|
||||||
|
.add(ELEMENT_BYTE_PADDING)
|
||||||
|
.add(ELEMENT_BYTE_PADDING) // padding is to make sure the format is a multiple of 4
|
||||||
|
.build());
|
||||||
|
|
||||||
|
}
|
||||||
+50
-9
@@ -19,12 +19,19 @@
|
|||||||
|
|
||||||
package com.seibel.distanthorizons.common.wrappers;
|
package com.seibel.distanthorizons.common.wrappers;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderApi;
|
||||||
|
import com.seibel.distanthorizons.api.interfaces.render.IDhApiCustomRenderObjectFactory;
|
||||||
|
import com.seibel.distanthorizons.common.render.blaze.BlazeDhRenderApiDefinition;
|
||||||
|
import com.seibel.distanthorizons.common.render.openGl.GlDhRenderApiDefinition;
|
||||||
|
import com.seibel.distanthorizons.core.config.Config;
|
||||||
|
import com.seibel.distanthorizons.core.render.renderer.GenericRenderObjectFactory;
|
||||||
import com.seibel.distanthorizons.common.wrappers.gui.ClassicConfigGUI;
|
import com.seibel.distanthorizons.common.wrappers.gui.ClassicConfigGUI;
|
||||||
import com.seibel.distanthorizons.common.wrappers.gui.LangWrapper;
|
import com.seibel.distanthorizons.common.wrappers.gui.LangWrapper;
|
||||||
import com.seibel.distanthorizons.common.wrappers.level.KeyedClientLevelManager;
|
import com.seibel.distanthorizons.common.wrappers.level.KeyedClientLevelManager;
|
||||||
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftServerWrapper;
|
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftServerWrapper;
|
||||||
import com.seibel.distanthorizons.core.level.IKeyedClientLevelManager;
|
import com.seibel.distanthorizons.core.level.IKeyedClientLevelManager;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.config.IConfigGui;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.config.IConfigGui;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.config.ILangWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.config.ILangWrapper;
|
||||||
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftClientWrapper;
|
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftClientWrapper;
|
||||||
@@ -33,9 +40,9 @@ import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
|||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftGLWrapper;
|
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Binds all necessary dependencies, so we
|
* Binds all necessary dependencies, so we
|
||||||
@@ -49,6 +56,9 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftSha
|
|||||||
*/
|
*/
|
||||||
public class DependencySetup
|
public class DependencySetup
|
||||||
{
|
{
|
||||||
|
protected static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static void createSharedBindings()
|
public static void createSharedBindings()
|
||||||
{
|
{
|
||||||
@@ -56,23 +66,54 @@ public class DependencySetup
|
|||||||
SingletonInjector.INSTANCE.bind(IVersionConstants.class, VersionConstants.INSTANCE);
|
SingletonInjector.INSTANCE.bind(IVersionConstants.class, VersionConstants.INSTANCE);
|
||||||
SingletonInjector.INSTANCE.bind(IWrapperFactory.class, WrapperFactory.INSTANCE);
|
SingletonInjector.INSTANCE.bind(IWrapperFactory.class, WrapperFactory.INSTANCE);
|
||||||
SingletonInjector.INSTANCE.bind(IKeyedClientLevelManager.class, KeyedClientLevelManager.INSTANCE);
|
SingletonInjector.INSTANCE.bind(IKeyedClientLevelManager.class, KeyedClientLevelManager.INSTANCE);
|
||||||
DependencySetupDoneCheck.isDone = true;
|
SingletonInjector.INSTANCE.bind(IDhApiCustomRenderObjectFactory.class, GenericRenderObjectFactory.INSTANCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
//@Environment(EnvType.SERVER)
|
|
||||||
public static void createServerBindings()
|
public static void createServerBindings()
|
||||||
{
|
{ SingletonInjector.INSTANCE.bind(IMinecraftSharedWrapper.class, MinecraftServerWrapper.INSTANCE); }
|
||||||
SingletonInjector.INSTANCE.bind(IMinecraftSharedWrapper.class, MinecraftServerWrapper.INSTANCE);
|
|
||||||
}
|
|
||||||
|
|
||||||
//@Environment(EnvType.CLIENT)
|
|
||||||
public static void createClientBindings()
|
public static void createClientBindings()
|
||||||
{
|
{
|
||||||
SingletonInjector.INSTANCE.bind(IMinecraftClientWrapper.class, MinecraftClientWrapper.INSTANCE);
|
SingletonInjector.INSTANCE.bind(IMinecraftClientWrapper.class, MinecraftClientWrapper.INSTANCE);
|
||||||
SingletonInjector.INSTANCE.bind(IMinecraftSharedWrapper.class, MinecraftClientWrapper.INSTANCE);
|
SingletonInjector.INSTANCE.bind(IMinecraftSharedWrapper.class, MinecraftClientWrapper.INSTANCE);
|
||||||
SingletonInjector.INSTANCE.bind(IMinecraftRenderWrapper.class, MinecraftRenderWrapper.INSTANCE);
|
SingletonInjector.INSTANCE.bind(IMinecraftRenderWrapper.class, MinecraftRenderWrapper.INSTANCE);
|
||||||
SingletonInjector.INSTANCE.bind(IMinecraftGLWrapper.class, MinecraftGLWrapper.INSTANCE);
|
|
||||||
SingletonInjector.INSTANCE.bind(IConfigGui.class, ClassicConfigGUI.CONFIG_CORE_INTERFACE);
|
SingletonInjector.INSTANCE.bind(IConfigGui.class, ClassicConfigGUI.CONFIG_CORE_INTERFACE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void setRenderingApiBindings()
|
||||||
|
{
|
||||||
|
EDhApiRenderApi renderingApiEnum = Config.Client.Advanced.Graphics.Experimental.renderingApi.get();
|
||||||
|
if (renderingApiEnum == EDhApiRenderApi.AUTO)
|
||||||
|
{
|
||||||
|
#if MC_VER < MC_1_21_11
|
||||||
|
renderingApiEnum = EDhApiRenderApi.OPEN_GL;
|
||||||
|
#else
|
||||||
|
renderingApiEnum = EDhApiRenderApi.BLAZE_3D;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGGER.info("Setting DH Rendering API to: ["+renderingApiEnum+"].");
|
||||||
|
|
||||||
|
AbstractDhRenderApiDefinition renderDefinition;
|
||||||
|
if (renderingApiEnum == EDhApiRenderApi.OPEN_GL)
|
||||||
|
{
|
||||||
|
renderDefinition = new GlDhRenderApiDefinition();
|
||||||
|
}
|
||||||
|
else if (renderingApiEnum == EDhApiRenderApi.BLAZE_3D)
|
||||||
|
{
|
||||||
|
#if MC_VER <= MC_1_21_10
|
||||||
|
throw new IllegalStateException("["+renderingApiEnum+"] is not supported on this version of Minecraft.");
|
||||||
|
#else
|
||||||
|
renderDefinition = new BlazeDhRenderApiDefinition();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("No ["+ AbstractDhRenderApiDefinition.class.getSimpleName()+"] concrete implementation found for the value: ["+renderingApiEnum+"].");
|
||||||
|
}
|
||||||
|
renderDefinition.bindRenderers();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-3
@@ -46,10 +46,11 @@ public class McObjectConverter
|
|||||||
|
|
||||||
|
|
||||||
/** 4x4 float matrix converter */
|
/** 4x4 float matrix converter */
|
||||||
@Deprecated
|
|
||||||
public static Mat4f Convert(
|
public static Mat4f Convert(
|
||||||
#if MC_VER < MC_1_19_4 com.mojang.math.Matrix4f
|
#if MC_VER < MC_1_19_4 com.mojang.math.Matrix4f
|
||||||
#else org.joml.Matrix4f #endif
|
#elif MC_VER < MC_1_21_6 org.joml.Matrix4f
|
||||||
|
#else org.joml.Matrix4fc
|
||||||
|
#endif
|
||||||
mcMatrix)
|
mcMatrix)
|
||||||
{
|
{
|
||||||
FloatBuffer buffer = FloatBuffer.allocate(16);
|
FloatBuffer buffer = FloatBuffer.allocate(16);
|
||||||
@@ -63,7 +64,9 @@ public class McObjectConverter
|
|||||||
/** Taken from Minecraft's com.mojang.math.Matrix4f class from 1.18.2 */
|
/** Taken from Minecraft's com.mojang.math.Matrix4f class from 1.18.2 */
|
||||||
private static void storeMatrix(
|
private static void storeMatrix(
|
||||||
#if MC_VER < MC_1_19_4 com.mojang.math.Matrix4f
|
#if MC_VER < MC_1_19_4 com.mojang.math.Matrix4f
|
||||||
#else org.joml.Matrix4f #endif
|
#elif MC_VER < MC_1_21_6 org.joml.Matrix4f
|
||||||
|
#else org.joml.Matrix4fc
|
||||||
|
#endif
|
||||||
matrix,
|
matrix,
|
||||||
FloatBuffer buffer)
|
FloatBuffer buffer)
|
||||||
{
|
{
|
||||||
|
|||||||
+41
-8
@@ -19,22 +19,30 @@
|
|||||||
|
|
||||||
package com.seibel.distanthorizons.common.wrappers;
|
package com.seibel.distanthorizons.common.wrappers;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderApi;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants;
|
||||||
|
|
||||||
/**
|
|
||||||
* @author James Seibel
|
|
||||||
* @version 12-11-2021
|
|
||||||
*/
|
|
||||||
public class VersionConstants implements IVersionConstants
|
public class VersionConstants implements IVersionConstants
|
||||||
{
|
{
|
||||||
public static final VersionConstants INSTANCE = new VersionConstants();
|
public static final VersionConstants INSTANCE = new VersionConstants();
|
||||||
|
|
||||||
|
|
||||||
private VersionConstants()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
|
private VersionConstants() { }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=========//
|
||||||
|
// methods //
|
||||||
|
//=========//
|
||||||
|
//region
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getMinecraftVersion()
|
public String getMinecraftVersion()
|
||||||
@@ -74,10 +82,35 @@ public class VersionConstants implements IVersionConstants
|
|||||||
return "1.21.4";
|
return "1.21.4";
|
||||||
#elif MC_VER == MC_1_21_5
|
#elif MC_VER == MC_1_21_5
|
||||||
return "1.21.5";
|
return "1.21.5";
|
||||||
|
#elif MC_VER == MC_1_21_6
|
||||||
|
return "1.21.6";
|
||||||
|
#elif MC_VER == MC_1_21_8
|
||||||
|
return "1.21.8";
|
||||||
|
|
||||||
|
#elif MC_VER == MC_1_21_9
|
||||||
|
return "1.21.9";
|
||||||
|
#elif MC_VER == MC_1_21_10
|
||||||
|
return "1.21.10";
|
||||||
|
#elif MC_VER == MC_1_21_11
|
||||||
|
return "1.21.11";
|
||||||
#else
|
#else
|
||||||
ERROR MC version constant missing
|
ERROR MC version constant missing
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EDhApiRenderApi getDefaultRenderingApi()
|
||||||
|
{
|
||||||
|
#if MC_VER <= MC_1_21_11
|
||||||
|
return EDhApiRenderApi.OPEN_GL;
|
||||||
|
#else
|
||||||
|
ERROR MC version constant missing
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
+51
-7
@@ -30,28 +30,33 @@ import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
|||||||
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
|
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
|
||||||
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
|
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
|
||||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||||
|
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||||
import com.seibel.distanthorizons.core.level.IDhLevel;
|
import com.seibel.distanthorizons.core.level.IDhLevel;
|
||||||
import com.seibel.distanthorizons.core.level.IDhServerLevel;
|
import com.seibel.distanthorizons.core.level.IDhServerLevel;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IDhGenericObjectVertexBufferContainer;
|
||||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.ILodContainerUniformBufferWrapper;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhGenericRenderer;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IVertexBufferWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.worldGeneration.AbstractBatchGenerationEnvironmentWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.worldGeneration.IBatchGeneratorEnvironmentWrapper;
|
||||||
|
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||||
import net.minecraft.client.multiplayer.ClientLevel;
|
import net.minecraft.client.multiplayer.ClientLevel;
|
||||||
#if MC_VER > MC_1_17_1
|
#if MC_VER > MC_1_17_1
|
||||||
import net.minecraft.core.Holder;
|
import net.minecraft.core.Holder;
|
||||||
#endif
|
#endif
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.level.LevelReader;
|
|
||||||
import net.minecraft.world.level.biome.Biome;
|
import net.minecraft.world.level.biome.Biome;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.HashSet;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This handles creating abstract wrapper objects.
|
* This handles creating abstract wrapper objects.
|
||||||
@@ -62,12 +67,35 @@ public class WrapperFactory implements IWrapperFactory
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=====================//
|
||||||
|
// internal properties //
|
||||||
|
//=====================//
|
||||||
|
//region
|
||||||
|
|
||||||
|
private AbstractDhRenderApiDefinition renderDefinition;
|
||||||
|
private AbstractDhRenderApiDefinition getRenderDefinition()
|
||||||
|
{
|
||||||
|
// delayed get to make sure we don't accidentally set the variable before it's bound
|
||||||
|
if (this.renderDefinition != null)
|
||||||
|
{
|
||||||
|
return this.renderDefinition;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.renderDefinition = SingletonInjector.INSTANCE.get(AbstractDhRenderApiDefinition.class);
|
||||||
|
return this.renderDefinition;
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//==============//
|
//==============//
|
||||||
// core methods //
|
// core methods //
|
||||||
//==============//
|
//==============//
|
||||||
|
//region
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AbstractBatchGenerationEnvironmentWrapper createBatchGenerator(IDhLevel targetLevel)
|
public IBatchGeneratorEnvironmentWrapper createBatchGenerator(IDhLevel targetLevel)
|
||||||
{
|
{
|
||||||
if (targetLevel instanceof IDhServerLevel)
|
if (targetLevel instanceof IDhServerLevel)
|
||||||
{
|
{
|
||||||
@@ -103,7 +131,7 @@ public class WrapperFactory implements IWrapperFactory
|
|||||||
@Override
|
@Override
|
||||||
public IBiomeWrapper deserializeBiomeWrapper(String str, ILevelWrapper levelWrapper) throws IOException { return BiomeWrapper.deserialize(str, levelWrapper); }
|
public IBiomeWrapper deserializeBiomeWrapper(String str, ILevelWrapper levelWrapper) throws IOException { return BiomeWrapper.deserialize(str, levelWrapper); }
|
||||||
@Override
|
@Override
|
||||||
public IBiomeWrapper getPlainsBiomeWrapper(ILevelWrapper levelWrapper) // TODO is there a way we could get this without the levelWrapper? it isn't necessary but would clean up the code a bit
|
public IBiomeWrapper getPlainsBiomeWrapper(ILevelWrapper levelWrapper)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -121,9 +149,9 @@ public class WrapperFactory implements IWrapperFactory
|
|||||||
public IBlockStateWrapper getAirBlockStateWrapper() { return BlockStateWrapper.AIR; }
|
public IBlockStateWrapper getAirBlockStateWrapper() { return BlockStateWrapper.AIR; }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public HashSet<IBlockStateWrapper> getRendererIgnoredBlocks(ILevelWrapper levelWrapper) { return BlockStateWrapper.getRendererIgnoredBlocks(levelWrapper); }
|
public ObjectOpenHashSet<IBlockStateWrapper> getRendererIgnoredBlocks(ILevelWrapper levelWrapper) { return BlockStateWrapper.getRendererIgnoredBlocks(levelWrapper); }
|
||||||
@Override
|
@Override
|
||||||
public HashSet<IBlockStateWrapper> getRendererIgnoredCaveBlocks(ILevelWrapper levelWrapper) { return BlockStateWrapper.getRendererIgnoredCaveBlocks(levelWrapper); }
|
public ObjectOpenHashSet<IBlockStateWrapper> getRendererIgnoredCaveBlocks(ILevelWrapper levelWrapper) { return BlockStateWrapper.getRendererIgnoredCaveBlocks(levelWrapper); }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void resetRendererIgnoredCaveBlocks() { BlockStateWrapper.clearRendererIgnoredCaveBlocks(); }
|
public void resetRendererIgnoredCaveBlocks() { BlockStateWrapper.clearRendererIgnoredCaveBlocks(); }
|
||||||
@@ -211,10 +239,19 @@ public class WrapperFactory implements IWrapperFactory
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override public IVertexBufferWrapper createVboWrapper(String name) { return this.getRenderDefinition().createVboWrapper(name); }
|
||||||
|
@Override public ILodContainerUniformBufferWrapper createLodContainerUniformWrapper() { return this.getRenderDefinition().createLodContainerUniformWrapper(); }
|
||||||
|
@Override public IDhGenericObjectVertexBufferContainer createGenericObjectVboContainer() { return this.getRenderDefinition().createGenericVboContainer(); }
|
||||||
|
@Override public IDhGenericRenderer createGenericRenderer() { return this.getRenderDefinition().createGenericRenderer(); }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//=============//
|
//=============//
|
||||||
// api methods //
|
// api methods //
|
||||||
//=============//
|
//=============//
|
||||||
|
//region
|
||||||
|
|
||||||
// documentation should be in the API interface
|
// documentation should be in the API interface
|
||||||
|
|
||||||
@@ -313,12 +350,15 @@ public class WrapperFactory implements IWrapperFactory
|
|||||||
return createWrapperErrorMessage("BlockState wrapper", expectedClassNames, objectArray);
|
return createWrapperErrorMessage("BlockState wrapper", expectedClassNames, objectArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//================//
|
//================//
|
||||||
// helper methods //
|
// helper methods //
|
||||||
//================//
|
//================//
|
||||||
|
//region
|
||||||
|
|
||||||
private static String createWrapperErrorMessage(String wrapperName, String[] expectedClassNames, Object[] objectArray)
|
private static String createWrapperErrorMessage(String wrapperName, String[] expectedClassNames, Object[] objectArray)
|
||||||
{
|
{
|
||||||
@@ -354,4 +394,8 @@ public class WrapperFactory implements IWrapperFactory
|
|||||||
return message.toString();
|
return message.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+337
@@ -0,0 +1,337 @@
|
|||||||
|
package com.seibel.distanthorizons.common.wrappers.block;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.core.config.Config;
|
||||||
|
import com.seibel.distanthorizons.core.dataObjects.BlockBiomeWrapperPair;
|
||||||
|
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
|
import com.seibel.distanthorizons.core.pos.DhSectionPos;
|
||||||
|
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPosMutable;
|
||||||
|
import com.seibel.distanthorizons.core.util.ColorUtil;
|
||||||
|
import com.seibel.distanthorizons.core.util.FullDataPointUtil;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||||
|
import it.unimi.dsi.fastutil.longs.LongArrayList;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.multiplayer.ClientLevel;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.world.level.BlockAndTintGetter;
|
||||||
|
import net.minecraft.world.level.ColorResolver;
|
||||||
|
import net.minecraft.world.level.biome.Biome;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
#if MC_VER >= MC_1_18_2
|
||||||
|
import net.minecraft.core.Holder;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
public abstract class AbstractDhTintGetter implements BlockAndTintGetter
|
||||||
|
{
|
||||||
|
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
|
|
||||||
|
#if MC_VER < MC_1_18_2
|
||||||
|
private static final ConcurrentHashMap<String, Biome> BIOME_BY_RESOURCE_STRING = new ConcurrentHashMap<>();
|
||||||
|
#else
|
||||||
|
private static final ConcurrentHashMap<String, Holder<Biome>> BIOME_BY_RESOURCE_STRING = new ConcurrentHashMap<>();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private static final ConcurrentHashMap<BlockBiomeWrapperPair, Integer> COLOR_BY_BLOCK_BIOME_PAIR = new ConcurrentHashMap<>();
|
||||||
|
/** returned if the color cache is incomplete */
|
||||||
|
public static final int INVALID_COLOR = Integer.MIN_VALUE;
|
||||||
|
|
||||||
|
|
||||||
|
protected BiomeWrapper biomeWrapper;
|
||||||
|
protected BlockStateWrapper blockStateWrapper;
|
||||||
|
protected FullDataSourceV2 fullDataSource;
|
||||||
|
protected int smoothingRadiusInBlocks;
|
||||||
|
protected IClientLevelWrapper clientLevelWrapper;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============//
|
||||||
|
// constructor //
|
||||||
|
//=============//
|
||||||
|
|
||||||
|
public AbstractDhTintGetter() { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mutates this getter so we can access the necessary
|
||||||
|
* variables for tint getting.
|
||||||
|
*/
|
||||||
|
public void update(BiomeWrapper biomeWrapper, BlockStateWrapper blockStateWrapper, FullDataSourceV2 fullDataSource, IClientLevelWrapper clientLevelWrapper)
|
||||||
|
{
|
||||||
|
this.biomeWrapper = biomeWrapper;
|
||||||
|
this.blockStateWrapper = blockStateWrapper;
|
||||||
|
this.fullDataSource = fullDataSource;
|
||||||
|
this.clientLevelWrapper = clientLevelWrapper;
|
||||||
|
this.smoothingRadiusInBlocks = Config.Client.Advanced.Graphics.Quality.lodBiomeBlending.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// shared methods //
|
||||||
|
//================//
|
||||||
|
|
||||||
|
/** Called by MC's tint getter */
|
||||||
|
@Override
|
||||||
|
public int getBlockTint(@NotNull BlockPos blockPos, @NotNull ColorResolver colorResolver)
|
||||||
|
{
|
||||||
|
DhBlockPosMutable mutableBlockPos = new DhBlockPosMutable(blockPos.getX(), blockPos.getY(), blockPos.getZ());
|
||||||
|
return this.tryGetBlockTint(mutableBlockPos, colorResolver);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Can be called by DH directly, skipping some of MC's logic
|
||||||
|
* to speed up tint getting slightly.
|
||||||
|
*
|
||||||
|
* @return {@link AbstractDhTintGetter#INVALID_COLOR} if any of the biomes needed for this position
|
||||||
|
* were not cached. In that case calling {@link AbstractDhTintGetter#getBlockTint(BlockPos, ColorResolver)}
|
||||||
|
* will need to be called by MC's ColorResolver so we can
|
||||||
|
* populate the color cache.
|
||||||
|
*/
|
||||||
|
public int tryGetBlockTint(DhBlockPosMutable mutableBlockPos)
|
||||||
|
{ return this.tryGetBlockTint(mutableBlockPos, null); }
|
||||||
|
|
||||||
|
private int tryGetBlockTint(DhBlockPosMutable mutableBlockPos, @Nullable ColorResolver colorResolver)
|
||||||
|
{
|
||||||
|
// determine how wide this data source is so we can determine
|
||||||
|
// if blending should be used
|
||||||
|
byte dataSourceDetailLevel = DhSectionPos.getDetailLevel(this.fullDataSource.getPos());
|
||||||
|
// convert from section detail level to absolute detail level
|
||||||
|
dataSourceDetailLevel = (byte)(dataSourceDetailLevel - DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL);
|
||||||
|
int dataSourceLodWidthInBlocks = DhSectionPos.getDetailLevelWidthInBlocks(dataSourceDetailLevel);
|
||||||
|
|
||||||
|
// don't do any smoothing if smoothing is disabled or if the LOD
|
||||||
|
// is to large for block-based smoothing to show up
|
||||||
|
if (this.smoothingRadiusInBlocks == 0
|
||||||
|
|| dataSourceLodWidthInBlocks > this.smoothingRadiusInBlocks)
|
||||||
|
{
|
||||||
|
return this.tryGetClientBiomeColor(colorResolver, this.biomeWrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// use a rolling average to calculate the color
|
||||||
|
int dataPointCount = 0;
|
||||||
|
int rollingRed = 0;
|
||||||
|
int rollingGreen = 0;
|
||||||
|
int rollingBlue = 0;
|
||||||
|
|
||||||
|
int xMin = mutableBlockPos.getX() - this.smoothingRadiusInBlocks;
|
||||||
|
int xMax = mutableBlockPos.getX() + this.smoothingRadiusInBlocks + 1; // +1 to account for the center block
|
||||||
|
|
||||||
|
int zMin = mutableBlockPos.getZ() - this.smoothingRadiusInBlocks;
|
||||||
|
int zMax = mutableBlockPos.getZ() + this.smoothingRadiusInBlocks + 1;
|
||||||
|
|
||||||
|
int levelMinY = this.clientLevelWrapper.getMinHeight();
|
||||||
|
|
||||||
|
for (int x = xMin; x < xMax; x++)
|
||||||
|
{
|
||||||
|
for (int z = zMin; z < zMax; z++)
|
||||||
|
{
|
||||||
|
mutableBlockPos.setX(x);
|
||||||
|
mutableBlockPos.setZ(z);
|
||||||
|
|
||||||
|
// this can return the same position/datapoint for larger LODs duplicating work,
|
||||||
|
// however for small smoothing ranges that isn't a big deal and for large LODs
|
||||||
|
// we ignore smoothing anyway
|
||||||
|
long dataPoint = this.fullDataSource.getDataPointAtBlockPos(mutableBlockPos.getX(), mutableBlockPos.getY(), mutableBlockPos.getZ(), levelMinY);
|
||||||
|
if (dataPoint == FullDataPointUtil.EMPTY_DATA_POINT)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// get the color for this nearby position
|
||||||
|
int id = FullDataPointUtil.getId(dataPoint);
|
||||||
|
BiomeWrapper biomeWrapper = (BiomeWrapper) this.fullDataSource.mapping.getBiomeWrapper(id);
|
||||||
|
int color = this.tryGetClientBiomeColor(colorResolver, biomeWrapper);
|
||||||
|
if (color == INVALID_COLOR)
|
||||||
|
{
|
||||||
|
return INVALID_COLOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// rolling average
|
||||||
|
rollingRed += ColorUtil.getRed(color);
|
||||||
|
rollingGreen += ColorUtil.getGreen(color);
|
||||||
|
rollingBlue += ColorUtil.getBlue(color);
|
||||||
|
|
||||||
|
dataPointCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// if no data was present (rarely possible)
|
||||||
|
// just use the default center's color
|
||||||
|
if (dataPointCount == 0)
|
||||||
|
{
|
||||||
|
return this.tryGetClientBiomeColor(colorResolver, this.biomeWrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
int colorInt = ColorUtil.argbToInt(
|
||||||
|
255, // blending often ignores alpha, having it always 255 prevents multiplication issues later
|
||||||
|
rollingRed / dataPointCount,
|
||||||
|
rollingGreen / dataPointCount,
|
||||||
|
rollingBlue / dataPointCount);
|
||||||
|
return colorInt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If given a ColorResolver this will always succeed. <Br>
|
||||||
|
* If not it will attempt to use the cached color.
|
||||||
|
*/
|
||||||
|
private int tryGetClientBiomeColor(@Nullable ColorResolver colorResolver, BiomeWrapper biomeWrapper)
|
||||||
|
{
|
||||||
|
BlockBiomeWrapperPair pair = BlockBiomeWrapperPair.get(this.blockStateWrapper, biomeWrapper);
|
||||||
|
|
||||||
|
// use the cached color if possible
|
||||||
|
Integer cachedColor = COLOR_BY_BLOCK_BIOME_PAIR.get(pair); // explicit Integer return here reduces unnecessary allocations
|
||||||
|
if (cachedColor != null)
|
||||||
|
{
|
||||||
|
return cachedColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (colorResolver == null)
|
||||||
|
{
|
||||||
|
// no color resolver is present,
|
||||||
|
// the cache needs to be populated before
|
||||||
|
// we can use the fast path
|
||||||
|
return INVALID_COLOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int color = colorResolver.getColor(unwrapClientBiome(biomeWrapper), 0, 0);
|
||||||
|
COLOR_BY_BLOCK_BIOME_PAIR.put(pair, color);
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static Biome unwrapClientBiome(BiomeWrapper biomeWrapper)
|
||||||
|
{
|
||||||
|
String biomeString = biomeWrapper.getSerialString();
|
||||||
|
if (biomeString == null
|
||||||
|
|| biomeString.isEmpty()
|
||||||
|
|| biomeString.equals(BiomeWrapper.EMPTY_BIOME_STRING))
|
||||||
|
{
|
||||||
|
// default to "plains" for empty/invalid biomes
|
||||||
|
biomeString = "minecraft:plains";
|
||||||
|
}
|
||||||
|
|
||||||
|
return unwrapBiome(getClientBiome(biomeString));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static Biome unwrapBiome(#if MC_VER >= MC_1_18_2 Holder<Biome> #else Biome #endif biome)
|
||||||
|
{
|
||||||
|
#if MC_VER >= MC_1_18_2
|
||||||
|
return biome.value();
|
||||||
|
#else
|
||||||
|
return biome;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Previously, this class might have immediately unwrapped the Holder like this:</p>
|
||||||
|
* <pre>{@code
|
||||||
|
* // Inside constructor (OLD WAY - PROBLEMATIC):
|
||||||
|
* Holder<Biome> biomeHolder = getTheHolderFromSomewhere();
|
||||||
|
* this.biome = biomeHolder.value(); // <-- PROBLEM HERE
|
||||||
|
* }</pre>
|
||||||
|
*
|
||||||
|
* <p>This approach is problematic because the {@link net.minecraft.core.Holder} system,
|
||||||
|
* particularly {@code Holder.Reference}, is designed for <strong>late binding</strong>. Here's why storing
|
||||||
|
* the Holder itself is now necessary:</p>
|
||||||
|
* <ol>
|
||||||
|
* <li>A {@code Holder.Reference<Biome>} might be created initially just with a
|
||||||
|
* {@link net.minecraft.resources.ResourceKey} (like {@code minecraft:plains}), but its actual
|
||||||
|
* {@link net.minecraft.core.Holder#value() value()} (the {@code Biome} object itself) might be {@code null}
|
||||||
|
* at construction time.</li>
|
||||||
|
* <li>Later, during game loading, registry population, or potentially due to modifications by other mods
|
||||||
|
* (e.g., Polytone), the system calls internal binding methods (like {@code bindValue(Biome)})
|
||||||
|
* on the {@code Holder} instance. This sets or <strong>updates</strong> the internal reference to the
|
||||||
|
* actual {@code Biome} object.</li>
|
||||||
|
* <li>Crucially, the binding process might assign a completely <strong>new</strong> {@code Biome} object
|
||||||
|
* instance to the {@code Holder} reference, replacing any previous one.</li>
|
||||||
|
* </ol>
|
||||||
|
*
|
||||||
|
* <p>If we unwrapped the {@code Holder} using {@code .value()} within the constructor (the old way),
|
||||||
|
* our class's internal {@code biome} field would permanently store a reference to whatever {@code Biome}
|
||||||
|
* object the {@code Holder} pointed to *at that exact moment*. It would have no link back to the
|
||||||
|
* {@code Holder} and would be unaware if the {@code Holder} was later updated to point to a different
|
||||||
|
* (or the initially missing) {@code Biome} object. This would lead to using stale or even {@code null} data.</p>
|
||||||
|
*
|
||||||
|
* <p>By storing the {@code Holder<Biome>} itself, this class can call {@link net.minecraft.core.Holder#value()}
|
||||||
|
* whenever the biome information is needed, ensuring it always retrieves the most current {@code Biome}
|
||||||
|
* instance associated with the holder at that time.</p>
|
||||||
|
*/
|
||||||
|
private static #if MC_VER < MC_1_18_2 Biome #else Holder<Biome> #endif getClientBiome(String biomeResourceString)
|
||||||
|
{
|
||||||
|
#if MC_VER < MC_1_18_2
|
||||||
|
Biome biome;
|
||||||
|
#else
|
||||||
|
Holder<Biome> biome;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// calling get instead of compute is slightly faster for already
|
||||||
|
// computed values
|
||||||
|
biome = BIOME_BY_RESOURCE_STRING.get(biomeResourceString);
|
||||||
|
if (biome != null)
|
||||||
|
{
|
||||||
|
return biome;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// cache the client biomes so we don't have to re-parse the resource location every time
|
||||||
|
return BIOME_BY_RESOURCE_STRING.compute(biomeResourceString,
|
||||||
|
(resourceString, existingBiome) ->
|
||||||
|
{
|
||||||
|
if (existingBiome != null)
|
||||||
|
{
|
||||||
|
return existingBiome;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientLevel clientLevel = Minecraft.getInstance().level;
|
||||||
|
if (clientLevel == null)
|
||||||
|
{
|
||||||
|
// shouldn't happen, but just in case
|
||||||
|
throw new IllegalStateException("Attempted to get client biome when no client level was loaded.");
|
||||||
|
}
|
||||||
|
|
||||||
|
BiomeWrapper.BiomeDeserializeResult result;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
result = BiomeWrapper.deserializeBiome(resourceString, clientLevel.registryAccess());
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
LOGGER.warn("Unable to deserialize client biome ["+resourceString+"], using fallback...");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
result = BiomeWrapper.deserializeBiome(BiomeWrapper.PLAINS_RESOURCE_LOCATION_STRING, clientLevel.registryAccess());
|
||||||
|
}
|
||||||
|
catch (IOException ex)
|
||||||
|
{
|
||||||
|
// should never happen, if it does this log will explode, but just in case
|
||||||
|
LOGGER.error("Unable to deserialize fallback client biome ["+BiomeWrapper.PLAINS_RESOURCE_LOCATION_STRING+"], returning NULL.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.success)
|
||||||
|
{
|
||||||
|
existingBiome = result.biome;
|
||||||
|
}
|
||||||
|
|
||||||
|
return existingBiome;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+105
-66
@@ -26,10 +26,10 @@ import java.util.Optional;
|
|||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
|
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
|
||||||
|
|
||||||
@@ -45,8 +45,14 @@ import net.minecraft.core.Holder;
|
|||||||
import net.minecraft.core.registries.Registries;
|
import net.minecraft.core.registries.Registries;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_21_10
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
#else
|
||||||
|
import net.minecraft.resources.Identifier;
|
||||||
|
#endif
|
||||||
|
|
||||||
import net.minecraft.world.level.biome.Biome;
|
import net.minecraft.world.level.biome.Biome;
|
||||||
|
|
||||||
#if MC_VER >= MC_1_18_2
|
#if MC_VER >= MC_1_18_2
|
||||||
import net.minecraft.world.level.biome.Biomes;
|
import net.minecraft.world.level.biome.Biomes;
|
||||||
#endif
|
#endif
|
||||||
@@ -56,7 +62,7 @@ import net.minecraft.world.level.biome.Biomes;
|
|||||||
public class BiomeWrapper implements IBiomeWrapper
|
public class BiomeWrapper implements IBiomeWrapper
|
||||||
{
|
{
|
||||||
// must be defined before AIR, otherwise a null pointer will be thrown
|
// must be defined before AIR, otherwise a null pointer will be thrown
|
||||||
private static final Logger LOGGER = LogManager.getLogger();
|
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
|
|
||||||
|
|
||||||
#if MC_VER < MC_1_18_2
|
#if MC_VER < MC_1_18_2
|
||||||
@@ -102,7 +108,7 @@ public class BiomeWrapper implements IBiomeWrapper
|
|||||||
// constructors //
|
// constructors //
|
||||||
//==============//
|
//==============//
|
||||||
|
|
||||||
static public IBiomeWrapper getBiomeWrapper(#if MC_VER < MC_1_18_2 Biome #else Holder<Biome> #endif biome, ILevelWrapper levelWrapper)
|
public static BiomeWrapper getBiomeWrapper(#if MC_VER < MC_1_18_2 Biome #else Holder<Biome> #endif biome, ILevelWrapper levelWrapper)
|
||||||
{
|
{
|
||||||
if (biome == null)
|
if (biome == null)
|
||||||
{
|
{
|
||||||
@@ -110,9 +116,10 @@ public class BiomeWrapper implements IBiomeWrapper
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (WRAPPER_BY_BIOME.containsKey(biome))
|
BiomeWrapper biomeWrapper = WRAPPER_BY_BIOME.get(biome);
|
||||||
|
if (biomeWrapper != null)
|
||||||
{
|
{
|
||||||
return WRAPPER_BY_BIOME.get(biome);
|
return biomeWrapper;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -130,14 +137,6 @@ public class BiomeWrapper implements IBiomeWrapper
|
|||||||
//LOGGER.trace("Created BiomeWrapper ["+this.serialString+"] for ["+biome+"]");
|
//LOGGER.trace("Created BiomeWrapper ["+this.serialString+"] for ["+biome+"]");
|
||||||
}
|
}
|
||||||
|
|
||||||
/** should only be used to create {@link BiomeWrapper#EMPTY_WRAPPER} */
|
|
||||||
private BiomeWrapper()
|
|
||||||
{
|
|
||||||
this.biome = null;
|
|
||||||
this.serialString = EMPTY_BIOME_STRING;
|
|
||||||
this.hashCode = Objects.hash(this.serialString);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//=========//
|
//=========//
|
||||||
@@ -222,7 +221,12 @@ public class BiomeWrapper implements IBiomeWrapper
|
|||||||
Level level = (Level)levelWrapper.getWrappedMcObject();
|
Level level = (Level)levelWrapper.getWrappedMcObject();
|
||||||
net.minecraft.core.RegistryAccess registryAccess = level.registryAccess();
|
net.minecraft.core.RegistryAccess registryAccess = level.registryAccess();
|
||||||
|
|
||||||
|
#if MC_VER < MC_1_21_11
|
||||||
ResourceLocation resourceLocation;
|
ResourceLocation resourceLocation;
|
||||||
|
#else
|
||||||
|
Identifier resourceLocation;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
||||||
resourceLocation = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).getKey(this.biome);
|
resourceLocation = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).getKey(this.biome);
|
||||||
#elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2
|
#elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2
|
||||||
@@ -254,7 +258,6 @@ public class BiomeWrapper implements IBiomeWrapper
|
|||||||
return this.serialString;
|
return this.serialString;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO would it be worth while to cache these objects in a ConcurrentHashMap<string, IBiomeWrapper>?
|
|
||||||
public static IBiomeWrapper deserialize(String resourceLocationString, ILevelWrapper levelWrapper) throws IOException
|
public static IBiomeWrapper deserialize(String resourceLocationString, ILevelWrapper levelWrapper) throws IOException
|
||||||
{
|
{
|
||||||
// we need the final string for the concurrent hash map later
|
// we need the final string for the concurrent hash map later
|
||||||
@@ -286,64 +289,16 @@ public class BiomeWrapper implements IBiomeWrapper
|
|||||||
BiomeWrapper foundWrapper = EMPTY_WRAPPER;
|
BiomeWrapper foundWrapper = EMPTY_WRAPPER;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// parse the resource location
|
|
||||||
int separatorIndex = resourceLocationString.indexOf(":");
|
|
||||||
if (separatorIndex == -1)
|
|
||||||
{
|
|
||||||
throw new IOException("Unable to parse resource location string: [" + resourceLocationString + "].");
|
|
||||||
}
|
|
||||||
|
|
||||||
ResourceLocation resourceLocation;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
#if MC_VER < MC_1_21_1
|
|
||||||
resourceLocation = new ResourceLocation(resourceLocationString.substring(0, separatorIndex), resourceLocationString.substring(separatorIndex + 1));
|
|
||||||
#else
|
|
||||||
resourceLocation = ResourceLocation.fromNamespaceAndPath(resourceLocationString.substring(0, separatorIndex), resourceLocationString.substring(separatorIndex + 1));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
throw new IOException("No Resource Location found for the string: [" + resourceLocationString + "] Error: [" + e.getMessage() + "].");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Level level = (Level) levelWrapper.getWrappedMcObject();
|
Level level = (Level) levelWrapper.getWrappedMcObject();
|
||||||
net.minecraft.core.RegistryAccess registryAccess = level.registryAccess();
|
net.minecraft.core.RegistryAccess registryAccess = level.registryAccess();
|
||||||
|
|
||||||
boolean success;
|
BiomeDeserializeResult deserializeResult = deserializeBiome(resourceLocationString, registryAccess);
|
||||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
|
||||||
Biome biome = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).get(resourceLocation);
|
|
||||||
success = (biome != null);
|
|
||||||
#elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2
|
|
||||||
Biome unwrappedBiome = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).get(resourceLocation);
|
|
||||||
success = (unwrappedBiome != null);
|
|
||||||
Holder<Biome> biome = new Holder.Direct<>(unwrappedBiome);
|
|
||||||
#elif MC_VER < MC_1_21_3
|
|
||||||
Biome unwrappedBiome = registryAccess.registryOrThrow(Registries.BIOME).get(resourceLocation);
|
|
||||||
success = (unwrappedBiome != null);
|
|
||||||
Holder<Biome> biome = new Holder.Direct<>(unwrappedBiome);
|
|
||||||
#else
|
|
||||||
Holder<Biome> biome;
|
|
||||||
Optional<Holder.Reference<Biome>> optionalBiomeHolder = registryAccess.lookupOrThrow(Registries.BIOME).get(resourceLocation);
|
|
||||||
if (optionalBiomeHolder.isPresent())
|
|
||||||
{
|
|
||||||
Biome unwrappedBiome = optionalBiomeHolder.get().value();
|
|
||||||
success = (unwrappedBiome != null);
|
|
||||||
biome = new Holder.Direct<>(unwrappedBiome);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
success = false;
|
|
||||||
biome = null;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (!success)
|
if (!deserializeResult.success)
|
||||||
{
|
{
|
||||||
if (!brokenResourceLocationStrings.contains(resourceLocationString))
|
if (!brokenResourceLocationStrings.contains(resourceLocationString))
|
||||||
{
|
{
|
||||||
@@ -354,7 +309,7 @@ public class BiomeWrapper implements IBiomeWrapper
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
foundWrapper = (BiomeWrapper) getBiomeWrapper(biome, levelWrapper);
|
foundWrapper = getBiomeWrapper(deserializeResult.biome, levelWrapper);
|
||||||
return foundWrapper;
|
return foundWrapper;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@@ -368,4 +323,88 @@ public class BiomeWrapper implements IBiomeWrapper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static BiomeDeserializeResult deserializeBiome(String resourceLocationString, net.minecraft.core.RegistryAccess registryAccess) throws IOException
|
||||||
|
{
|
||||||
|
// parse the resource location
|
||||||
|
int separatorIndex = resourceLocationString.indexOf(":");
|
||||||
|
if (separatorIndex == -1)
|
||||||
|
{
|
||||||
|
throw new IOException("Unable to parse resource location string: [" + resourceLocationString + "].");
|
||||||
|
}
|
||||||
|
|
||||||
|
#if MC_VER < MC_1_21_11
|
||||||
|
ResourceLocation resourceLocation;
|
||||||
|
#else
|
||||||
|
Identifier resourceLocation;
|
||||||
|
#endif
|
||||||
|
try
|
||||||
|
{
|
||||||
|
#if MC_VER <= MC_1_20_6
|
||||||
|
resourceLocation = new ResourceLocation(resourceLocationString.substring(0, separatorIndex), resourceLocationString.substring(separatorIndex + 1));
|
||||||
|
#elif MC_VER <= MC_1_21_10
|
||||||
|
resourceLocation = ResourceLocation.fromNamespaceAndPath(resourceLocationString.substring(0, separatorIndex), resourceLocationString.substring(separatorIndex + 1));
|
||||||
|
#else
|
||||||
|
resourceLocation = Identifier.fromNamespaceAndPath(resourceLocationString.substring(0, separatorIndex), resourceLocationString.substring(separatorIndex + 1));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new IOException("No Resource Location found for the string: [" + resourceLocationString + "] Error: [" + e.getMessage() + "].");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
boolean success;
|
||||||
|
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
||||||
|
Biome biome = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).get(resourceLocation);
|
||||||
|
success = (biome != null);
|
||||||
|
#elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2
|
||||||
|
Biome unwrappedBiome = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).get(resourceLocation);
|
||||||
|
success = (unwrappedBiome != null);
|
||||||
|
Holder<Biome> biome = new Holder.Direct<>(unwrappedBiome);
|
||||||
|
#elif MC_VER < MC_1_21_3
|
||||||
|
Biome unwrappedBiome = registryAccess.registryOrThrow(Registries.BIOME).get(resourceLocation);
|
||||||
|
success = (unwrappedBiome != null);
|
||||||
|
Holder<Biome> biome = new Holder.Direct<>(unwrappedBiome);
|
||||||
|
#else
|
||||||
|
Holder<Biome> biome;
|
||||||
|
Optional<Holder.Reference<Biome>> optionalBiomeHolder = registryAccess.lookupOrThrow(Registries.BIOME).get(resourceLocation);
|
||||||
|
if (optionalBiomeHolder.isPresent())
|
||||||
|
{
|
||||||
|
Biome unwrappedBiome = optionalBiomeHolder.get().value();
|
||||||
|
success = (unwrappedBiome != null);
|
||||||
|
biome = new Holder.Direct<>(unwrappedBiome);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
success = false;
|
||||||
|
biome = null;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return new BiomeDeserializeResult(success, biome);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//================//
|
||||||
|
// helper classes //
|
||||||
|
//================//
|
||||||
|
|
||||||
|
public static class BiomeDeserializeResult
|
||||||
|
{
|
||||||
|
public final boolean success;
|
||||||
|
|
||||||
|
#if MC_VER < MC_1_18_2
|
||||||
|
public final Biome biome;
|
||||||
|
#else
|
||||||
|
public final Holder<Biome> biome;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public BiomeDeserializeResult(boolean success, #if MC_VER < MC_1_18_2 Biome #else Holder<Biome> #endif biome)
|
||||||
|
{
|
||||||
|
this.success = success;
|
||||||
|
this.biome = biome;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+125
-27
@@ -28,21 +28,23 @@ import com.seibel.distanthorizons.core.util.LodUtil;
|
|||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
|
||||||
|
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||||
import net.minecraft.tags.BlockTags;
|
import net.minecraft.tags.BlockTags;
|
||||||
import net.minecraft.world.level.block.BeaconBeamBlock;
|
import net.minecraft.world.level.block.BeaconBeamBlock;
|
||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.Block;
|
||||||
import net.minecraft.world.level.block.Blocks;
|
import net.minecraft.world.level.block.Blocks;
|
||||||
import net.minecraft.world.level.block.SoundType;
|
import net.minecraft.world.level.block.SoundType;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import org.apache.logging.log4j.Logger;
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
||||||
@@ -50,12 +52,14 @@ import net.minecraft.core.Registry;
|
|||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.world.level.EmptyBlockGetter;
|
import net.minecraft.world.level.EmptyBlockGetter;
|
||||||
#elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2
|
#elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2
|
||||||
|
import net.minecraft.tags.TagKey;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Registry;
|
import net.minecraft.core.Registry;
|
||||||
import net.minecraft.world.level.EmptyBlockGetter;
|
import net.minecraft.world.level.EmptyBlockGetter;
|
||||||
#else
|
#else
|
||||||
|
import net.minecraft.tags.TagKey;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.registries.Registries;
|
import net.minecraft.core.registries.Registries;
|
||||||
@@ -63,6 +67,12 @@ import net.minecraft.world.level.EmptyBlockGetter;
|
|||||||
import net.minecraft.core.Holder;
|
import net.minecraft.core.Holder;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_21_10
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
#else
|
||||||
|
import net.minecraft.resources.Identifier;
|
||||||
|
#endif
|
||||||
|
|
||||||
public class BlockStateWrapper implements IBlockStateWrapper
|
public class BlockStateWrapper implements IBlockStateWrapper
|
||||||
{
|
{
|
||||||
/** example "minecraft:water" */
|
/** example "minecraft:water" */
|
||||||
@@ -72,7 +82,7 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
|||||||
|
|
||||||
|
|
||||||
// must be defined before AIR, otherwise a null pointer will be thrown
|
// must be defined before AIR, otherwise a null pointer will be thrown
|
||||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
|
|
||||||
public static final ConcurrentHashMap<BlockState, BlockStateWrapper> WRAPPER_BY_BLOCK_STATE = new ConcurrentHashMap<>();
|
public static final ConcurrentHashMap<BlockState, BlockStateWrapper> WRAPPER_BY_BLOCK_STATE = new ConcurrentHashMap<>();
|
||||||
public static final ConcurrentHashMap<String, BlockStateWrapper> WRAPPER_BY_RESOURCE_LOCATION = new ConcurrentHashMap<>();
|
public static final ConcurrentHashMap<String, BlockStateWrapper> WRAPPER_BY_RESOURCE_LOCATION = new ConcurrentHashMap<>();
|
||||||
@@ -81,12 +91,17 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
|||||||
public static final BlockStateWrapper AIR = new BlockStateWrapper(null, null);
|
public static final BlockStateWrapper AIR = new BlockStateWrapper(null, null);
|
||||||
|
|
||||||
public static final String DIRT_RESOURCE_LOCATION_STRING = "minecraft:dirt";
|
public static final String DIRT_RESOURCE_LOCATION_STRING = "minecraft:dirt";
|
||||||
|
public static final String WATER_RESOURCE_LOCATION_STRING = "minecraft:water";
|
||||||
|
|
||||||
public static HashSet<IBlockStateWrapper> rendererIgnoredBlocks = null;
|
public static ObjectOpenHashSet<IBlockStateWrapper> rendererIgnoredBlocks = null;
|
||||||
public static HashSet<IBlockStateWrapper> rendererIgnoredCaveBlocks = null;
|
public static ObjectOpenHashSet<IBlockStateWrapper> rendererIgnoredCaveBlocks = null;
|
||||||
|
|
||||||
/** keep track of broken blocks so we don't log every time */
|
/** keep track of broken blocks so we don't log every time */
|
||||||
|
#if MC_VER <= MC_1_21_10
|
||||||
private static final HashSet<ResourceLocation> BROKEN_RESOURCE_LOCATIONS = new HashSet<>();
|
private static final HashSet<ResourceLocation> BROKEN_RESOURCE_LOCATIONS = new HashSet<>();
|
||||||
|
#else
|
||||||
|
private static final HashSet<Identifier> BROKEN_RESOURCE_LOCATIONS = new HashSet<>();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -114,6 +129,7 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
|||||||
//==============//
|
//==============//
|
||||||
// constructors //
|
// constructors //
|
||||||
//==============//
|
//==============//
|
||||||
|
//region
|
||||||
|
|
||||||
public static BlockStateWrapper fromBlockState(BlockState blockState, ILevelWrapper levelWrapper)
|
public static BlockStateWrapper fromBlockState(BlockState blockState, ILevelWrapper levelWrapper)
|
||||||
{
|
{
|
||||||
@@ -155,7 +171,7 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private BlockStateWrapper(BlockState blockState, ILevelWrapper levelWrapper)
|
private BlockStateWrapper(@Nullable BlockState blockState, ILevelWrapper levelWrapper)
|
||||||
{
|
{
|
||||||
this.blockState = blockState;
|
this.blockState = blockState;
|
||||||
this.serialString = this.serialize(levelWrapper);
|
this.serialString = this.serialize(levelWrapper);
|
||||||
@@ -166,11 +182,24 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
|||||||
String lowercaseSerial = this.serialString.toLowerCase();
|
String lowercaseSerial = this.serialString.toLowerCase();
|
||||||
|
|
||||||
|
|
||||||
// beacon blocks
|
|
||||||
|
// beacon base blocks
|
||||||
|
#if MC_VER <= MC_1_18_2
|
||||||
|
|
||||||
|
// Used to handle older MC versions that don't have an simple way of getting the block's tags
|
||||||
|
List<String> oldBeaconBaseBlockNameList = Arrays.asList(
|
||||||
|
"iron_block",
|
||||||
|
"gold_block",
|
||||||
|
"diamond_block",
|
||||||
|
"emerald_block",
|
||||||
|
"netherite_block"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Older MC versions are harder to get block tags, so just use a static list to determine beacon blocks
|
||||||
boolean isBeaconBaseBlock = false;
|
boolean isBeaconBaseBlock = false;
|
||||||
for (int i = 0; i < LodUtil.BEACON_BASE_BLOCK_NAME_LIST.size(); i++)
|
for (int i = 0; i < oldBeaconBaseBlockNameList.size(); i++)
|
||||||
{
|
{
|
||||||
String baseBlockName = LodUtil.BEACON_BASE_BLOCK_NAME_LIST.get(i);
|
String baseBlockName = oldBeaconBaseBlockNameList.get(i);
|
||||||
if (lowercaseSerial.contains(baseBlockName))
|
if (lowercaseSerial.contains(baseBlockName))
|
||||||
{
|
{
|
||||||
isBeaconBaseBlock = true;
|
isBeaconBaseBlock = true;
|
||||||
@@ -178,8 +207,23 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.isBeaconBaseBlock = isBeaconBaseBlock;
|
this.isBeaconBaseBlock = isBeaconBaseBlock;
|
||||||
|
#else
|
||||||
|
if (blockState != null)
|
||||||
|
{
|
||||||
|
// check if this block has any tags
|
||||||
|
Stream<TagKey<Block>> tags = blockState.getTags();
|
||||||
|
this.isBeaconBaseBlock = tags.anyMatch((TagKey<Block> tag) -> tag.location().getPath().toLowerCase().contains("beacon_base_blocks"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.isBeaconBaseBlock = false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// beacon block
|
||||||
this.isBeaconBlock = lowercaseSerial.contains("minecraft:beacon");
|
this.isBeaconBlock = lowercaseSerial.contains("minecraft:beacon");
|
||||||
|
|
||||||
|
|
||||||
// beacon tint color
|
// beacon tint color
|
||||||
Color beaconTintColor = null;
|
Color beaconTintColor = null;
|
||||||
if (this.blockState != null
|
if (this.blockState != null
|
||||||
@@ -215,6 +259,12 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
|||||||
// bedrock is a special case fully opaque block that does allow beacons through
|
// bedrock is a special case fully opaque block that does allow beacons through
|
||||||
allowsBeaconBeamPassage = true;
|
allowsBeaconBeamPassage = true;
|
||||||
}
|
}
|
||||||
|
else if (lowercaseSerial.contains("minecraft:tinted_glass"))
|
||||||
|
{
|
||||||
|
// tinted glass is a special case where it isn't fully opaque,
|
||||||
|
// but should block beacons
|
||||||
|
allowsBeaconBeamPassage = false;
|
||||||
|
}
|
||||||
else if (propagatesSkyLightDown || !canOcclude)
|
else if (propagatesSkyLightDown || !canOcclude)
|
||||||
{
|
{
|
||||||
// stairs, cake, fences, etc.
|
// stairs, cake, fences, etc.
|
||||||
@@ -253,17 +303,20 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
|||||||
//LOGGER.trace("Created BlockStateWrapper ["+this.serialString+"] for ["+blockState+"] with material ID ["+this.EDhApiBlockMaterialId+"]");
|
//LOGGER.trace("Created BlockStateWrapper ["+this.serialString+"] for ["+blockState+"] with material ID ["+this.EDhApiBlockMaterialId+"]");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//====================//
|
//====================//
|
||||||
// LodBuilder methods //
|
// LodBuilder methods //
|
||||||
//====================//
|
//====================//
|
||||||
|
//region
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Requires a {@link ILevelWrapper} since {@link BlockStateWrapper#deserialize(String,ILevelWrapper)} also requires one.
|
* Requires a {@link ILevelWrapper} since {@link BlockStateWrapper#deserialize(String,ILevelWrapper)} also requires one.
|
||||||
* This way the method won't accidentally be called before the deserialization can be completed.
|
* This way the method won't accidentally be called before the deserialization can be completed.
|
||||||
*/
|
*/
|
||||||
public static HashSet<IBlockStateWrapper> getRendererIgnoredBlocks(ILevelWrapper levelWrapper)
|
public static ObjectOpenHashSet<IBlockStateWrapper> getRendererIgnoredBlocks(ILevelWrapper levelWrapper)
|
||||||
{
|
{
|
||||||
// use the cached version if possible
|
// use the cached version if possible
|
||||||
if (rendererIgnoredBlocks != null)
|
if (rendererIgnoredBlocks != null)
|
||||||
@@ -271,16 +324,16 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
|||||||
return rendererIgnoredBlocks;
|
return rendererIgnoredBlocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
HashSet<String> baseIgnoredBlock = new HashSet<>();
|
ObjectOpenHashSet<String> baseIgnoredBlock = new ObjectOpenHashSet<>();
|
||||||
baseIgnoredBlock.add(AIR_STRING);
|
baseIgnoredBlock.add(AIR_STRING);
|
||||||
rendererIgnoredBlocks = getBlockWrappers(Config.Client.Advanced.Graphics.Culling.ignoredRenderBlockCsv, baseIgnoredBlock, levelWrapper);
|
rendererIgnoredBlocks = getAllBlockWrappers(Config.Client.Advanced.Graphics.Culling.ignoredRenderBlockCsv, baseIgnoredBlock, levelWrapper);
|
||||||
return rendererIgnoredBlocks;
|
return rendererIgnoredBlocks;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Requires a {@link ILevelWrapper} since {@link BlockStateWrapper#deserialize(String,ILevelWrapper)} also requires one.
|
* Requires a {@link ILevelWrapper} since {@link BlockStateWrapper#deserialize(String,ILevelWrapper)} also requires one.
|
||||||
* This way the method won't accidentally be called before the deserialization can be completed.
|
* This way the method won't accidentally be called before the deserialization can be completed.
|
||||||
*/
|
*/
|
||||||
public static HashSet<IBlockStateWrapper> getRendererIgnoredCaveBlocks(ILevelWrapper levelWrapper)
|
public static ObjectOpenHashSet<IBlockStateWrapper> getRendererIgnoredCaveBlocks(ILevelWrapper levelWrapper)
|
||||||
{
|
{
|
||||||
// use the cached version if possible
|
// use the cached version if possible
|
||||||
if (rendererIgnoredCaveBlocks != null)
|
if (rendererIgnoredCaveBlocks != null)
|
||||||
@@ -288,23 +341,28 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
|||||||
return rendererIgnoredCaveBlocks;
|
return rendererIgnoredCaveBlocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
HashSet<String> baseIgnoredBlock = new HashSet<>();
|
ObjectOpenHashSet<String> baseIgnoredBlock = new ObjectOpenHashSet<>();
|
||||||
baseIgnoredBlock.add(AIR_STRING);
|
baseIgnoredBlock.add(AIR_STRING);
|
||||||
rendererIgnoredCaveBlocks = getBlockWrappers(Config.Client.Advanced.Graphics.Culling.ignoredRenderCaveBlockCsv, baseIgnoredBlock, levelWrapper);
|
rendererIgnoredCaveBlocks = getAllBlockWrappers(Config.Client.Advanced.Graphics.Culling.ignoredRenderCaveBlockCsv, baseIgnoredBlock, levelWrapper);
|
||||||
return rendererIgnoredCaveBlocks;
|
return rendererIgnoredCaveBlocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void clearRendererIgnoredBlocks() { rendererIgnoredBlocks = null; }
|
public static void clearRendererIgnoredBlocks() { rendererIgnoredBlocks = null; }
|
||||||
public static void clearRendererIgnoredCaveBlocks() { rendererIgnoredCaveBlocks = null; }
|
public static void clearRendererIgnoredCaveBlocks() { rendererIgnoredCaveBlocks = null; }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=====================//
|
||||||
// lod builder helpers //
|
// lod builder helpers //
|
||||||
|
//=====================//
|
||||||
|
//region
|
||||||
|
|
||||||
private static HashSet<IBlockStateWrapper> getBlockWrappers(ConfigEntry<String> config, HashSet<String> baseResourceLocations, ILevelWrapper levelWrapper)
|
private static ObjectOpenHashSet<IBlockStateWrapper> getAllBlockWrappers(ConfigEntry<String> config, ObjectOpenHashSet<String> baseResourceLocations, ILevelWrapper levelWrapper)
|
||||||
{
|
{
|
||||||
// get the base blocks
|
// get the base blocks
|
||||||
HashSet<String> blockStringList = new HashSet<>();
|
ObjectOpenHashSet<String> blockStringList = new ObjectOpenHashSet<>();
|
||||||
if (baseResourceLocations != null)
|
if (baseResourceLocations != null)
|
||||||
{
|
{
|
||||||
blockStringList.addAll(baseResourceLocations);
|
blockStringList.addAll(baseResourceLocations);
|
||||||
@@ -317,12 +375,12 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
|||||||
blockStringList.addAll(Arrays.asList(ignoreBlockCsv.split(",")));
|
blockStringList.addAll(Arrays.asList(ignoreBlockCsv.split(",")));
|
||||||
}
|
}
|
||||||
|
|
||||||
return getBlockWrappers(blockStringList, levelWrapper);
|
return getAllBlockWrappers(blockStringList, levelWrapper);
|
||||||
}
|
}
|
||||||
private static HashSet<IBlockStateWrapper> getBlockWrappers(HashSet<String> blockResourceLocationSet, ILevelWrapper levelWrapper)
|
private static ObjectOpenHashSet<IBlockStateWrapper> getAllBlockWrappers(ObjectOpenHashSet<String> blockResourceLocationSet, ILevelWrapper levelWrapper)
|
||||||
{
|
{
|
||||||
// deserialize each of the given resource locations
|
// deserialize each of the given resource locations
|
||||||
HashSet<IBlockStateWrapper> blockStateWrappers = new HashSet<>();
|
ObjectOpenHashSet<IBlockStateWrapper> blockStateWrappers = new ObjectOpenHashSet<>();
|
||||||
for (String blockResourceLocation : blockResourceLocationSet)
|
for (String blockResourceLocation : blockResourceLocationSet)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -371,11 +429,14 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
|||||||
return blockStateWrappers;
|
return blockStateWrappers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//=================//
|
//=================//
|
||||||
// wrapper methods //
|
// wrapper methods //
|
||||||
//=================//
|
//=================//
|
||||||
|
//region
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getOpacity() { return this.opacity; }
|
public int getOpacity() { return this.opacity; }
|
||||||
@@ -483,25 +544,37 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
|||||||
public boolean isAir() { return this.isAir(this.blockState); }
|
public boolean isAir() { return this.isAir(this.blockState); }
|
||||||
public boolean isAir(BlockState blockState) { return blockState == null || blockState.isAir(); }
|
public boolean isAir(BlockState blockState) { return blockState == null || blockState.isAir(); }
|
||||||
|
|
||||||
|
private Boolean blockIsSolid = null;
|
||||||
@Override
|
@Override
|
||||||
public boolean isSolid()
|
public boolean isSolid()
|
||||||
{
|
{
|
||||||
if (this.isAir())
|
if (this.isAir()
|
||||||
|
|| this.blockState == null) // == null isn't necessary since its handled in isAir() but is here to prevent intellij from complaining
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// cached since getCollisionShape() is a dictionary lookup that allocates objects
|
||||||
|
// and this call is used in a high traffic location
|
||||||
|
if (this.blockIsSolid != null)
|
||||||
|
{
|
||||||
|
return this.blockIsSolid;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#if MC_VER < MC_1_20_1
|
#if MC_VER < MC_1_20_1
|
||||||
return this.blockState.getMaterial().isSolid();
|
this.blockIsSolid = this.blockState.getMaterial().isSolid();
|
||||||
#else
|
#else
|
||||||
return !this.blockState.getCollisionShape(EmptyBlockGetter.INSTANCE, BlockPos.ZERO).isEmpty();
|
this.blockIsSolid = !this.blockState.getCollisionShape(EmptyBlockGetter.INSTANCE, BlockPos.ZERO).isEmpty();
|
||||||
#endif
|
#endif
|
||||||
|
return this.blockIsSolid;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isLiquid()
|
public boolean isLiquid()
|
||||||
{
|
{
|
||||||
if (this.isAir())
|
if (this.isAir()
|
||||||
|
|| this.blockState == null) // == null isn't necessary since its handled in isAir() but is here to prevent intellij from complaining
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -533,11 +606,14 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
|||||||
@Override
|
@Override
|
||||||
public String toString() { return this.getSerialString(); }
|
public String toString() { return this.getSerialString(); }
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//=======================//
|
//=======================//
|
||||||
// serialization methods //
|
// serialization methods //
|
||||||
//=======================//
|
//=======================//
|
||||||
|
//region
|
||||||
|
|
||||||
private String serialize(ILevelWrapper levelWrapper)
|
private String serialize(ILevelWrapper levelWrapper)
|
||||||
{
|
{
|
||||||
@@ -554,7 +630,12 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
|||||||
net.minecraft.core.RegistryAccess registryAccess = level.registryAccess();
|
net.minecraft.core.RegistryAccess registryAccess = level.registryAccess();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if MC_VER < MC_1_21_11
|
||||||
ResourceLocation resourceLocation;
|
ResourceLocation resourceLocation;
|
||||||
|
#else
|
||||||
|
Identifier resourceLocation;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
||||||
resourceLocation = Registry.BLOCK.getKey(this.blockState.getBlock());
|
resourceLocation = Registry.BLOCK.getKey(this.blockState.getBlock());
|
||||||
#elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2
|
#elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2
|
||||||
@@ -586,7 +667,8 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
|||||||
// we need the final string for the concurrent hash map later
|
// we need the final string for the concurrent hash map later
|
||||||
final String finalResourceStateString = resourceStateString;
|
final String finalResourceStateString = resourceStateString;
|
||||||
|
|
||||||
if (finalResourceStateString.equals(AIR_STRING) || finalResourceStateString.equals("")) // the empty string shouldn't normally happen, but just in case
|
if (finalResourceStateString.equals(AIR_STRING)
|
||||||
|
|| finalResourceStateString.equals("")) // the empty string shouldn't normally happen, but just in case
|
||||||
{
|
{
|
||||||
return AIR;
|
return AIR;
|
||||||
}
|
}
|
||||||
@@ -620,13 +702,20 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
|||||||
throw new IOException("Unable to parse Resource Location out of string: [" + resourceStateString + "].");
|
throw new IOException("Unable to parse Resource Location out of string: [" + resourceStateString + "].");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if MC_VER < MC_1_21_11
|
||||||
ResourceLocation resourceLocation;
|
ResourceLocation resourceLocation;
|
||||||
|
#else
|
||||||
|
Identifier resourceLocation;
|
||||||
|
#endif
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
#if MC_VER < MC_1_21_1
|
#if MC_VER < MC_1_21_1
|
||||||
resourceLocation = new ResourceLocation(resourceStateString.substring(0, separatorIndex), resourceStateString.substring(separatorIndex + 1));
|
resourceLocation = new ResourceLocation(resourceStateString.substring(0, separatorIndex), resourceStateString.substring(separatorIndex + 1));
|
||||||
#else
|
#elif MC_VER <= MC_1_21_10
|
||||||
resourceLocation = ResourceLocation.fromNamespaceAndPath(resourceStateString.substring(0, separatorIndex), resourceStateString.substring(separatorIndex + 1));
|
resourceLocation = ResourceLocation.fromNamespaceAndPath(resourceStateString.substring(0, separatorIndex), resourceStateString.substring(separatorIndex + 1));
|
||||||
|
#else
|
||||||
|
resourceLocation = Identifier.fromNamespaceAndPath(resourceStateString.substring(0, separatorIndex), resourceStateString.substring(separatorIndex + 1));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@@ -752,11 +841,14 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
|||||||
return stringBuilder.toString();
|
return stringBuilder.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//==============//
|
//==============//
|
||||||
// Iris methods //
|
// Iris methods //
|
||||||
//==============//
|
//==============//
|
||||||
|
//region
|
||||||
|
|
||||||
private EDhApiBlockMaterial calculateEDhApiBlockMaterialId()
|
private EDhApiBlockMaterial calculateEDhApiBlockMaterialId()
|
||||||
{
|
{
|
||||||
@@ -806,7 +898,10 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
|||||||
{
|
{
|
||||||
return EDhApiBlockMaterial.METAL;
|
return EDhApiBlockMaterial.METAL;
|
||||||
}
|
}
|
||||||
else if (serialString.contains("grass_block"))
|
else if (
|
||||||
|
serialString.contains("grass_block")
|
||||||
|
|| serialString.contains("grass_slab")
|
||||||
|
)
|
||||||
{
|
{
|
||||||
return EDhApiBlockMaterial.GRASS;
|
return EDhApiBlockMaterial.GRASS;
|
||||||
}
|
}
|
||||||
@@ -861,4 +956,7 @@ public class BlockStateWrapper implements IBlockStateWrapper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+113
-54
@@ -20,26 +20,25 @@
|
|||||||
package com.seibel.distanthorizons.common.wrappers.block;
|
package com.seibel.distanthorizons.common.wrappers.block;
|
||||||
|
|
||||||
import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
|
import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
|
||||||
|
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2;
|
||||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos;
|
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos;
|
||||||
|
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPosMutable;
|
||||||
import com.seibel.distanthorizons.core.util.ColorUtil;
|
import com.seibel.distanthorizons.core.util.ColorUtil;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.world.level.LevelReader;
|
import net.minecraft.world.level.block.*;
|
||||||
import net.minecraft.world.level.block.Block;
|
|
||||||
import net.minecraft.world.level.block.FlowerBlock;
|
|
||||||
import net.minecraft.world.level.block.LeavesBlock;
|
|
||||||
import net.minecraft.world.level.block.RotatedPillarBlock;
|
|
||||||
#if MC_VER >= MC_1_19_2
|
#if MC_VER >= MC_1_19_2
|
||||||
import net.minecraft.util.RandomSource;
|
import net.minecraft.util.RandomSource;
|
||||||
#else
|
#else
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
#endif
|
#endif
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import org.apache.logging.log4j.Logger;
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
import net.minecraft.world.level.block.state.properties.SlabType;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -61,7 +60,9 @@ import net.minecraft.client.renderer.block.model.BlockModelPart;
|
|||||||
*/
|
*/
|
||||||
public class ClientBlockStateColorCache
|
public class ClientBlockStateColorCache
|
||||||
{
|
{
|
||||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
|
|
||||||
|
private static final Minecraft MC = Minecraft.getInstance();
|
||||||
|
|
||||||
private static final HashSet<BlockState> BLOCK_STATES_THAT_NEED_LEVEL = new HashSet<>();
|
private static final HashSet<BlockState> BLOCK_STATES_THAT_NEED_LEVEL = new HashSet<>();
|
||||||
private static final HashSet<BlockState> BROKEN_BLOCK_STATES = new HashSet<>();
|
private static final HashSet<BlockState> BROKEN_BLOCK_STATES = new HashSet<>();
|
||||||
@@ -78,7 +79,16 @@ public class ClientBlockStateColorCache
|
|||||||
|
|
||||||
|
|
||||||
/** This is the order each direction on a block is processed when attempting to get the texture/color */
|
/** This is the order each direction on a block is processed when attempting to get the texture/color */
|
||||||
private static final Direction[] COLOR_RESOLUTION_DIRECTION_ORDER = { Direction.UP, Direction.NORTH, Direction.EAST, Direction.WEST, Direction.SOUTH, Direction.DOWN };
|
private static final @Nullable Direction[] COLOR_RESOLUTION_DIRECTION_ORDER =
|
||||||
|
{
|
||||||
|
Direction.UP,
|
||||||
|
null, // null represents "unculled" faces, IE the top of farmland
|
||||||
|
Direction.NORTH,
|
||||||
|
Direction.EAST,
|
||||||
|
Direction.WEST,
|
||||||
|
Direction.SOUTH,
|
||||||
|
Direction.DOWN
|
||||||
|
};
|
||||||
|
|
||||||
private static final int FLOWER_COLOR_SCALE = 5;
|
private static final int FLOWER_COLOR_SCALE = 5;
|
||||||
|
|
||||||
@@ -91,13 +101,12 @@ public class ClientBlockStateColorCache
|
|||||||
private static final RandomSource RANDOM = RandomSource.create();
|
private static final RandomSource RANDOM = RandomSource.create();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
private final IClientLevelWrapper levelWrapper;
|
private final IClientLevelWrapper clientLevelWrapper;
|
||||||
private final BlockState blockState;
|
private final BlockState blockState;
|
||||||
private final LevelReader level;
|
private final BlockStateWrapper blockStateWrapper;
|
||||||
|
|
||||||
private boolean isColorResolved = false;
|
private boolean isColorResolved = false;
|
||||||
private int baseColor = 0;
|
private int baseColor = 0;
|
||||||
private boolean needShade = true;
|
|
||||||
private boolean needPostTinting = false;
|
private boolean needPostTinting = false;
|
||||||
private int tintIndex = 0;
|
private int tintIndex = 0;
|
||||||
|
|
||||||
@@ -165,17 +174,21 @@ public class ClientBlockStateColorCache
|
|||||||
0.93011117f, 0.9386859f, 0.9473069f, 0.9559735f, 0.9646866f, 0.9734455f, 0.98225087f, 0.9911022f, 1.0f
|
0.93011117f, 0.9386859f, 0.9473069f, 0.9559735f, 0.9646866f, 0.9734455f, 0.98225087f, 0.9911022f, 1.0f
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private static final ThreadLocal<TintWithoutLevelOverrider> TintWithoutLevelOverrideGetter = ThreadLocal.withInitial(() -> new TintWithoutLevelOverrider());
|
||||||
|
private static final ThreadLocal<TintGetterOverride> TintOverrideGetter = ThreadLocal.withInitial(() -> new TintGetterOverride());
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//=============//
|
//=============//
|
||||||
// constructor //
|
// constructor //
|
||||||
//=============//
|
//=============//
|
||||||
|
|
||||||
public ClientBlockStateColorCache(BlockState blockState, IClientLevelWrapper samplingLevel)
|
public ClientBlockStateColorCache(BlockState blockState, IClientLevelWrapper clientLevelWrapper)
|
||||||
{
|
{
|
||||||
this.blockState = blockState;
|
this.blockState = blockState;
|
||||||
this.levelWrapper = samplingLevel;
|
this.blockStateWrapper = BlockStateWrapper.fromBlockState(blockState, clientLevelWrapper);
|
||||||
this.level = (LevelReader) samplingLevel.getWrappedMcObject();
|
this.clientLevelWrapper = clientLevelWrapper;
|
||||||
|
|
||||||
this.resolveColors();
|
this.resolveColors();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,32 +241,29 @@ public class ClientBlockStateColorCache
|
|||||||
|
|
||||||
this.needPostTinting = firstQuad.isTinted();
|
this.needPostTinting = firstQuad.isTinted();
|
||||||
#if MC_VER <= MC_1_21_4
|
#if MC_VER <= MC_1_21_4
|
||||||
this.needShade = firstQuad.isShade();
|
|
||||||
this.tintIndex = firstQuad.getTintIndex();
|
this.tintIndex = firstQuad.getTintIndex();
|
||||||
#else
|
#else
|
||||||
this.needShade = firstQuad.shade();
|
|
||||||
this.tintIndex = firstQuad.tintIndex();
|
this.tintIndex = firstQuad.tintIndex();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if MC_VER < MC_1_17_1
|
#if MC_VER < MC_1_17_1
|
||||||
this.baseColor = calculateColorFromTexture(
|
this.baseColor = calculateColorFromTexture(
|
||||||
firstQuad.sprite,
|
firstQuad.sprite,
|
||||||
ColorMode.getColorMode(this.blockState.getBlock()));
|
EColorMode.getColorMode(this.blockState.getBlock()));
|
||||||
#elif MC_VER < MC_1_21_5
|
#elif MC_VER < MC_1_21_5
|
||||||
this.baseColor = calculateColorFromTexture(
|
this.baseColor = calculateColorFromTexture(
|
||||||
firstQuad.getSprite(),
|
firstQuad.getSprite(),
|
||||||
ColorMode.getColorMode(this.blockState.getBlock()));
|
EColorMode.getColorMode(this.blockState.getBlock()));
|
||||||
#else
|
#else
|
||||||
this.baseColor = calculateColorFromTexture(
|
this.baseColor = calculateColorFromTexture(
|
||||||
firstQuad.sprite(),
|
firstQuad.sprite(),
|
||||||
ColorMode.getColorMode(this.blockState.getBlock()));
|
EColorMode.getColorMode(this.blockState.getBlock()));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Backup method.
|
// Backup method.
|
||||||
this.needPostTinting = false;
|
this.needPostTinting = false;
|
||||||
this.needShade = false;
|
|
||||||
this.tintIndex = 0;
|
this.tintIndex = 0;
|
||||||
this.baseColor = this.getParticleIconColor();
|
this.baseColor = this.getParticleIconColor();
|
||||||
}
|
}
|
||||||
@@ -262,11 +272,11 @@ public class ClientBlockStateColorCache
|
|||||||
{
|
{
|
||||||
// Liquid Block
|
// Liquid Block
|
||||||
this.needPostTinting = true;
|
this.needPostTinting = true;
|
||||||
this.needShade = false;
|
|
||||||
this.tintIndex = 0;
|
this.tintIndex = 0;
|
||||||
this.baseColor = this.getParticleIconColor();
|
this.baseColor = this.getParticleIconColor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
this.isColorResolved = true;
|
this.isColorResolved = true;
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
@@ -280,14 +290,23 @@ public class ClientBlockStateColorCache
|
|||||||
@Nullable
|
@Nullable
|
||||||
private List<BakedQuad> getQuadsForDirection(@Nullable Direction direction)
|
private List<BakedQuad> getQuadsForDirection(@Nullable Direction direction)
|
||||||
{
|
{
|
||||||
List<BakedQuad> quads = null;
|
BlockState effectiveBlockState = this.blockState;
|
||||||
|
|
||||||
|
// if this block is a slab, use it's double variant so we can get the top face,
|
||||||
|
// otherwise the color will use the side, which isn't as accurate
|
||||||
|
if (this.blockState.getBlock() instanceof SlabBlock)
|
||||||
|
{
|
||||||
|
effectiveBlockState = this.blockState.setValue( SlabBlock.TYPE, SlabType.DOUBLE );
|
||||||
|
}
|
||||||
|
|
||||||
|
List<BakedQuad> quads;
|
||||||
|
|
||||||
#if MC_VER < MC_1_21_5
|
#if MC_VER < MC_1_21_5
|
||||||
quads = Minecraft.getInstance().getModelManager().getBlockModelShaper().
|
quads = MC.getModelManager().getBlockModelShaper().
|
||||||
getBlockModel(this.blockState).getQuads(this.blockState, direction, RANDOM);
|
getBlockModel(effectiveBlockState).getQuads(effectiveBlockState, direction, RANDOM);
|
||||||
#else
|
#else
|
||||||
List<BlockModelPart> blockModelPartList = Minecraft.getInstance().getModelManager().getBlockModelShaper().
|
List<BlockModelPart> blockModelPartList = MC.getModelManager().getBlockModelShaper().
|
||||||
getBlockModel(this.blockState).collectParts(RANDOM);
|
getBlockModel(effectiveBlockState).collectParts(RANDOM);
|
||||||
|
|
||||||
quads = new ArrayList<>();
|
quads = new ArrayList<>();
|
||||||
if (blockModelPartList != null)
|
if (blockModelPartList != null)
|
||||||
@@ -303,8 +322,8 @@ public class ClientBlockStateColorCache
|
|||||||
return quads;
|
return quads;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: Perhaps make this not just use the first frame?
|
/** if multiple frames are present, just the first one will be used */
|
||||||
private static int calculateColorFromTexture(TextureAtlasSprite texture, ColorMode colorMode)
|
private static int calculateColorFromTexture(TextureAtlasSprite texture, EColorMode colorMode)
|
||||||
{
|
{
|
||||||
int count = 0;
|
int count = 0;
|
||||||
int alpha = 0;
|
int alpha = 0;
|
||||||
@@ -314,8 +333,8 @@ public class ClientBlockStateColorCache
|
|||||||
int tempColor;
|
int tempColor;
|
||||||
|
|
||||||
// don't render Chiseled blocks.
|
// don't render Chiseled blocks.
|
||||||
// Since ColorMode is set per block, you only need to check this once.
|
// Since EColorMode is set per block, you only need to check this once.
|
||||||
if (colorMode != ColorMode.Chisel)
|
if (colorMode != EColorMode.Chisel)
|
||||||
{
|
{
|
||||||
// textures normally use u and v instead of x and y
|
// textures normally use u and v instead of x and y
|
||||||
for (int v = 0; v < getTextureHeight(texture); v++)
|
for (int v = 0; v < getTextureHeight(texture); v++)
|
||||||
@@ -333,7 +352,7 @@ public class ClientBlockStateColorCache
|
|||||||
int b = (tempColor & 0x00FF0000) >>> 16;
|
int b = (tempColor & 0x00FF0000) >>> 16;
|
||||||
int a = (tempColor & 0xFF000000) >>> 24;
|
int a = (tempColor & 0xFF000000) >>> 24;
|
||||||
int scale = 1;
|
int scale = 1;
|
||||||
if (colorMode == ColorMode.Leaves)
|
if (colorMode == EColorMode.Leaves)
|
||||||
{
|
{
|
||||||
//switch (//FIXME add config option)
|
//switch (//FIXME add config option)
|
||||||
// case BLACK:
|
// case BLACK:
|
||||||
@@ -352,11 +371,11 @@ public class ClientBlockStateColorCache
|
|||||||
// break; //do nothing, let it count towards transparency
|
// break; //do nothing, let it count towards transparency
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (a == 0 && colorMode != ColorMode.Glass)
|
else if (a == 0 && colorMode != EColorMode.Glass)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (colorMode == ColorMode.Flower && (g + 25 < b || g + 25 < r))
|
else if (colorMode == EColorMode.Flower && (g + 25 < b || g + 25 < r))
|
||||||
{
|
{
|
||||||
scale = FLOWER_COLOR_SCALE;
|
scale = FLOWER_COLOR_SCALE;
|
||||||
}
|
}
|
||||||
@@ -414,16 +433,18 @@ public class ClientBlockStateColorCache
|
|||||||
* This method was suggested by IMS from the Iris/Sodium team.
|
* This method was suggested by IMS from the Iris/Sodium team.
|
||||||
* That's where the numbers and code are based.
|
* That's where the numbers and code are based.
|
||||||
*/
|
*/
|
||||||
private static int linearToSrgb(float c)
|
private static int linearToSrgb(float color)
|
||||||
{
|
{
|
||||||
if (!(c > MIN_SRGB_BOUND)) {
|
if (!(color > MIN_SRGB_BOUND))
|
||||||
c = MIN_SRGB_BOUND;
|
{
|
||||||
|
color = MIN_SRGB_BOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c > MAX_SRGB_BOUND) {
|
if (color > MAX_SRGB_BOUND)
|
||||||
c = MAX_SRGB_BOUND;
|
{
|
||||||
|
color = MAX_SRGB_BOUND;
|
||||||
}
|
}
|
||||||
int inputBits = Float.floatToRawIntBits(c);
|
int inputBits = Float.floatToRawIntBits(color);
|
||||||
int entry = linearToSrgbTable[((inputBits - MIN_SRGB_BITS) >> 20)];
|
int entry = linearToSrgbTable[((inputBits - MIN_SRGB_BITS) >> 20)];
|
||||||
|
|
||||||
int bias = (entry >>> 16) << 9;
|
int bias = (entry >>> 16) << 9;
|
||||||
@@ -437,7 +458,7 @@ public class ClientBlockStateColorCache
|
|||||||
{
|
{
|
||||||
return calculateColorFromTexture(
|
return calculateColorFromTexture(
|
||||||
Minecraft.getInstance().getModelManager().getBlockModelShaper().getParticleIcon(this.blockState),
|
Minecraft.getInstance().getModelManager().getBlockModelShaper().getParticleIcon(this.blockState),
|
||||||
ColorMode.getColorMode(this.blockState.getBlock()));
|
EColorMode.getColorMode(this.blockState.getBlock()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -446,7 +467,7 @@ public class ClientBlockStateColorCache
|
|||||||
// public getter //
|
// public getter //
|
||||||
//===============//
|
//===============//
|
||||||
|
|
||||||
public int getColor(BiomeWrapper biome, DhBlockPos pos)
|
public int getColor(BiomeWrapper biomeWrapper, FullDataSourceV2 fullDataSource, DhBlockPos blockPos)
|
||||||
{
|
{
|
||||||
// only get the tint if the block needs to be tinted
|
// only get the tint if the block needs to be tinted
|
||||||
if (!this.needPostTinting)
|
if (!this.needPostTinting)
|
||||||
@@ -470,13 +491,27 @@ public class ClientBlockStateColorCache
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
tintColor = Minecraft.getInstance().getBlockColors()
|
TintWithoutLevelOverrider tintOverride = TintWithoutLevelOverrideGetter.get();
|
||||||
.getColor(this.blockState, new TintWithoutLevelOverrider(biome, this.levelWrapper), McObjectConverter.Convert(pos), this.tintIndex);
|
tintOverride.update(biomeWrapper, this.blockStateWrapper, fullDataSource, this.clientLevelWrapper);
|
||||||
|
|
||||||
|
// try using DH's cached tint values first if possible
|
||||||
|
tintColor = tintOverride.tryGetBlockTint(new DhBlockPosMutable(blockPos));
|
||||||
|
if (tintColor == AbstractDhTintGetter.INVALID_COLOR)
|
||||||
|
{
|
||||||
|
// one or more tint values weren't calculated,
|
||||||
|
// we need MC's color resolver
|
||||||
|
tintColor = Minecraft.getInstance()
|
||||||
|
.getBlockColors()
|
||||||
|
.getColor(this.blockState,
|
||||||
|
tintOverride,
|
||||||
|
McObjectConverter.Convert(blockPos),
|
||||||
|
this.tintIndex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (UnsupportedOperationException e)
|
catch (UnsupportedOperationException e)
|
||||||
{
|
{
|
||||||
// this exception generally occurs if the tint requires other blocks besides itself
|
// this exception generally occurs if the tint requires other blocks besides itself
|
||||||
LOGGER.debug("Unable to use ["+TintWithoutLevelOverrider.class.getSimpleName()+"] to get the block tint for block: [" + this.blockState + "] and biome: [" + biome + "] at pos: " + pos + ". Error: [" + e.getMessage() + "]. Attempting to use backup method...", e);
|
LOGGER.debug("Unable to use ["+ TintWithoutLevelOverrider.class.getSimpleName()+"] to get the block tint for block: [" + this.blockState + "] and biome: [" + biomeWrapper + "] at pos: " + blockPos + ". Error: [" + e.getMessage() + "]. Attempting to use backup method...", e);
|
||||||
BLOCK_STATES_THAT_NEED_LEVEL.add(this.blockState);
|
BLOCK_STATES_THAT_NEED_LEVEL.add(this.blockState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -484,10 +519,22 @@ public class ClientBlockStateColorCache
|
|||||||
// use the level logic only if requested
|
// use the level logic only if requested
|
||||||
if (BLOCK_STATES_THAT_NEED_LEVEL.contains(this.blockState))
|
if (BLOCK_STATES_THAT_NEED_LEVEL.contains(this.blockState))
|
||||||
{
|
{
|
||||||
// this logic can't be used all the time due to it breaking some blocks tinting
|
// the level shouldn't be used all the time due to it breaking some blocks tinting
|
||||||
// specifically oceans don't render correctly
|
// specifically oceans don't render correctly
|
||||||
tintColor = Minecraft.getInstance().getBlockColors()
|
|
||||||
.getColor(this.blockState, new TintGetterOverrideFast(this.level), McObjectConverter.Convert(pos), this.tintIndex);
|
TintGetterOverride tintOverride = TintOverrideGetter.get();
|
||||||
|
tintOverride.update(biomeWrapper, this.blockStateWrapper, fullDataSource, this.clientLevelWrapper);
|
||||||
|
|
||||||
|
tintColor = tintOverride.tryGetBlockTint(new DhBlockPosMutable(blockPos));
|
||||||
|
if (tintColor == AbstractDhTintGetter.INVALID_COLOR)
|
||||||
|
{
|
||||||
|
tintColor = Minecraft.getInstance()
|
||||||
|
.getBlockColors()
|
||||||
|
.getColor(this.blockState,
|
||||||
|
tintOverride,
|
||||||
|
McObjectConverter.Convert(blockPos),
|
||||||
|
this.tintIndex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@@ -495,7 +542,7 @@ public class ClientBlockStateColorCache
|
|||||||
// only display the error once per block/biome type to reduce log spam
|
// only display the error once per block/biome type to reduce log spam
|
||||||
if (!BROKEN_BLOCK_STATES.contains(this.blockState))
|
if (!BROKEN_BLOCK_STATES.contains(this.blockState))
|
||||||
{
|
{
|
||||||
LOGGER.warn("Failed to get block color for block: [" + this.blockState + "] and biome: [" + biome + "] at pos: " + pos + ". Error: ["+e.getMessage() + "]. Note: future errors for this block/biome will be ignored.", e);
|
LOGGER.warn("Failed to get block color for block: [" + this.blockState + "] and biome: [" + biomeWrapper + "] at pos: " + blockPos + ". Error: ["+e.getMessage() + "]. Note: future errors for this block/biome will be ignored.", e);
|
||||||
BROKEN_BLOCK_STATES.add(this.blockState);
|
BROKEN_BLOCK_STATES.add(this.blockState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -519,7 +566,7 @@ public class ClientBlockStateColorCache
|
|||||||
// helper classes //
|
// helper classes //
|
||||||
//================//
|
//================//
|
||||||
|
|
||||||
enum ColorMode
|
private enum EColorMode
|
||||||
{
|
{
|
||||||
Default,
|
Default,
|
||||||
Flower,
|
Flower,
|
||||||
@@ -527,12 +574,24 @@ public class ClientBlockStateColorCache
|
|||||||
Chisel,
|
Chisel,
|
||||||
Glass;
|
Glass;
|
||||||
|
|
||||||
static ColorMode getColorMode(Block block)
|
static EColorMode getColorMode(Block block)
|
||||||
{
|
{
|
||||||
if (block instanceof LeavesBlock) return Leaves;
|
if (block instanceof LeavesBlock)
|
||||||
if (block instanceof FlowerBlock) return Flower;
|
{
|
||||||
if (block.toString().contains("glass")) return Glass;
|
return Leaves;
|
||||||
if (block.toString().equals("Block{chiselsandbits:chiseled}")) return Chisel;
|
}
|
||||||
|
if (block instanceof FlowerBlock)
|
||||||
|
{
|
||||||
|
return Flower;
|
||||||
|
}
|
||||||
|
if (block.toString().contains("glass"))
|
||||||
|
{
|
||||||
|
return Glass;
|
||||||
|
}
|
||||||
|
if (block.toString().equals("Block{chiselsandbits:chiseled}"))
|
||||||
|
{
|
||||||
|
return Chisel;
|
||||||
|
}
|
||||||
return Default;
|
return Default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+24
-36
@@ -19,10 +19,11 @@
|
|||||||
|
|
||||||
package com.seibel.distanthorizons.common.wrappers.block;
|
package com.seibel.distanthorizons.common.wrappers.block;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2;
|
||||||
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.world.level.*;
|
import net.minecraft.world.level.*;
|
||||||
import net.minecraft.world.level.biome.Biome;
|
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
@@ -38,9 +39,9 @@ import java.util.Optional;
|
|||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public class TintGetterOverrideFast implements BlockAndTintGetter
|
public class TintGetterOverride extends AbstractDhTintGetter
|
||||||
{
|
{
|
||||||
LevelReader parent;
|
private LevelReader parent;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -48,7 +49,13 @@ public class TintGetterOverrideFast implements BlockAndTintGetter
|
|||||||
// constructor //
|
// constructor //
|
||||||
//=============//
|
//=============//
|
||||||
|
|
||||||
public TintGetterOverrideFast(LevelReader parent) { this.parent = parent; }
|
public TintGetterOverride() { }
|
||||||
|
|
||||||
|
public void update(BiomeWrapper biomeWrapper, BlockStateWrapper blockStateWrapper, FullDataSourceV2 fullDataSource, IClientLevelWrapper clientLevelWrapper)
|
||||||
|
{
|
||||||
|
super.update(biomeWrapper, blockStateWrapper, fullDataSource, clientLevelWrapper);
|
||||||
|
this.parent = (LevelReader)this.clientLevelWrapper.getWrappedMcObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -56,18 +63,6 @@ public class TintGetterOverrideFast implements BlockAndTintGetter
|
|||||||
// methods //
|
// methods //
|
||||||
//=========//
|
//=========//
|
||||||
|
|
||||||
private Biome _getBiome(BlockPos pos)
|
|
||||||
{
|
|
||||||
#if MC_VER >= MC_1_18_2
|
|
||||||
return this.parent.getBiome(pos).value();
|
|
||||||
#else
|
|
||||||
return parent.getBiome(pos);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getBlockTint(BlockPos blockPos, ColorResolver colorResolver) { return colorResolver.getColor(this._getBiome(blockPos), blockPos.getX(), blockPos.getZ()); }
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public float getShade(Direction direction, boolean bl) { return this.parent.getShade(direction, bl); }
|
public float getShade(Direction direction, boolean bl) { return this.parent.getShade(direction, bl); }
|
||||||
|
|
||||||
@@ -87,7 +82,6 @@ public class TintGetterOverrideFast implements BlockAndTintGetter
|
|||||||
@Nullable
|
@Nullable
|
||||||
public BlockEntity getBlockEntity(BlockPos blockPos) { return this.parent.getBlockEntity(blockPos); }
|
public BlockEntity getBlockEntity(BlockPos blockPos) { return this.parent.getBlockEntity(blockPos); }
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BlockState getBlockState(BlockPos blockPos) { return this.parent.getBlockState(blockPos); }
|
public BlockState getBlockState(BlockPos blockPos) { return this.parent.getBlockState(blockPos); }
|
||||||
|
|
||||||
@@ -99,26 +93,25 @@ public class TintGetterOverrideFast implements BlockAndTintGetter
|
|||||||
|
|
||||||
#if MC_VER < MC_1_21_3
|
#if MC_VER < MC_1_21_3
|
||||||
@Override
|
@Override
|
||||||
public int getMaxLightLevel() { return parent.getMaxLightLevel(); }
|
public int getMaxLightLevel() { return this.parent.getMaxLightLevel(); }
|
||||||
#else
|
#else
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Stream<BlockState> getBlockStates(AABB aABB)
|
public Stream<BlockState> getBlockStates(AABB aABB) { return this.parent.getBlockStates(aABB); }
|
||||||
{ return this.parent.getBlockStates(aABB); }
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BlockHitResult clip(ClipContext clipContext)
|
public BlockHitResult clip(ClipContext clipContext) { return this.parent.clip(clipContext); }
|
||||||
{ return this.parent.clip(clipContext); }
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Nullable
|
@Nullable
|
||||||
public BlockHitResult clipWithInteractionOverride(Vec3 vec3, Vec3 vec32, BlockPos blockPos, VoxelShape voxelShape, BlockState blockState)
|
public BlockHitResult clipWithInteractionOverride(Vec3 vec3, Vec3 vec32, BlockPos blockPos, VoxelShape voxelShape, BlockState blockState)
|
||||||
{ return this.parent.clipWithInteractionOverride(vec3, vec32, blockPos, voxelShape, blockState); }
|
{
|
||||||
|
return this.parent.clipWithInteractionOverride(vec3, vec32, blockPos, voxelShape, blockState);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double getBlockFloorHeight(VoxelShape voxelShape, Supplier<VoxelShape> supplier)
|
public double getBlockFloorHeight(VoxelShape voxelShape, Supplier<VoxelShape> supplier) { return this.parent.getBlockFloorHeight(voxelShape, supplier); }
|
||||||
{ return this.parent.getBlockFloorHeight(voxelShape, supplier); }
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double getBlockFloorHeight(BlockPos blockPos) { return this.parent.getBlockFloorHeight(blockPos); }
|
public double getBlockFloorHeight(BlockPos blockPos) { return this.parent.getBlockFloorHeight(blockPos); }
|
||||||
@@ -131,20 +124,12 @@ public class TintGetterOverrideFast implements BlockAndTintGetter
|
|||||||
public int getMaxY() { return this.parent.getMaxY(); }
|
public int getMaxY() { return this.parent.getMaxY(); }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//==============//
|
|
||||||
// post MC 1.17 //
|
|
||||||
//==============//
|
|
||||||
|
|
||||||
#if MC_VER >= MC_1_17_1
|
#if MC_VER >= MC_1_17_1
|
||||||
@Override
|
@Override
|
||||||
public <T extends BlockEntity> Optional<T> getBlockEntity(BlockPos blockPos, BlockEntityType<T> blockEntityType)
|
public <T extends BlockEntity> Optional<T> getBlockEntity(BlockPos blockPos, BlockEntityType<T> blockEntityType) { return this.parent.getBlockEntity(blockPos, blockEntityType); }
|
||||||
{ return this.parent.getBlockEntity(blockPos, blockEntityType); }
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BlockHitResult isBlockInLine(ClipBlockStateContext clipBlockStateContext)
|
public BlockHitResult isBlockInLine(ClipBlockStateContext clipBlockStateContext) { return this.parent.isBlockInLine(clipBlockStateContext); }
|
||||||
{ return this.parent.isBlockInLine(clipBlockStateContext); }
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getHeight() { return this.parent.getHeight(); }
|
public int getHeight() { return this.parent.getHeight(); }
|
||||||
@@ -165,7 +150,7 @@ public class TintGetterOverrideFast implements BlockAndTintGetter
|
|||||||
public int getMinSection() { return this.parent.getMinSection(); }
|
public int getMinSection() { return this.parent.getMinSection(); }
|
||||||
#else
|
#else
|
||||||
@Override
|
@Override
|
||||||
public int getMinSectionY() { return BlockAndTintGetter.super.getMinSectionY(); }
|
public int getMinSectionY() { return super.getMinSectionY(); }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if MC_VER < MC_1_21_3
|
#if MC_VER < MC_1_21_3
|
||||||
@@ -191,4 +176,7 @@ public class TintGetterOverrideFast implements BlockAndTintGetter
|
|||||||
@Override
|
@Override
|
||||||
public int getSectionYFromSectionIndex(int i) { return this.parent.getSectionYFromSectionIndex(i); }
|
public int getSectionYFromSectionIndex(int i) { return this.parent.getSectionYFromSectionIndex(i); }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
-214
@@ -1,214 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.wrappers.block;
|
|
||||||
|
|
||||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
|
||||||
import net.minecraft.core.BlockPos;
|
|
||||||
import net.minecraft.core.Cursor3D;
|
|
||||||
import net.minecraft.core.Direction;
|
|
||||||
import net.minecraft.world.level.*;
|
|
||||||
import net.minecraft.world.level.biome.Biome;
|
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
|
||||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
|
||||||
import net.minecraft.world.level.lighting.LevelLightEngine;
|
|
||||||
import net.minecraft.world.level.material.FluidState;
|
|
||||||
import net.minecraft.world.phys.AABB;
|
|
||||||
import net.minecraft.world.phys.BlockHitResult;
|
|
||||||
import net.minecraft.world.phys.Vec3;
|
|
||||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
public class TintGetterOverrideSmooth implements BlockAndTintGetter
|
|
||||||
{
|
|
||||||
LevelReader parent;
|
|
||||||
public int smoothingRange;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//=============//
|
|
||||||
// constructor //
|
|
||||||
//=============//
|
|
||||||
|
|
||||||
public TintGetterOverrideSmooth(LevelReader parent, int smoothingRange)
|
|
||||||
{
|
|
||||||
this.parent = parent;
|
|
||||||
this.smoothingRange = smoothingRange;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//=========//
|
|
||||||
// methods //
|
|
||||||
//=========//
|
|
||||||
|
|
||||||
private Biome _getBiome(BlockPos pos)
|
|
||||||
{
|
|
||||||
#if MC_VER >= MC_1_18_2
|
|
||||||
return this.parent.getBiome(pos).value();
|
|
||||||
#else
|
|
||||||
return parent.getBiome(pos);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
public int calculateBlockTint(BlockPos blockPos, ColorResolver colorResolver)
|
|
||||||
{
|
|
||||||
int i = smoothingRange;
|
|
||||||
if (i == 0)
|
|
||||||
return colorResolver.getColor(_getBiome(blockPos), blockPos.getX(), blockPos.getZ());
|
|
||||||
int j = (i * 2 + 1) * (i * 2 + 1);
|
|
||||||
int k = 0;
|
|
||||||
int l = 0;
|
|
||||||
int m = 0;
|
|
||||||
Cursor3D cursor3D = new Cursor3D(blockPos.getX() - i, blockPos.getY(), blockPos.getZ() - i, blockPos.getX() + i, blockPos.getY(), blockPos.getZ() + i);
|
|
||||||
BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
|
|
||||||
while (cursor3D.advance())
|
|
||||||
{
|
|
||||||
mutableBlockPos.set(cursor3D.nextX(), cursor3D.nextY(), cursor3D.nextZ());
|
|
||||||
int n = colorResolver.getColor(this._getBiome(mutableBlockPos), mutableBlockPos.getX(), mutableBlockPos.getZ());
|
|
||||||
|
|
||||||
k += (n & 0xFF0000) >> 16;
|
|
||||||
l += (n & 0xFF00) >> 8;
|
|
||||||
m += n & 0xFF;
|
|
||||||
}
|
|
||||||
return (k / j & 0xFF) << 16 | (l / j & 0xFF) << 8 | m / j & 0xFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getBlockTint(BlockPos blockPos, ColorResolver colorResolver) { return this.calculateBlockTint(blockPos, colorResolver); }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public float getShade(Direction direction, boolean bl) { return this.parent.getShade(direction, bl); }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public LevelLightEngine getLightEngine() { return this.parent.getLightEngine(); }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getBrightness(LightLayer lightLayer, BlockPos blockPos) { return this.parent.getBrightness(lightLayer, blockPos); }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getRawBrightness(BlockPos blockPos, int i) { return this.parent.getRawBrightness(blockPos, i); }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean canSeeSky(BlockPos blockPos) { return this.parent.canSeeSky(blockPos); }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Nullable
|
|
||||||
public BlockEntity getBlockEntity(BlockPos blockPos) { return this.parent.getBlockEntity(blockPos); }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BlockState getBlockState(BlockPos blockPos) { return this.parent.getBlockState(blockPos); }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public FluidState getFluidState(BlockPos blockPos) { return this.parent.getFluidState(blockPos); }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getLightEmission(BlockPos blockPos) { return this.parent.getLightEmission(blockPos); }
|
|
||||||
|
|
||||||
#if MC_VER < MC_1_21_3
|
|
||||||
@Override
|
|
||||||
public int getMaxLightLevel() { return this.parent.getMaxLightLevel(); }
|
|
||||||
#else
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Stream<BlockState> getBlockStates(AABB aABB) { return this.parent.getBlockStates(aABB); }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BlockHitResult clip(ClipContext clipContext) { return this.parent.clip(clipContext); }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Nullable
|
|
||||||
public BlockHitResult clipWithInteractionOverride(Vec3 vec3, Vec3 vec32, BlockPos blockPos, VoxelShape voxelShape, BlockState blockState)
|
|
||||||
{
|
|
||||||
return this.parent.clipWithInteractionOverride(vec3, vec32, blockPos, voxelShape, blockState);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public double getBlockFloorHeight(VoxelShape voxelShape, Supplier<VoxelShape> supplier) { return this.parent.getBlockFloorHeight(voxelShape, supplier); }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public double getBlockFloorHeight(BlockPos blockPos) { return this.parent.getBlockFloorHeight(blockPos); }
|
|
||||||
|
|
||||||
#if MC_VER < MC_1_21_3
|
|
||||||
@Override
|
|
||||||
public int getMaxBuildHeight() { return this.parent.getMaxBuildHeight(); }
|
|
||||||
#else
|
|
||||||
@Override
|
|
||||||
public int getMaxY() { return this.parent.getMaxY(); }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if MC_VER >= MC_1_17_1
|
|
||||||
@Override
|
|
||||||
public <T extends BlockEntity> Optional<T> getBlockEntity(BlockPos blockPos, BlockEntityType<T> blockEntityType) { return this.parent.getBlockEntity(blockPos, blockEntityType); }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BlockHitResult isBlockInLine(ClipBlockStateContext clipBlockStateContext) { return this.parent.isBlockInLine(clipBlockStateContext); }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getHeight() { return this.parent.getHeight(); }
|
|
||||||
|
|
||||||
#if MC_VER < MC_1_21_3
|
|
||||||
@Override
|
|
||||||
public int getMinBuildHeight() { return this.parent.getMinBuildHeight(); }
|
|
||||||
#else
|
|
||||||
@Override
|
|
||||||
public int getMinY() { return this.parent.getMinY(); }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getSectionsCount() { return this.parent.getSectionsCount(); }
|
|
||||||
|
|
||||||
#if MC_VER < MC_1_21_3
|
|
||||||
@Override
|
|
||||||
public int getMinSection() { return this.parent.getMinSection(); }
|
|
||||||
#else
|
|
||||||
@Override
|
|
||||||
public int getMinSectionY() { return BlockAndTintGetter.super.getMinSectionY(); }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if MC_VER < MC_1_21_3
|
|
||||||
@Override
|
|
||||||
public int getMaxSection() { return this.parent.getMaxSection(); }
|
|
||||||
#else
|
|
||||||
@Override
|
|
||||||
public int getMaxSectionY() { return this.parent.getMaxSectionY(); }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isOutsideBuildHeight(BlockPos blockPos) { return this.parent.isOutsideBuildHeight(blockPos); }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isOutsideBuildHeight(int i) { return this.parent.isOutsideBuildHeight(i); }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getSectionIndex(int i) { return this.parent.getSectionIndex(i); }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getSectionIndexFromSectionY(int i) { return this.parent.getSectionIndexFromSectionY(i); }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getSectionYFromSectionIndex(int i) { return this.parent.getSectionYFromSectionIndex(i); }
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
+24
-117
@@ -19,143 +19,50 @@
|
|||||||
|
|
||||||
package com.seibel.distanthorizons.common.wrappers.block;
|
package com.seibel.distanthorizons.common.wrappers.block;
|
||||||
|
|
||||||
import com.seibel.distanthorizons.core.util.ColorUtil;
|
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2;
|
||||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.world.level.*;
|
import net.minecraft.world.level.LevelReader;
|
||||||
import net.minecraft.world.level.biome.Biome;
|
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.level.lighting.LevelLightEngine;
|
import net.minecraft.world.level.lighting.LevelLightEngine;
|
||||||
import net.minecraft.world.level.material.FluidState;
|
import net.minecraft.world.level.material.FluidState;
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
#if MC_VER >= MC_1_18_2
|
public class TintWithoutLevelOverrider extends AbstractDhTintGetter
|
||||||
import net.minecraft.core.Holder;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
public class TintWithoutLevelOverrider implements BlockAndTintGetter
|
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* This will only ever be null if there was an issue with {@link IClientLevelWrapper#getPlainsBiomeWrapper()}
|
|
||||||
* but {@link Nullable} is there just in case.
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
#if MC_VER >= MC_1_18_2
|
|
||||||
public final Holder<Biome> biome;
|
|
||||||
#else
|
|
||||||
public final Biome biome;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
//=============//
|
||||||
* Constructs the TintWithoutLevelOverrider, storing the provided Biome Holder for late-binding access.
|
// constructor //
|
||||||
*
|
//=============//
|
||||||
* <p>Previously, this class might have immediately unwrapped the Holder like this:</p>
|
|
||||||
* <pre>{@code
|
public TintWithoutLevelOverrider()
|
||||||
* // Inside constructor (OLD WAY - PROBLEMATIC):
|
{ }
|
||||||
* Holder<Biome> biomeHolder = getTheHolderFromSomewhere();
|
|
||||||
* this.biome = biomeHolder.value(); // <-- PROBLEM HERE
|
|
||||||
* }</pre>
|
|
||||||
*
|
|
||||||
* <p>This approach is problematic because the {@link net.minecraft.core.Holder} system,
|
|
||||||
* particularly {@code Holder.Reference}, is designed for <strong>late binding</strong>. Here's why storing
|
|
||||||
* the Holder itself is now necessary:</p>
|
|
||||||
* <ol>
|
|
||||||
* <li>A {@code Holder.Reference<Biome>} might be created initially just with a
|
|
||||||
* {@link net.minecraft.resources.ResourceKey} (like {@code minecraft:plains}), but its actual
|
|
||||||
* {@link net.minecraft.core.Holder#value() value()} (the {@code Biome} object itself) might be {@code null}
|
|
||||||
* at construction time.</li>
|
|
||||||
* <li>Later, during game loading, registry population, or potentially due to modifications by other mods
|
|
||||||
* (e.g., Polytone), the system calls internal binding methods (like {@code bindValue(Biome)})
|
|
||||||
* on the {@code Holder} instance. This sets or <strong>updates</strong> the internal reference to the
|
|
||||||
* actual {@code Biome} object.</li>
|
|
||||||
* <li>Crucially, the binding process might assign a completely <strong>new</strong> {@code Biome} object
|
|
||||||
* instance to the {@code Holder} reference, replacing any previous one.</li>
|
|
||||||
* </ol>
|
|
||||||
*
|
|
||||||
* <p>If we unwrapped the {@code Holder} using {@code .value()} within the constructor (the old way),
|
|
||||||
* our class's internal {@code biome} field would permanently store a reference to whatever {@code Biome}
|
|
||||||
* object the {@code Holder} pointed to *at that exact moment*. It would have no link back to the
|
|
||||||
* {@code Holder} and would be unaware if the {@code Holder} was later updated to point to a different
|
|
||||||
* (or the initially missing) {@code Biome} object. This would lead to using stale or even {@code null} data.</p>
|
|
||||||
*
|
|
||||||
* <p>By storing the {@code Holder<Biome>} itself, this class can call {@link net.minecraft.core.Holder#value()}
|
|
||||||
* whenever the biome information is needed, ensuring it always retrieves the most current {@code Biome}
|
|
||||||
* instance associated with the holder at that time.</p>
|
|
||||||
*/
|
|
||||||
public TintWithoutLevelOverrider(BiomeWrapper biomeWrapper, IClientLevelWrapper clientLevelWrapper)
|
|
||||||
{
|
|
||||||
#if MC_VER >= MC_1_18_2 Holder<Biome> #else Biome #endif biome = biomeWrapper.biome;
|
|
||||||
if (biome == null) // We are looking at the empty biome wrapper
|
|
||||||
{
|
|
||||||
BiomeWrapper plainsBiomeWrapper = ((BiomeWrapper) clientLevelWrapper.getPlainsBiomeWrapper());
|
|
||||||
if (plainsBiomeWrapper != null)
|
|
||||||
{
|
|
||||||
biome = plainsBiomeWrapper.biome;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.biome = biome;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=========//
|
||||||
|
// methods //
|
||||||
|
//=========//
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getBlockTint(@NotNull BlockPos blockPos, @NotNull ColorResolver colorResolver)
|
public float getShade(Direction direction, boolean shade)
|
||||||
{
|
{ throw new UnsupportedOperationException("ERROR: getShade() called on TintWithoutLevelOverrider. Object is for tinting only."); }
|
||||||
if (this.biome == null)
|
|
||||||
{
|
|
||||||
// hopefully unneeded debug color
|
|
||||||
return ColorUtil.CYAN;
|
|
||||||
}
|
|
||||||
return colorResolver.getColor(unwrap(biome), blockPos.getX(), blockPos.getZ());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Biome unwrap(#if MC_VER >= MC_1_18_2 Holder<Biome> #else Biome #endif biome)
|
|
||||||
{
|
|
||||||
#if MC_VER >= MC_1_18_2
|
|
||||||
return biome.value();
|
|
||||||
#else
|
|
||||||
return biome;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//================//
|
|
||||||
// unused methods //
|
|
||||||
//================//
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public float getShade(@NotNull Direction direction, boolean shade)
|
public LevelLightEngine getLightEngine()
|
||||||
{
|
{ throw new UnsupportedOperationException("ERROR: getLightEngine() called on TintWithoutLevelOverrider. Object is for tinting only."); }
|
||||||
throw new UnsupportedOperationException("ERROR: getShade() called on TintWithoutLevelOverrider. Object is for tinting only.");
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public @NotNull LevelLightEngine getLightEngine()
|
|
||||||
{
|
|
||||||
throw new UnsupportedOperationException("ERROR: getLightEngine() called on TintWithoutLevelOverrider. Object is for tinting only.");
|
|
||||||
}
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public BlockEntity getBlockEntity(@NotNull BlockPos pos)
|
public BlockEntity getBlockEntity(BlockPos pos)
|
||||||
{
|
{ throw new UnsupportedOperationException("ERROR: getBlockEntity() called on TintWithoutLevelOverrider. Object is for tinting only."); }
|
||||||
throw new UnsupportedOperationException("ERROR: getBlockEntity() called on TintWithoutLevelOverrider. Object is for tinting only.");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull BlockState getBlockState(@NotNull BlockPos pos)
|
public BlockState getBlockState(BlockPos pos)
|
||||||
{
|
{ throw new UnsupportedOperationException("ERROR: getBlockState() called on TintWithoutLevelOverrider. Object is for tinting only."); }
|
||||||
throw new UnsupportedOperationException("ERROR: getBlockState() called on TintWithoutLevelOverrider. Object is for tinting only.");
|
|
||||||
}
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull FluidState getFluidState(@NotNull BlockPos pos)
|
public FluidState getFluidState(BlockPos pos)
|
||||||
{
|
{ throw new UnsupportedOperationException("ERROR: getFluidState() called on TintWithoutLevelOverrider. Object is for tinting only."); }
|
||||||
throw new UnsupportedOperationException("ERROR: getFluidState() called on TintWithoutLevelOverrider. Object is for tinting only.");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//==============//
|
//==============//
|
||||||
@@ -171,7 +78,7 @@ public class TintWithoutLevelOverrider implements BlockAndTintGetter
|
|||||||
#if MC_VER < MC_1_21_3
|
#if MC_VER < MC_1_21_3
|
||||||
@Override
|
@Override
|
||||||
public int getMinBuildHeight()
|
public int getMinBuildHeight()
|
||||||
{ throw new UnsupportedOperationException("ERROR: getMinBuildHeight() called on TintWithoutLevelOverrider. Object is for tinting only."); }
|
{ throw new UnsupportedOperationException("ERROR: getMinBuildHeight() called on TintWithoutLevelSmoothOverrider. Object is for tinting only."); }
|
||||||
#else
|
#else
|
||||||
@Override
|
@Override
|
||||||
public int getMinY()
|
public int getMinY()
|
||||||
|
|||||||
-144
@@ -1,144 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.wrappers.block;
|
|
||||||
|
|
||||||
import net.minecraft.core.BlockPos;
|
|
||||||
import net.minecraft.core.Direction;
|
|
||||||
import net.minecraft.world.level.BlockAndTintGetter;
|
|
||||||
import net.minecraft.world.level.ColorResolver;
|
|
||||||
import net.minecraft.world.level.biome.Biome;
|
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
|
||||||
import net.minecraft.world.level.lighting.LevelLightEngine;
|
|
||||||
import net.minecraft.world.level.material.FluidState;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
#if MC_VER >= MC_1_18_2
|
|
||||||
import net.minecraft.core.Holder;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
public class TintWithoutLevelSmoothOverrider implements BlockAndTintGetter
|
|
||||||
{
|
|
||||||
final BiomeWrapper biome;
|
|
||||||
public int smoothingRange;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//=============//
|
|
||||||
// constructor //
|
|
||||||
//=============//
|
|
||||||
|
|
||||||
public TintWithoutLevelSmoothOverrider(BiomeWrapper biome, int smoothingRange)
|
|
||||||
{
|
|
||||||
this.biome = biome;
|
|
||||||
this.smoothingRange = smoothingRange;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//=========//
|
|
||||||
// methods //
|
|
||||||
//=========//
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getBlockTint(BlockPos blockPos, ColorResolver colorResolver)
|
|
||||||
{
|
|
||||||
return colorResolver.getColor(_unwrap(biome.biome), blockPos.getX(), blockPos.getZ());
|
|
||||||
}
|
|
||||||
private Biome _unwrap(#if MC_VER >= MC_1_18_2 Holder<Biome> #else Biome #endif biome)
|
|
||||||
{
|
|
||||||
#if MC_VER >= MC_1_18_2
|
|
||||||
return biome.value();
|
|
||||||
#else
|
|
||||||
return biome;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// public int calculateBlockTint(BlockPos blockPos, ColorResolver colorResolver)
|
|
||||||
// {
|
|
||||||
// int i = smoothingRange;
|
|
||||||
// if (i == 0)
|
|
||||||
// return colorResolver.getColor(_getBiome(blockPos), blockPos.getX(), blockPos.getZ());
|
|
||||||
// int j = (i * 2 + 1) * (i * 2 + 1);
|
|
||||||
// int k = 0;
|
|
||||||
// int l = 0;
|
|
||||||
// int m = 0;
|
|
||||||
// Cursor3D cursor3D = new Cursor3D(blockPos.getX() - i, blockPos.getY(), blockPos.getZ() - i, blockPos.getX() + i, blockPos.getY(), blockPos.getZ() + i);
|
|
||||||
// BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
|
|
||||||
// while (cursor3D.advance())
|
|
||||||
// {
|
|
||||||
// mutableBlockPos.set(cursor3D.nextX(), cursor3D.nextY(), cursor3D.nextZ());
|
|
||||||
// int n;
|
|
||||||
// if (LodCommonMain.forgeMethodCaller != null) {
|
|
||||||
// n = LodCommonMain.forgeMethodCaller.colorResolverGetColor(colorResolver, _getBiome(mutableBlockPos),
|
|
||||||
// mutableBlockPos.getX(), mutableBlockPos.getZ());
|
|
||||||
// } else {
|
|
||||||
// n = colorResolver.getColor(_getBiome(mutableBlockPos), mutableBlockPos.getX(), mutableBlockPos.getZ());
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// k += (n & 0xFF0000) >> 16;
|
|
||||||
// l += (n & 0xFF00) >> 8;
|
|
||||||
// m += n & 0xFF;
|
|
||||||
// }
|
|
||||||
// return (k / j & 0xFF) << 16 | (l / j & 0xFF) << 8 | m / j & 0xFF;
|
|
||||||
// }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public float getShade(Direction direction, boolean shade)
|
|
||||||
{ throw new UnsupportedOperationException("ERROR: getShade() called on TintWithoutLevelSmoothOverrider. Object is for tinting only."); }
|
|
||||||
@Override
|
|
||||||
public LevelLightEngine getLightEngine()
|
|
||||||
{ throw new UnsupportedOperationException("ERROR: getLightEngine() called on TintWithoutLevelSmoothOverrider. Object is for tinting only."); }
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public BlockEntity getBlockEntity(BlockPos pos)
|
|
||||||
{ throw new UnsupportedOperationException("ERROR: getBlockEntity() called on TintWithoutLevelSmoothOverrider. Object is for tinting only."); }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BlockState getBlockState(BlockPos pos)
|
|
||||||
{ throw new UnsupportedOperationException("ERROR: getBlockState() called on TintWithoutLevelSmoothOverrider. Object is for tinting only."); }
|
|
||||||
@Override
|
|
||||||
public FluidState getFluidState(BlockPos pos)
|
|
||||||
{ throw new UnsupportedOperationException("ERROR: getFluidState() called on TintWithoutLevelSmoothOverrider. Object is for tinting only."); }
|
|
||||||
|
|
||||||
|
|
||||||
//==============//
|
|
||||||
// post MC 1.17 //
|
|
||||||
//==============//
|
|
||||||
|
|
||||||
#if MC_VER >= MC_1_17_1
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getHeight()
|
|
||||||
{ throw new UnsupportedOperationException("ERROR: getHeight() called on TintWithoutLevelSmoothOverrider. Object is for tinting only."); }
|
|
||||||
|
|
||||||
#if MC_VER < MC_1_21_3
|
|
||||||
@Override
|
|
||||||
public int getMinBuildHeight()
|
|
||||||
{ throw new UnsupportedOperationException("ERROR: getMinBuildHeight() called on TintWithoutLevelSmoothOverrider. Object is for tinting only."); }
|
|
||||||
#else
|
|
||||||
@Override
|
|
||||||
public int getMinY()
|
|
||||||
{ throw new UnsupportedOperationException("ERROR: getMinY() called on TintWithoutLevelSmoothOverrider. Object is for tinting only."); }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
|
||||||
+99
-76
@@ -18,10 +18,10 @@
|
|||||||
*/
|
*/
|
||||||
package com.seibel.distanthorizons.common.wrappers.chunk;
|
package com.seibel.distanthorizons.common.wrappers.chunk;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.api.DhApi;
|
||||||
import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper;
|
import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper;
|
||||||
import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper;
|
import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper;
|
||||||
import com.seibel.distanthorizons.common.wrappers.misc.MutableBlockPosWrapper;
|
import com.seibel.distanthorizons.common.wrappers.misc.MutableBlockPosWrapper;
|
||||||
import com.seibel.distanthorizons.core.config.Config;
|
|
||||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos;
|
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos;
|
||||||
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
||||||
@@ -38,9 +38,10 @@ import net.minecraft.world.level.chunk.ChunkAccess;
|
|||||||
import net.minecraft.world.level.chunk.ProtoChunk;
|
import net.minecraft.world.level.chunk.ProtoChunk;
|
||||||
import net.minecraft.world.level.levelgen.Heightmap;
|
import net.minecraft.world.level.levelgen.Heightmap;
|
||||||
|
|
||||||
import org.apache.logging.log4j.Logger;
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
#if MC_VER >= MC_1_17_1
|
#if MC_VER >= MC_1_17_1
|
||||||
import net.minecraft.core.QuartPos;
|
import net.minecraft.core.QuartPos;
|
||||||
@@ -75,12 +76,16 @@ import net.minecraft.world.level.chunk.status.ChunkStatus;
|
|||||||
|
|
||||||
public class ChunkWrapper implements IChunkWrapper
|
public class ChunkWrapper implements IChunkWrapper
|
||||||
{
|
{
|
||||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
|
|
||||||
/** can be used for interactions with the underlying chunk where creating new BlockPos objects could cause issues for the garbage collector. */
|
/** can be used for interactions with the underlying chunk where creating new BlockPos objects could cause issues for the garbage collector. */
|
||||||
private static final ThreadLocal<BlockPos.MutableBlockPos> MUTABLE_BLOCK_POS_REF = ThreadLocal.withInitial(() -> new BlockPos.MutableBlockPos());
|
private static final ThreadLocal<BlockPos.MutableBlockPos> MUTABLE_BLOCK_POS_REF = ThreadLocal.withInitial(() -> new BlockPos.MutableBlockPos());
|
||||||
private static final ThreadLocal<MutableBlockPosWrapper> MUTABLE_BLOCK_POS_WRAPPER_REF = ThreadLocal.withInitial(() -> new MutableBlockPosWrapper());
|
private static final ThreadLocal<MutableBlockPosWrapper> MUTABLE_BLOCK_POS_WRAPPER_REF = ThreadLocal.withInitial(() -> new MutableBlockPosWrapper());
|
||||||
|
|
||||||
|
public static final Set<String> LOGGED_BLOCK_GET_ERRORS = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
|
||||||
|
|
||||||
|
private static boolean heightmapThreadWarningLogged = false;
|
||||||
|
|
||||||
|
|
||||||
private final ChunkAccess chunk;
|
private final ChunkAccess chunk;
|
||||||
private final DhChunkPos chunkPos;
|
private final DhChunkPos chunkPos;
|
||||||
@@ -98,9 +103,9 @@ public class ChunkWrapper implements IChunkWrapper
|
|||||||
private int maxNonEmptyHeight = Integer.MAX_VALUE;
|
private int maxNonEmptyHeight = Integer.MAX_VALUE;
|
||||||
|
|
||||||
/** will be null if we are using MC heightmaps */
|
/** will be null if we are using MC heightmaps */
|
||||||
private final int[][] solidHeightMap;
|
private int[][] solidHeightMap = null;
|
||||||
/** will be null if we are using MC heightmaps */
|
/** will be null if we are using MC heightmaps */
|
||||||
private final int[][] lightBlockingHeightMap;
|
private int[][] lightBlockingHeightMap = null;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -108,27 +113,21 @@ public class ChunkWrapper implements IChunkWrapper
|
|||||||
// constructor //
|
// constructor //
|
||||||
//=============//
|
//=============//
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note: this constructor should be very
|
||||||
|
* fast since it will be called frequently on the MC
|
||||||
|
* server thread and a slow method will cause server lag.
|
||||||
|
*/
|
||||||
public ChunkWrapper(ChunkAccess chunk, ILevelWrapper wrappedLevel)
|
public ChunkWrapper(ChunkAccess chunk, ILevelWrapper wrappedLevel)
|
||||||
{
|
{
|
||||||
this.chunk = chunk;
|
this.chunk = chunk;
|
||||||
this.wrappedLevel = wrappedLevel;
|
this.wrappedLevel = wrappedLevel;
|
||||||
this.chunkPos = new DhChunkPos(chunk.getPos().x, chunk.getPos().z);
|
this.chunkPos = new DhChunkPos(chunk.getPos().x, chunk.getPos().z);
|
||||||
|
|
||||||
// use DH heightmaps if requested
|
|
||||||
if (Config.Common.LodBuilding.recalculateChunkHeightmaps.get())
|
|
||||||
{
|
|
||||||
this.solidHeightMap = new int[LodUtil.CHUNK_WIDTH][LodUtil.CHUNK_WIDTH];
|
|
||||||
this.lightBlockingHeightMap = new int[LodUtil.CHUNK_WIDTH][LodUtil.CHUNK_WIDTH];
|
|
||||||
|
|
||||||
this.recalculateDhHeightMapsIfNeeded();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this.solidHeightMap = null;
|
|
||||||
this.lightBlockingHeightMap = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChunkWrapper copy() { return new ChunkWrapper(this.chunk, this.wrappedLevel); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//=========//
|
//=========//
|
||||||
@@ -248,56 +247,64 @@ public class ChunkWrapper implements IChunkWrapper
|
|||||||
}
|
}
|
||||||
private int getChunkSectionMinHeight(int index) { return (index * 16) + this.getInclusiveMinBuildHeight(); }
|
private int getChunkSectionMinHeight(int index) { return (index * 16) + this.getInclusiveMinBuildHeight(); }
|
||||||
|
|
||||||
/** Will only run if the config says the MC heightmaps shouldn't be trusted. */
|
@Override
|
||||||
public void recalculateDhHeightMapsIfNeeded()
|
public void createDhHeightMaps()
|
||||||
{
|
{
|
||||||
// re-calculate the min/max heights for consistency (during world gen these may be wrong)
|
if (heightmapThreadWarningLogged
|
||||||
this.minNonEmptyHeight = Integer.MIN_VALUE;
|
&& !DhApi.isDhThread())
|
||||||
this.maxNonEmptyHeight = Integer.MAX_VALUE;
|
|
||||||
|
|
||||||
|
|
||||||
// recalculate heightmaps if needed
|
|
||||||
if (this.solidHeightMap != null)
|
|
||||||
{
|
{
|
||||||
for (int x = 0; x < LodUtil.CHUNK_WIDTH; x++)
|
heightmapThreadWarningLogged = true;
|
||||||
|
LOGGER.warn("ChunkWrapper Height maps created on non-DH thread ["+Thread.currentThread().getName()+"]. This may cause stuttering.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
this.solidHeightMap = new int[LodUtil.CHUNK_WIDTH][LodUtil.CHUNK_WIDTH];
|
||||||
|
this.lightBlockingHeightMap = new int[LodUtil.CHUNK_WIDTH][LodUtil.CHUNK_WIDTH];
|
||||||
|
|
||||||
|
for (int x = 0; x < LodUtil.CHUNK_WIDTH; x++)
|
||||||
|
{
|
||||||
|
for (int z = 0; z < LodUtil.CHUNK_WIDTH; z++)
|
||||||
{
|
{
|
||||||
for (int z = 0; z < LodUtil.CHUNK_WIDTH; z++)
|
int minInclusiveBuildHeight = this.getMinNonEmptyHeight();
|
||||||
|
// if no blocks are found the height map will be at the bottom of the world
|
||||||
|
int solidHeight = minInclusiveBuildHeight;
|
||||||
|
int lightBlockingHeight = minInclusiveBuildHeight;
|
||||||
|
|
||||||
|
|
||||||
|
int y = this.getMaxNonEmptyHeight(); //this.getExclusiveMaxBuildHeight();
|
||||||
|
IBlockStateWrapper block = this.getBlockState(x, y, z);
|
||||||
|
while (// go down until we reach the minimum build height
|
||||||
|
y > minInclusiveBuildHeight
|
||||||
|
// keep going until we find both height map values
|
||||||
|
&&
|
||||||
|
(
|
||||||
|
solidHeight == minInclusiveBuildHeight
|
||||||
|
|| lightBlockingHeight == minInclusiveBuildHeight
|
||||||
|
)
|
||||||
|
)
|
||||||
{
|
{
|
||||||
int minInclusiveBuildHeight = this.getMinNonEmptyHeight();
|
// is this block solid?
|
||||||
// if no blocks are found the height map will be at the bottom of the world
|
if (solidHeight == minInclusiveBuildHeight
|
||||||
int solidHeight = minInclusiveBuildHeight;
|
&& block.isSolid())
|
||||||
int lightBlockingHeight = minInclusiveBuildHeight;
|
|
||||||
|
|
||||||
|
|
||||||
int y = this.getMaxNonEmptyHeight(); //this.getExclusiveMaxBuildHeight();
|
|
||||||
IBlockStateWrapper block = this.getBlockState(x, y, z);
|
|
||||||
while (// go down until we reach the minimum build height
|
|
||||||
y > minInclusiveBuildHeight
|
|
||||||
// keep going until we find both height map values
|
|
||||||
&& (solidHeight == minInclusiveBuildHeight || lightBlockingHeight == minInclusiveBuildHeight))
|
|
||||||
{
|
{
|
||||||
// is this block solid?
|
solidHeight = y;
|
||||||
if (solidHeight == minInclusiveBuildHeight
|
|
||||||
&& block.isSolid())
|
|
||||||
{
|
|
||||||
solidHeight = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
// is this block light blocking?
|
|
||||||
if (lightBlockingHeight == minInclusiveBuildHeight
|
|
||||||
&& block.getOpacity() != LodUtil.BLOCK_FULLY_TRANSPARENT)
|
|
||||||
{
|
|
||||||
lightBlockingHeight = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the next block down
|
|
||||||
y--;
|
|
||||||
block = this.getBlockState(x, y, z);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.solidHeightMap[x][z] = solidHeight;
|
// is this block light blocking?
|
||||||
this.lightBlockingHeightMap[x][z] = lightBlockingHeight;
|
if (lightBlockingHeight == minInclusiveBuildHeight
|
||||||
|
&& block.getOpacity() != LodUtil.BLOCK_FULLY_TRANSPARENT)
|
||||||
|
{
|
||||||
|
lightBlockingHeight = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the next block down
|
||||||
|
y--;
|
||||||
|
block = this.getBlockState(x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.solidHeightMap[x][z] = solidHeight;
|
||||||
|
this.lightBlockingHeightMap[x][z] = lightBlockingHeight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -368,8 +375,19 @@ public class ChunkWrapper implements IChunkWrapper
|
|||||||
blockPos.setY(relY);
|
blockPos.setY(relY);
|
||||||
blockPos.setZ(relZ);
|
blockPos.setZ(relZ);
|
||||||
|
|
||||||
// TODO copy into pooled array, this isn't thread safe and can cause MC to throw errors if the chunk is loaded
|
try
|
||||||
return BlockStateWrapper.fromBlockState(this.chunk.getBlockState(blockPos), this.wrappedLevel);
|
{
|
||||||
|
return BlockStateWrapper.fromBlockState(this.chunk.getBlockState(blockPos), this.wrappedLevel);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
if (LOGGED_BLOCK_GET_ERRORS.add(e.getMessage()))
|
||||||
|
{
|
||||||
|
LOGGER.warn("Failed to get block from chunk ["+this.chunkPos+"] at relative block pos ["+relX+","+relY+","+relZ+"], air will be used instead. This error message will only be logged once. error: ["+e.getMessage()+"].", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return BlockStateWrapper.AIR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -381,8 +399,20 @@ public class ChunkWrapper implements IChunkWrapper
|
|||||||
pos.setX(relX);
|
pos.setX(relX);
|
||||||
pos.setY(relY);
|
pos.setY(relY);
|
||||||
pos.setZ(relZ);
|
pos.setZ(relZ);
|
||||||
|
|
||||||
return BlockStateWrapper.fromBlockState(this.chunk.getBlockState(pos), this.wrappedLevel, guess);
|
try
|
||||||
|
{
|
||||||
|
return BlockStateWrapper.fromBlockState(this.chunk.getBlockState(pos), this.wrappedLevel, guess);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
if (LOGGED_BLOCK_GET_ERRORS.add(e.getMessage()))
|
||||||
|
{
|
||||||
|
LOGGER.warn("Failed to get block from chunk ["+this.chunkPos+"] at relative block pos ["+relX+","+relY+","+relZ+"], air will be used instead. This error message will only be logged once. error: ["+e.getMessage()+"].", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return BlockStateWrapper.AIR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -410,8 +440,10 @@ public class ChunkWrapper implements IChunkWrapper
|
|||||||
LevelChunkSection section = sections[i];
|
LevelChunkSection section = sections[i];
|
||||||
if (section != null)
|
if (section != null)
|
||||||
{
|
{
|
||||||
// TODO implement section cloning for older MC versions, only 1.21.4 MC (and maybe other semi recent versions) have a clean way to handle this
|
// Implementation notes:
|
||||||
// TODO we probably want a wrapper object instead
|
// implement section cloning for older MC versions, only 1.21.4 MC (and maybe other semi recent versions) have a clean way to handle this
|
||||||
|
// we probably want a wrapper object instead
|
||||||
|
|
||||||
#if MC_VER < MC_1_21_4
|
#if MC_VER < MC_1_21_4
|
||||||
this.levelChunkSections[i] = section;
|
this.levelChunkSections[i] = section;
|
||||||
#else
|
#else
|
||||||
@@ -617,15 +649,6 @@ public class ChunkWrapper implements IChunkWrapper
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
//===============//
|
|
||||||
// other methods //
|
|
||||||
//===============//
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isStillValid() { return this.wrappedLevel.tryGetChunk(this.chunkPos) == this; }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//================//
|
//================//
|
||||||
// base overrides //
|
// base overrides //
|
||||||
//================//
|
//================//
|
||||||
|
|||||||
+826
-442
File diff suppressed because it is too large
Load Diff
+98
@@ -0,0 +1,98 @@
|
|||||||
|
package com.seibel.distanthorizons.common.wrappers.gui;
|
||||||
|
|
||||||
|
#if MC_VER < MC_1_21_9
|
||||||
|
// not supported for older MC versions
|
||||||
|
#else
|
||||||
|
import com.seibel.distanthorizons.core.logging.f3.F3Screen;
|
||||||
|
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import net.minecraft.client.gui.components.debug.DebugScreenDisplayer;
|
||||||
|
import net.minecraft.client.gui.components.debug.DebugScreenEntries;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.chunk.LevelChunk;
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_21_10
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MC_VER < MC_1_21_9
|
||||||
|
// not supported for older MC versions
|
||||||
|
public class DhDebugScreenEntry
|
||||||
|
{}
|
||||||
|
#else
|
||||||
|
public class DhDebugScreenEntry implements net.minecraft.client.gui.components.debug.DebugScreenEntry
|
||||||
|
{
|
||||||
|
public static void register()
|
||||||
|
{
|
||||||
|
// This method is private, so its access will need to be widened
|
||||||
|
DebugScreenEntries.register(
|
||||||
|
// The id, this will be displayed on the options screen
|
||||||
|
#if MC_VER <= MC_1_21_10
|
||||||
|
ResourceLocation.fromNamespaceAndPath(ModInfo.RESOURCE_NAMESPACE, "distant_horizons"),
|
||||||
|
#else
|
||||||
|
"distant_horizons",
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// The screen entry
|
||||||
|
new DhDebugScreenEntry()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void display(@NotNull DebugScreenDisplayer displayer, @Nullable Level level, @Nullable LevelChunk clientChunk, @Nullable LevelChunk serverChunk)
|
||||||
|
{
|
||||||
|
List<String> messageList = new ArrayList<>();
|
||||||
|
F3Screen.addStringToDisplay(messageList);
|
||||||
|
|
||||||
|
for (String message : messageList)
|
||||||
|
{
|
||||||
|
displayer.addLine(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
//// The following will display like so if it is the only entry on the screen:
|
||||||
|
//// First left! First Right!
|
||||||
|
////
|
||||||
|
//// Hello world! Random text!
|
||||||
|
//// Lorem ipsum.
|
||||||
|
//// I am another group!
|
||||||
|
//// I am one group This will appear after with no line breaks!
|
||||||
|
//// All in a row
|
||||||
|
//// Provided in a list.
|
||||||
|
////
|
||||||
|
//
|
||||||
|
//displayer.addLine("Hello world!");
|
||||||
|
//displayer.addLine("Lorem ipsum.");
|
||||||
|
//displayer.addLine("Random text!");
|
||||||
|
//
|
||||||
|
//// These will be displayed first
|
||||||
|
//displayer.addPriorityLine("First left!");
|
||||||
|
//displayer.addPriorityLine("First right!");
|
||||||
|
//
|
||||||
|
//// These will be grouped separately based on the key
|
||||||
|
//displayer.addToGroup(GROUP_ONE, List.of(
|
||||||
|
// "I am one group",
|
||||||
|
// "All in a row",
|
||||||
|
// "Provided in a list."
|
||||||
|
//));
|
||||||
|
//
|
||||||
|
//displayer.addToGroup(GROUP_TWO, "I am another group!");
|
||||||
|
//displayer.addToGroup(GROUP_TWO, "This will appear after with no line breaks!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAllowed(boolean reducedDebugInfo)
|
||||||
|
{
|
||||||
|
// Always show regardless of accessibility option
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -52,6 +52,27 @@ public class DhScreen extends Screen
|
|||||||
{
|
{
|
||||||
renderTooltip(guiStack, comp, x, y);
|
renderTooltip(guiStack, comp, x, y);
|
||||||
}
|
}
|
||||||
|
#elif MC_VER < MC_1_21_6
|
||||||
|
protected void DhDrawCenteredString(GuiGraphics guiStack, Font font, Component text, int x, int y, int color)
|
||||||
|
{
|
||||||
|
guiStack.drawCenteredString(font, text, x, y, color);
|
||||||
|
}
|
||||||
|
protected void DhDrawString(GuiGraphics guiStack, Font font, Component text, int x, int y, int color)
|
||||||
|
{
|
||||||
|
guiStack.drawString(font, text, x, y, color);
|
||||||
|
}
|
||||||
|
//protected void DhRenderTooltip(GuiGraphics guiStack, Font font, List<? extends net.minecraft.util.FormattedCharSequence> text, int x, int y)
|
||||||
|
//{
|
||||||
|
// guiStack.renderTooltip(font, text, x, y);
|
||||||
|
//}
|
||||||
|
protected void DhRenderComponentTooltip(GuiGraphics guiStack, Font font, List<Component> comp, int x, int y)
|
||||||
|
{
|
||||||
|
guiStack.renderComponentTooltip(font, comp, x, y);
|
||||||
|
}
|
||||||
|
protected void DhRenderTooltip(GuiGraphics guiStack, Font font, Component text, int x, int y)
|
||||||
|
{
|
||||||
|
guiStack.renderTooltip(font, text, x, y);
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
protected void DhDrawCenteredString(GuiGraphics guiStack, Font font, Component text, int x, int y, int color)
|
protected void DhDrawCenteredString(GuiGraphics guiStack, Font font, Component text, int x, int y, int color)
|
||||||
{
|
{
|
||||||
@@ -61,17 +82,20 @@ public class DhScreen extends Screen
|
|||||||
{
|
{
|
||||||
guiStack.drawString(font, text, x, y, color);
|
guiStack.drawString(font, text, x, y, color);
|
||||||
}
|
}
|
||||||
protected void DhRenderTooltip(GuiGraphics guiStack, Font font, List<? extends net.minecraft.util.FormattedCharSequence> text, int x, int y)
|
//protected void DhRenderTooltip(GuiGraphics guiStack, Font font, List<? extends net.minecraft.util.FormattedCharSequence> text, int x, int y)
|
||||||
{
|
//{
|
||||||
guiStack.renderTooltip(font, text, x, y);
|
// //guiStack.renderTooltip(font, text, x, y);
|
||||||
}
|
//}
|
||||||
protected void DhRenderComponentTooltip(GuiGraphics guiStack, Font font, List<Component> comp, int x, int y)
|
protected void DhRenderComponentTooltip(GuiGraphics guiStack, Font font, List<Component> comp, int x, int y)
|
||||||
{
|
{
|
||||||
guiStack.renderComponentTooltip(font, comp, x, y);
|
guiStack.setComponentTooltipForNextFrame(font, comp, x, y);
|
||||||
}
|
}
|
||||||
protected void DhRenderTooltip(GuiGraphics guiStack, Font font, Component text, int x, int y)
|
protected void DhRenderTooltip(GuiGraphics guiStack, Font font, Component text, int x, int y)
|
||||||
{
|
{
|
||||||
guiStack.renderTooltip(font, text, x, y);
|
guiStack.setTooltipForNextFrame(font, text, x, y);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+21
-28
@@ -1,43 +1,36 @@
|
|||||||
package com.seibel.distanthorizons.common.wrappers.gui;
|
package com.seibel.distanthorizons.common.wrappers.gui;
|
||||||
|
|
||||||
|
import com.seibel.distanthorizons.core.config.ConfigHandler;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||||
import com.seibel.distanthorizons.coreapi.ModInfo;
|
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||||
import com.seibel.distanthorizons.core.config.ConfigBase;
|
|
||||||
import com.seibel.distanthorizons.core.config.gui.ConfigScreen;
|
|
||||||
import com.seibel.distanthorizons.core.config.gui.JavaScreenHandlerScreen;
|
|
||||||
import com.seibel.distanthorizons.core.config.gui.OpenGLConfigScreen;
|
|
||||||
import net.minecraft.client.gui.screens.Screen;
|
import net.minecraft.client.gui.screens.Screen;
|
||||||
|
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||||
|
|
||||||
public class GetConfigScreen
|
public class GetConfigScreen
|
||||||
{
|
{
|
||||||
public static type useScreen = type.Classic;
|
protected static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||||
|
|
||||||
public enum type
|
|
||||||
{
|
|
||||||
Classic,
|
|
||||||
@Deprecated
|
|
||||||
OpenGL, // This was just an attempt, it didn't work out, and we are going to change to javafx soon (as soon as that works)
|
|
||||||
JavaFX;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Screen getScreen(Screen parent)
|
public static Screen getScreen(Screen parent)
|
||||||
{
|
{
|
||||||
// Generate the language
|
if (ModInfo.IS_DEV_BUILD)
|
||||||
// This shouldn't be here, but I need a way to test it after Minecraft inits its assets
|
|
||||||
//System.out.println(ConfigBase.INSTANCE.generateLang(false, true));
|
|
||||||
|
|
||||||
switch (useScreen)
|
|
||||||
{
|
{
|
||||||
case Classic:
|
// it'd be nice to have this run automatically on startup
|
||||||
return ClassicConfigGUI.getScreen(ConfigBase.INSTANCE, parent, "client");
|
// but this will only work once MC has added our lang file,
|
||||||
case OpenGL:
|
// which won't be for sure added until we request a GUI
|
||||||
MinecraftScreen.getScreen(parent, new OpenGLConfigScreen(), ModInfo.ID + ".title");
|
String missingLangEntries = ConfigHandler.INSTANCE.generateLang(true, true);
|
||||||
return null;
|
|
||||||
// case JavaFX -> MinecraftScreen.getScreen(parent, new JavaScreenHandlerScreen(new JavaScreenHandlerScreen.ExampleScreen()), ModInfo.ID + ".title");
|
// trim to remove any newlines/spaces
|
||||||
case JavaFX:
|
// that may be present when no lang entries need changing
|
||||||
return MinecraftScreen.getScreen(parent, new JavaScreenHandlerScreen(new ConfigScreen()), ModInfo.ID + ".title");
|
// then we can check length != 0 if any items are missing and need adding
|
||||||
default:
|
String trimmedMissingEntries = missingLangEntries.trim();
|
||||||
throw new IllegalArgumentException("No config screen implementation defined for ["+useScreen+"].");
|
if (!trimmedMissingEntries.isEmpty())
|
||||||
|
{
|
||||||
|
LOGGER.warn("One or more language entries is missing:");
|
||||||
|
LOGGER.warn(missingLangEntries);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ClassicConfigGUI.getScreen(parent, "client");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+53
-38
@@ -24,26 +24,26 @@ public class MinecraftScreen
|
|||||||
private static class ConfigScreenRenderer extends DhScreen
|
private static class ConfigScreenRenderer extends DhScreen
|
||||||
{
|
{
|
||||||
private final Screen parent;
|
private final Screen parent;
|
||||||
private ConfigListWidget list;
|
private ConfigListWidget configListWidget;
|
||||||
private AbstractScreen screen;
|
private AbstractScreen screen;
|
||||||
|
|
||||||
|
|
||||||
#if MC_VER < MC_1_19_2
|
#if MC_VER < MC_1_19_2
|
||||||
public static net.minecraft.network.chat.TranslatableComponent translate(String str, Object... args)
|
public static net.minecraft.network.chat.TranslatableComponent translate(String str, Object... args)
|
||||||
{
|
{ return new net.minecraft.network.chat.TranslatableComponent(str, args); }
|
||||||
return new net.minecraft.network.chat.TranslatableComponent(str, args);
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
public static net.minecraft.network.chat.MutableComponent translate(String str, Object... args)
|
public static net.minecraft.network.chat.MutableComponent translate(String str, Object... args)
|
||||||
{
|
{ return net.minecraft.network.chat.Component.translatable(str, args); }
|
||||||
return net.minecraft.network.chat.Component.translatable(str, args);
|
#endif
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
protected ConfigScreenRenderer(Screen parent, AbstractScreen screen, String translationName)
|
protected ConfigScreenRenderer(Screen parent, AbstractScreen screen, String translationName)
|
||||||
{
|
{
|
||||||
super(translate(translationName));
|
super(translate(translationName));
|
||||||
|
#if MC_VER < MC_1_21_9
|
||||||
screen.minecraftWindow = Minecraft.getInstance().getWindow().getWindow();
|
screen.minecraftWindow = Minecraft.getInstance().getWindow().getWindow();
|
||||||
|
#else
|
||||||
|
screen.minecraftWindow = Minecraft.getInstance().getWindow().handle();
|
||||||
|
#endif
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.screen = screen;
|
this.screen = screen;
|
||||||
}
|
}
|
||||||
@@ -53,20 +53,22 @@ public class MinecraftScreen
|
|||||||
{
|
{
|
||||||
super.init(); // Init Minecraft's screen
|
super.init(); // Init Minecraft's screen
|
||||||
Window mcWindow = this.minecraft.getWindow();
|
Window mcWindow = this.minecraft.getWindow();
|
||||||
screen.width = mcWindow.getWidth();
|
this.screen.width = mcWindow.getWidth();
|
||||||
screen.height = mcWindow.getHeight();
|
this.screen.height = mcWindow.getHeight();
|
||||||
screen.scaledWidth = this.width;
|
this.screen.scaledWidth = this.width;
|
||||||
screen.scaledHeight = this.height;
|
this.screen.scaledHeight = this.height;
|
||||||
screen.init(); // Init our own config screen
|
this.screen.init(); // Init our own config screen
|
||||||
|
|
||||||
this.list = new ConfigListWidget(this.minecraft, this.width, this.height, 0, 0, 25); // Select the area to tint
|
this.configListWidget = new ConfigListWidget(this.minecraft, this.width, this.height, 0, 0, 25); // Select the area to tint
|
||||||
|
|
||||||
#if MC_VER < MC_1_20_6 // no background is rendered in MC 1.20.6+
|
#if MC_VER < MC_1_20_6 // no background is rendered in MC 1.20.6+
|
||||||
if (this.minecraft != null && this.minecraft.level != null) // Check if in game
|
if (this.minecraft != null && this.minecraft.level != null) // Check if in game
|
||||||
this.list.setRenderBackground(false); // Disable from rendering
|
{
|
||||||
|
this.configListWidget.setRenderBackground(false); // Disable from rendering
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
this.addWidget(this.list); // Add the tint to the things to be rendered
|
this.addWidget(this.configListWidget); // Add the tint to the things to be rendered
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -78,58 +80,71 @@ public class MinecraftScreen
|
|||||||
{
|
{
|
||||||
#if MC_VER < MC_1_20_2
|
#if MC_VER < MC_1_20_2
|
||||||
this.renderBackground(matrices); // Render background
|
this.renderBackground(matrices); // Render background
|
||||||
#else
|
#elif MC_VER < MC_1_21_6
|
||||||
this.renderBackground(matrices, mouseX, mouseY, delta); // Render background
|
this.renderBackground(matrices, mouseX, mouseY, delta); // Render background
|
||||||
|
#else
|
||||||
|
// background blur is already being rendered, rendering again causes the game to crash
|
||||||
#endif
|
#endif
|
||||||
this.list.render(matrices, mouseX, mouseY, delta); // Renders the items in the render list (currently only used to tint background darker)
|
|
||||||
|
|
||||||
screen.mouseX = mouseX;
|
this.configListWidget.render(matrices, mouseX, mouseY, delta); // Renders the items in the render list (currently only used to tint background darker)
|
||||||
screen.mouseY = mouseY;
|
|
||||||
screen.render(delta); // Render everything on the main screen
|
this.screen.mouseX = mouseX;
|
||||||
|
this.screen.mouseY = mouseY;
|
||||||
|
this.screen.render(delta); // Render everything on the main screen
|
||||||
|
|
||||||
super.render(matrices, mouseX, mouseY, delta); // Render the vanilla stuff (currently only used for the background and tint)
|
super.render(matrices, mouseX, mouseY, delta); // Render the vanilla stuff (currently only used for the background and tint)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if MC_VER <= MC_1_21_10
|
||||||
@Override
|
@Override
|
||||||
public void resize(Minecraft mc, int width, int height)
|
public void resize(Minecraft mc, int width, int height)
|
||||||
|
#else
|
||||||
|
@Override
|
||||||
|
public void resize(int width, int height)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
super.resize(mc, width, height); // Resize Minecraft's screen
|
// Resize Minecraft's screen
|
||||||
|
#if MC_VER <= MC_1_21_10
|
||||||
|
super.resize(mc, width, height);
|
||||||
|
#else
|
||||||
|
super.resize(width, height);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
Window mcWindow = this.minecraft.getWindow();
|
Window mcWindow = this.minecraft.getWindow();
|
||||||
screen.width = mcWindow.getWidth();
|
this.screen.width = mcWindow.getWidth();
|
||||||
screen.height = mcWindow.getHeight();
|
this.screen.height = mcWindow.getHeight();
|
||||||
screen.scaledWidth = this.width;
|
this.screen.scaledWidth = this.width;
|
||||||
screen.scaledHeight = this.height;
|
this.screen.scaledHeight = this.height;
|
||||||
screen.onResize(); // Resize our screen
|
this.screen.onResize(); // Resize our screen
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void tick()
|
public void tick()
|
||||||
{
|
{
|
||||||
super.tick(); // Tick Minecraft's screen
|
super.tick(); // Tick Minecraft's screen
|
||||||
screen.tick(); // Tick our screen
|
this.screen.tick(); // Tick our screen
|
||||||
if (screen.close) // If we decide to close the screen, then actually close the screen
|
if (this.screen.close) // If we decide to close the screen, then actually close the screen
|
||||||
onClose();
|
{
|
||||||
|
this.onClose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClose()
|
public void onClose()
|
||||||
{
|
{
|
||||||
screen.onClose(); // Close our screen
|
this.screen.onClose(); // Close our screen
|
||||||
Objects.requireNonNull(minecraft).setScreen(this.parent); // Goto the parent screen
|
Objects.requireNonNull(this.minecraft).setScreen(this.parent); // Goto the parent screen
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFilesDrop(@NotNull List<Path> files)
|
public void onFilesDrop(@NotNull List<Path> files)
|
||||||
{
|
{ this.screen.onFilesDrop(files); }
|
||||||
screen.onFilesDrop(files);
|
|
||||||
}
|
|
||||||
|
|
||||||
// For checking if it should close when you press the escape key
|
// For checking if it should close when you press the escape key
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldCloseOnEsc()
|
public boolean shouldCloseOnEsc()
|
||||||
{
|
{ return this.screen.shouldCloseOnEsc; }
|
||||||
return screen.shouldCloseOnEsc;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user