Compare commits
371 Commits
dynamicFade
...
Vulkan
| Author | SHA1 | Date | |
|---|---|---|---|
| 64d8f7ee2d | |||
| d8b3aee9dc | |||
| fce94fa4bf | |||
| 254d671629 | |||
| e66e7e627a | |||
| 1f1024251b | |||
| fc516a20d5 | |||
| 791c2c3426 | |||
| b00079897a | |||
| 37b73e1d5c | |||
| 4bd1136713 | |||
| ef98dbd5fd | |||
| 5df0a60b06 | |||
| 9feb20eff8 | |||
| c9267d61a8 | |||
| a29e225a80 | |||
| ae0f3c2b3b | |||
| 852ea75449 | |||
| ab6a5dad2b | |||
| 1a1eaca280 | |||
| 0272f8c57f | |||
| cf09358710 | |||
| b5d833fa3d | |||
| 329dbe9585 | |||
| c7ae7f155e | |||
| 5f7dbb8662 | |||
| ee21548151 | |||
| ca00125960 | |||
| 4067264e72 | |||
| 9c2d243ad4 | |||
| de9d8b0d2e | |||
| 67f4615b34 | |||
| cd7a130ee4 | |||
| 4d17f7aecf | |||
| a59e7500ab | |||
| 40040294e7 | |||
| 783e61ec3d | |||
| e09db5d7df | |||
| 91f9ef3f4b | |||
| d52a3abb14 | |||
| 16370b0b6e | |||
| bfa60b48cf | |||
| 50518bfe21 | |||
| 80e4467829 | |||
| 396315bd05 | |||
| 7a0fec2c2f | |||
| 4afaaa7b12 | |||
| b057041467 | |||
| 33e6ce6376 | |||
| 118ef39c30 | |||
| 1013e1c824 | |||
| b0e924c7fe | |||
| 1777acd1d4 | |||
| 8276a862f8 | |||
| 4329acf91d | |||
| 72f83b40f7 | |||
| a33eb30a53 | |||
| d3e96f50a8 | |||
| 3aefeb98b4 | |||
| 3553ff8e60 | |||
| 945a2c0c5a | |||
| 8c7974e216 | |||
| 37756cd759 | |||
| c60cc4f013 | |||
| 87cce2e33c | |||
| 40ada9c186 | |||
| 55fb458266 | |||
| 79d2466fa2 | |||
| d750e489df | |||
| a206e49b2b | |||
| 0b691ebcd5 | |||
| 3c35c52803 | |||
| 0ed4964ee5 | |||
| b7cf7b61c8 | |||
| 54b0ccfce6 | |||
| 050d00b628 | |||
| 2733201ac3 | |||
| 26bf03205c | |||
| 628d57d216 | |||
| 58ed8259f2 | |||
| 062ed5bcc8 | |||
| 539d152caa | |||
| a1af4335e0 | |||
| e68b112020 | |||
| fab6d187ca | |||
| 0daa00cec2 | |||
| f3036850ce | |||
| 51c8b47bba | |||
| 89efd53d61 | |||
| 7667f51cf3 | |||
| 61eaa5a734 | |||
| 1d589d1a62 | |||
| 03b1eeb77e | |||
| 8446df72f7 | |||
| c07397e9c0 | |||
| 29a92aeb93 | |||
| 8467782b80 | |||
| c8dbb21ea4 | |||
| 63e1c12564 | |||
| 52f58150da | |||
| d1d642a7bb | |||
| 8e45358aad | |||
| a959c7220b | |||
| e06425c5eb | |||
| 66ce258fe1 | |||
| 181881a661 | |||
| af0d8d1d2f | |||
| 6c68e94b96 | |||
| 93313a5c50 | |||
| 0527baa708 | |||
| ce1fbde937 | |||
| 764abdac45 | |||
| b42d3d8f74 | |||
| cd67a773c5 | |||
| 6d7bade7ca | |||
| dea8d4498a | |||
| 2969916f34 | |||
| 8785224c51 | |||
| 605f02a655 | |||
| 8099d37c14 | |||
| dd4dbefe9a | |||
| 52a15fd349 | |||
| 3b3be6aed4 | |||
| aeb7d6d0f9 | |||
| 5336dbafec | |||
| 6079cb4830 | |||
| 50ff174104 | |||
| b77ef89df6 | |||
| a701dd29a9 | |||
| ab36fdd545 | |||
| f87afb34f4 | |||
| 053917d3d7 | |||
| 063ba01970 | |||
| 72a888f3ff | |||
| 0bd36bff1d | |||
| 2bf125b7ac | |||
| ba3cf8fd56 | |||
| 951f2a4ee7 | |||
| d55b1bb3c2 | |||
| 275ecb78c3 | |||
| 64ac0d6017 | |||
| 3f16d67746 | |||
| 3a34dc8626 | |||
| c1766fb439 | |||
| cfd47adfda | |||
| 9b9e6b9179 | |||
| 49d1587a71 | |||
| b0f5e55744 | |||
| d9191534d5 | |||
| ff459621e6 | |||
| 64fb45d74d | |||
| 1590abb489 | |||
| a3c9b0654a | |||
| a9388321d9 | |||
| 877c824e58 | |||
| 80f30dfd74 | |||
| 9a087025fe | |||
| 29381bce7b | |||
| 21dc0f13c9 | |||
| 7794958804 | |||
| c245ed6598 | |||
| 6270b03005 | |||
| 2674b945bb | |||
| 0647bdbab3 | |||
| 528a12ac83 | |||
| 4ac9de05df | |||
| a0f1b72089 | |||
| 85c07b11c6 | |||
| 215e1d46d0 | |||
| 5f228f0567 | |||
| f597958e1e | |||
| 95921358f8 | |||
| a22d494797 | |||
| 666e917b8f | |||
| a26a97e7fb | |||
| cdbb9de933 | |||
| feccf12580 | |||
| d371d93c9d | |||
| 5f3e8d76b2 | |||
| a7bd72e35b | |||
| 0a5326d2b1 | |||
| dad2014c46 | |||
| 70dd0bda72 | |||
| 8213901229 | |||
| 668ba491e8 | |||
| d85589c41a | |||
| 7f5316108d | |||
| 9c1abbac2b | |||
| 1bb957a866 | |||
| 6ccba17baf | |||
| e4c5d8adab | |||
| 823f204424 | |||
| 505e9a77fd | |||
| 4c580fe4ff | |||
| efc1865f87 | |||
| ae08ad56c4 | |||
| 633544e0b0 | |||
| 2432028aa0 | |||
| eb6aa13815 | |||
| 55155103ec | |||
| 667dd85aef | |||
| 9bd946a41c | |||
| 241baef7af | |||
| b5890a4783 | |||
| e3b67ef500 | |||
| 5905fe3df2 | |||
| 9d35a70437 | |||
| f121860563 | |||
| 9715db3ac6 | |||
| 03a29fbacb | |||
| e91888934b | |||
| 030f814398 | |||
| 90ef8fd64d | |||
| 0ffefaa8c1 | |||
| 99703d65df | |||
| bd2f5a7836 | |||
| a44556f86a | |||
| 4597b7f647 | |||
| 0de80cfaa7 | |||
| 034aaddca3 | |||
| a1d493f25d | |||
| 4b5a4dda79 | |||
| ce528f3fd5 | |||
| e4c769e95e | |||
| f13095875f | |||
| 3d1af8f944 | |||
| d73867efd6 | |||
| 045733deb5 | |||
| b552bf2566 | |||
| 33d37b3937 | |||
| 15a044d059 | |||
| 9e5be3ad21 | |||
| ba977a29f0 | |||
| c6c94ef906 | |||
| 7fed4b1ddb | |||
| dfee36f416 | |||
| cf6945b44c | |||
| a01a9ac356 | |||
| 89619696cb | |||
| 88f945bf22 | |||
| 3555133d7f | |||
| 294013eff0 | |||
| 6748ec25ff | |||
| 485c3dedb3 | |||
| 4ceecdfb09 | |||
| 23d3e44002 | |||
| 3a5d6e7370 | |||
| 71237caa81 | |||
| 7e19f9e6eb | |||
| f7b5b9a2f5 | |||
| 77016de6e6 | |||
| e530d0ffda | |||
| b04a308090 | |||
| 385d6919fb | |||
| 458cc9b505 | |||
| afdccfe087 | |||
| 4d7674348b | |||
| a2c96ba7ff | |||
| 5c5de3c744 | |||
| 18acb5d101 | |||
| c86c32b39e | |||
| 3c680b5daf | |||
| 84d1298e18 | |||
| 354b6567d4 | |||
| 3498faed59 | |||
| f8eb1e8a97 | |||
| 19057218d6 | |||
| f745e9c51a | |||
| da922a8c69 | |||
| 3f2d8ea6ae | |||
| 550f36e9fa | |||
| ba0835bf4a | |||
| 766a41ce56 | |||
| 3b5728692d | |||
| 05d573c847 | |||
| 9360e45a39 | |||
| 71aaff32a2 | |||
| 2fbeb43894 | |||
| ae6fa83c50 | |||
| f4171ffca1 | |||
| dedcc875d2 | |||
| 224a5449ed | |||
| b0d325fd14 | |||
| 36ad3f4e43 | |||
| b5eff6aa80 | |||
| f1e93ad547 | |||
| e59c22fb69 | |||
| 183882f9ce | |||
| 5b825f9dbb | |||
| 933d5c957c | |||
| 1bfa93eea3 | |||
| 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 | |||
| 6c56d09b18 | |||
| e5536de44f |
@@ -1,19 +0,0 @@
|
||||
**/.git
|
||||
**/.gitlab
|
||||
**/.cache
|
||||
|
||||
buildAllJars
|
||||
|
||||
**/_Misc Files
|
||||
*.bat
|
||||
*.md
|
||||
*.sh
|
||||
*.txt
|
||||
|
||||
coreSubProjects/*.md
|
||||
coreSubProjects/*.txt
|
||||
|
||||
**/.gitignore
|
||||
**/.gitattributes
|
||||
**/.gitlab-cy.yml
|
||||
**/.gitmodules
|
||||
@@ -25,6 +25,8 @@ hs_err_pid*
|
||||
Merged/
|
||||
# Folder created by the buildAll scripts
|
||||
buildAllJars/
|
||||
_buildAllJars/
|
||||
_buildWorkers/
|
||||
|
||||
relocate_natives/.venv/
|
||||
relocate_natives/__pycache__/
|
||||
|
||||
+3
-4
@@ -1,9 +1,8 @@
|
||||
# use Eclipse's JDK
|
||||
# The ci should always use a unix(-like) OS to work
|
||||
image: eclipse-temurin:21
|
||||
image: eclipse-temurin:25
|
||||
|
||||
# all stages need to be defined here
|
||||
# TODO: Make stages depend on what is in versionProperties
|
||||
stages:
|
||||
- build
|
||||
- api
|
||||
@@ -36,6 +35,7 @@ build:
|
||||
parallel:
|
||||
matrix:
|
||||
- MC_VER: [
|
||||
"26.1.2",
|
||||
"1.21.11", "1.21.10", "1.21.9", "1.21.8", "1.21.6", "1.21.5", "1.21.4", "1.21.3", "1.21.1",
|
||||
"1.20.6", "1.20.4", "1.20.2", "1.20.1",
|
||||
"1.19.4", "1.19.2",
|
||||
@@ -47,8 +47,7 @@ build:
|
||||
# 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 mergeJars -PmcVer="${MC_VER}" -PinfoGitCommit="${CI_COMMIT_SHA}" -PinfoGitBranch="${CI_COMMIT_BRANCH}" -PinfoBuildSource="GitLab CI (${CI_PIPELINE_ID})" --gradle-user-home cache/;
|
||||
- cp ./fabric/build/libs/* ./forge/build/libs/* ./neoforge/build/libs/* ./build/merged/* . || true
|
||||
- cp ./fabric/build/libs/* ./forge/build/libs/* ./neoforge/build/libs/* ./build/forgix/* . || true
|
||||
artifacts:
|
||||
name: "NightlyBuild_${MC_VER}-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
|
||||
paths:
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
# See mailmap docs: https://git-scm.com/docs/gitmailmap
|
||||
# Test with git shortlog --summary --email
|
||||
# Keep sorted for easier editing and smaller diffs
|
||||
|
||||
Ada Aster <an.ada.poirier@gmail.com>
|
||||
CodeF53 <fseusb@gmail.com> <37855219+CodeF53@users.noreply.github.com>
|
||||
coolGi <me@coolgi.dev> <sasanaps@hotmail.com>
|
||||
James Seibel <jeseibel@gondtc.com> <jseibel@vertsys.com>
|
||||
Morippi <leoleo97@libero.it> <leoloe97@libero.it>
|
||||
Morippi <leoleo97@libero.it> <Morippi>
|
||||
Ran <43445785+Ran-Mewo@users.noreply.github.com> <10044908-_Ran@users.noreply.gitlab.com>
|
||||
Ran <43445785+Ran-Mewo@users.noreply.github.com> <43445785+Ran-Mewo@users.noreply.github.com>
|
||||
Ran <43445785+Ran-Mewo@users.noreply.github.com> <43445785+RanCraftPlayz@users.noreply.github.com>
|
||||
TomTheFurry <tomlee92502@yahoo.com>
|
||||
TomTheFurry <tomlee92502@yahoo.com> <46843632+TomTheFurry@users.noreply.github.com>
|
||||
Yeshi <yeshi@newengine.org>
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
FROM eclipse-temurin:17-jdk
|
||||
|
||||
WORKDIR /home/build/
|
||||
COPY ./gradlew .
|
||||
RUN chmod +x ./gradlew
|
||||
CMD echo "\r========== [CLEAN: $MC_VER] ==========" && \
|
||||
./gradlew clean -PmcVer="$MC_VER" --gradle-user-home .gradle-cache/ && \
|
||||
echo "\r========== [BUILD: $MC_VER] ==========" && \
|
||||
./gradlew build -PmcVer="$MC_VER" --gradle-user-home .gradle-cache/ && \
|
||||
echo "\r========== [MERGE: $MC_VER] ==========" && \
|
||||
./gradlew mergeJars -PmcVer="$MC_VER" --gradle-user-home .gradle-cache/ && \
|
||||
echo "\r========== [DONE: $MC_VER] =========="
|
||||
@@ -14,89 +14,11 @@ Below is a video demonstrating the system:
|
||||
|
||||
<br>
|
||||
|
||||
## Minecraft and Library Versions
|
||||
|
||||
### This branch supports the following versions of Minecraft:
|
||||
|
||||
#### 1.20.4, 1.20.3 (Default)
|
||||
Fabric: 0.15.1\
|
||||
Fabric API: 0.91.2+1.20.4\
|
||||
Forge: 49.0.30\
|
||||
NeoForge: 118-beta\
|
||||
Parchment: 1.20.2:2023.12.10\
|
||||
Modmenu: 9.0.0-pre.1
|
||||
|
||||
#### 1.20.2
|
||||
Fabric: 0.14.24\
|
||||
Fabric API: 0.90.4+1.20.2\
|
||||
Forge: 48.0.13\
|
||||
Parchment: 1.20.1:2023.09.03\
|
||||
Modmenu: 8.0.0
|
||||
|
||||
#### 1.20.1, 1.20
|
||||
Fabric: 0.14.24\
|
||||
Fabric API: 0.90.4+1.20.1\
|
||||
Forge: 47.2.1\
|
||||
Parchment: 1.20.1:2023.09.03\
|
||||
Modmenu: 7.2.2
|
||||
|
||||
#### 1.19.4
|
||||
Fabric: 0.14.24\
|
||||
Fabric API: 0.87.1+1.19.4\
|
||||
Forge: 45.2.4\
|
||||
Parchment: 1.19.4:2023.06.26\
|
||||
Modmenu: 6.3.1
|
||||
|
||||
#### 1.19.2
|
||||
Fabric: 0.14.24\
|
||||
Fabric API: 0.76.1+1.19.2\
|
||||
Forge: 43.3.2\
|
||||
Parchment: 1.19.2:2022.11.27\
|
||||
Modmenu: 4.2.0-beta.2
|
||||
|
||||
#### 1.18.2
|
||||
Fabric: 0.14.24\
|
||||
Fabric API: 0.76.0+1.18.2\
|
||||
Forge: 40.2.10\
|
||||
Parchment: 1.18.2:2022.11.06\
|
||||
Modmenu: 3.2.5
|
||||
|
||||
#### 1.17.1, 1.17
|
||||
Fabric: 0.14.24\
|
||||
Fabric API: 0.46.1+1.17\
|
||||
Forge: 37.1.1\
|
||||
Parchment: 1.17.1:2021.12.12\
|
||||
Modmenu: 2.0.14
|
||||
|
||||
#### 1.16.5, 1.16.4
|
||||
Fabric: 0.14.24\
|
||||
Fabric API: 0.42.0+1.16\
|
||||
Forge: 36.2.39\
|
||||
Parchment: 1.16.5:2022.03.06\
|
||||
Modmenu: 1.16.22
|
||||
|
||||
### Versions no longer supported
|
||||
- 1.18.1, 1.18
|
||||
- 1.19.1, 1.19
|
||||
- 1.19.3
|
||||
|
||||
<br>
|
||||
|
||||
### Plugin and Library versions
|
||||
|
||||
Gradle: 8.5\
|
||||
Fabric loom: 1.4-SNAPSHOT\
|
||||
Architectury loom (Forge gradle replacement): 1.4-SNAPSHOT\
|
||||
Sponge vanilla gradle: 0.2.1-SNAPSHOT\
|
||||
Java Preprocessor plugin: Manifold Preprocessor
|
||||
|
||||
<br>
|
||||
|
||||
## Source Code Installation
|
||||
|
||||
### Prerequisites
|
||||
|
||||
* A Java Development Kit (JDK) for Java 17 (recommended) or newer. <br>
|
||||
* A Java Development Kit (JDK) for Java 25 (recommended) or newer. <br>
|
||||
Visit https://www.oracle.com/java/technologies/downloads/ for installers.
|
||||
* Git or someway to clone git projects. <br>
|
||||
Visit https://git-scm.com/ for installers.
|
||||
@@ -104,15 +26,10 @@ Java Preprocessor plugin: Manifold Preprocessor
|
||||
|
||||
**If using IntelliJ:**
|
||||
1. Install the Manifold plugin
|
||||
- https://plugins.jetbrains.com/plugin/10057-manifold-ij
|
||||
2. Open IDEA and import the build.gradle
|
||||
3. Refresh the Gradle project in IDEA if required
|
||||
|
||||
**If using Eclipse: (Note that Eclipse doesn't support Manifold's preprocessor!)**
|
||||
1. Run the command: `./gradlew geneclipseruns`
|
||||
2. Run the command: `./gradlew eclipse`
|
||||
3. Make sure eclipse has the JDK 17 installed. (This is needed so that eclipse can run minecraft)
|
||||
4. Import the project into eclipse
|
||||
|
||||
<br>
|
||||
|
||||
## Switching Versions
|
||||
@@ -127,72 +44,42 @@ In IntelliJ, you will also need to do a gradle sync if it didn't happen automati
|
||||
## Compiling
|
||||
|
||||
Prerequisites:
|
||||
- JDK 17 or newer
|
||||
|
||||
From the File Explorer:
|
||||
1. Download and extract the project zip
|
||||
2. Download the core from https://gitlab.com/distant-horizons-team/distant-horizons-core and extract into a folder called `coreSubProjects`
|
||||
3. Open a terminal emulator in the project folder (On Windows you can type `cmd` in the title bar)
|
||||
4. Run the commands: `./gradlew assemble` (You may need to use a `.\` on Windows)
|
||||
5. Merge the jars with `./gradlew mergeJars`
|
||||
6. The compiled jar file will be in the folder `Merged`
|
||||
- JDK 25 or newer
|
||||
|
||||
From the command line:
|
||||
1. `git clone --recurse-submodules https://gitlab.com/distant-horizons-team/distant-horizons.git`
|
||||
2. `cd distant-horizons`
|
||||
3. `./gradlew assemble`
|
||||
4. `./gradlew mergeJars`
|
||||
5. The compiled jar file will be in the folder `Merged`
|
||||
5. The compiled jar file will be in the folder `\build\libs`
|
||||
|
||||
Run tests with: `./gradlew test`
|
||||
From the File Explorer:
|
||||
1. Download and extract the project zip
|
||||
2. Download the core from https://gitlab.com/distant-horizons-team/distant-horizons-core and extract into a folder called `coreSubProjects`
|
||||
3. Open command prompt/terminal in the project folder
|
||||
4. Run the commands: `./gradlew assemble`
|
||||
6. The compiled jar file will be in the folder `\build\libs`
|
||||
|
||||
>Note: You can add the argument `-PmcVer=?` to tell gradle to build a selected MC version instead of having to modify the `gradle.properties` file.\
|
||||
> For example: `./gradlew assemble -PmcVer=1.18.2`
|
||||
|
||||
<br>
|
||||
|
||||
## Compiling with Docker
|
||||
|
||||
`./compile <version>`
|
||||
|
||||
You can also locally compile the DH jars without a Java environment by using Docker. Where `<version>` is the version of Minecraft to compile for (ie `1.20.1`), or the keyword `all`. See [Versions](#minecraft-and-library-versions) for a list of all supported values.
|
||||
|
||||
<br>
|
||||
|
||||
## Other commands
|
||||
|
||||
`./gradlew --refresh-dependencies` to refresh local dependencies.
|
||||
|
||||
`./gradlew clean` to delete any compiled code.
|
||||
|
||||
<br>
|
||||
|
||||
## Note to self
|
||||
|
||||
The Minecraft source code is NOT added to your workspace in an editable way. Minecraft is treated like a normal Library. Sources are there for documentation and research purposes only.
|
||||
|
||||
Source code uses Mojang mappings & [Parchment](https://parchmentmc.org/) mappings.
|
||||
|
||||
To generate the source code run `./gradlew genSources` <br>
|
||||
If your IDE fails to auto-detect the source jars when browsing Minecraft classes; manually select the JAR file ending with -sources.jar when prompted by your IDE. <br>
|
||||
(In IntelliJ it's at the top where it says "choose sources" when browsing a Minecraft class)
|
||||
|
||||
<br>
|
||||
|
||||
## Other Useful commands
|
||||
|
||||
Run the standalone jar: `./gradlew run` <br>
|
||||
Build the standalone jar: `./gradlew core:build` <br>
|
||||
Only build Fabric: `./gradlew fabric:assemble` or `./gradlew fabric:build` <br>
|
||||
Only build Forge: `./gradlew forge:assemble` or `./gradlew forge:build` <br>
|
||||
Run the Fabric client (for debugging): `./gradlew fabric:runClient` <br>
|
||||
Run the Forge client (for debugging): `./gradlew forge:runClient` <br>
|
||||
Delete all compiled code: `./gradlew clean` <br>
|
||||
Refresh local dependencies: `./gradlew --refresh-dependencies`
|
||||
|
||||
To build all versions: `./buildAll` (all builds will end up in the `Merged` folder)
|
||||
To build all versions: `./buildAll`
|
||||
|
||||
<br>
|
||||
|
||||
## Open Source Acknowledgements
|
||||
## Open Source Libraries
|
||||
|
||||
Forgix (To merge multiple mod versions into one jar) [_Formerly_ [_DHJarMerger_](https://github.com/Ran-helo/DHJarMerger)]\
|
||||
https://github.com/PacifistMC/Forgix
|
||||
@@ -208,3 +95,18 @@ https://github.com/blackears/svgSalamander
|
||||
|
||||
sqlite-jdbc\
|
||||
https://github.com/xerial/sqlite-jdbc
|
||||
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
Distant Horizons has been graciously provided an open source license for <a href="https://www.yourkit.com/java/profiler/">YourKit Java Profiler</a>.
|
||||
|
||||
> <img src="https://www.yourkit.com/images/yklogo.png">
|
||||
>
|
||||
> YourKit supports open source projects with innovative and intelligent tools
|
||||
for monitoring and profiling Java and .NET applications.
|
||||
YourKit is the creator of <a href="https://www.yourkit.com/java/profiler/">YourKit Java Profiler</a>,
|
||||
<a href="https://www.yourkit.com/dotnet-profiler/">YourKit .NET Profiler</a>,
|
||||
and <a href="https://www.yourkit.com/youmonitor/">YourKit YouMonitor</a>.
|
||||
|
||||
|
||||
|
||||
+21
-722
@@ -1,730 +1,29 @@
|
||||
import com.github.jengelman.gradle.plugins.shadow.transformers.Transformer
|
||||
import com.github.jengelman.gradle.plugins.shadow.transformers.TransformerContext
|
||||
import org.apache.tools.zip.ZipEntry
|
||||
|
||||
import javax.annotation.Nonnull
|
||||
import org.apache.tools.zip.ZipOutputStream
|
||||
|
||||
import java.util.function.Function
|
||||
import java.util.function.Predicate
|
||||
|
||||
|
||||
plugins {
|
||||
id "java"
|
||||
|
||||
// Plugin to put dependencies inside our final jar
|
||||
id "com.github.johnrengelman.shadow" version '8.1.1' apply false
|
||||
|
||||
// Plugin to create merged jars
|
||||
id "io.github.pacifistmc.forgix" version "1.3.4"
|
||||
|
||||
// Manifold preprocessor
|
||||
id "systems.manifold.manifold-gradle-plugin" version "0.0.2-alpha"
|
||||
|
||||
// Architectury is used here only as a replacement for forge's own loom
|
||||
id "dev.architectury.loom" version "1.13-SNAPSHOT" apply false
|
||||
id 'root'
|
||||
id 'io.github.pacifistmc.forgix' version '2.+'
|
||||
}
|
||||
|
||||
if (false) // TODO vulkan don't run if there is only one mod loader
|
||||
forgix {
|
||||
autoRun = true
|
||||
|
||||
/**
|
||||
* Creates the list of preprocessors to use.
|
||||
*
|
||||
* @param mcVers array of all MC versions
|
||||
* @param mcIndex array index of the currently active MC version
|
||||
*/
|
||||
def writeBuildGradlePredefine(List<String> mcVers, int mcIndex)
|
||||
{
|
||||
// Build the list of preprocessors to use
|
||||
StringBuilder sb = new StringBuilder();
|
||||
// add the mod loaders to the end of the jar
|
||||
// put together in the format: "a", "a-b", "a-b-c"
|
||||
String modLoaders = "";
|
||||
((String) gradle.builds_for)
|
||||
.split(",")
|
||||
.each
|
||||
{ loader ->
|
||||
def loaderName = loader.trim()
|
||||
if (modLoaders != "")
|
||||
{
|
||||
modLoaders += "-";
|
||||
}
|
||||
|
||||
sb.append("# DON'T TOUCH THIS FILE, This is handled by the build script\n");
|
||||
|
||||
|
||||
for (int i = 0; i < mcVers.size(); i++)
|
||||
{
|
||||
String verStr = mcVers[i].replace(".", "_");
|
||||
sb.append("MC_" + verStr + "=" + i.toString() + "\n");
|
||||
|
||||
if (mcIndex == i)
|
||||
{
|
||||
sb.append("MC_VER=" + i.toString() + "\n");
|
||||
modLoaders += loaderName;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Check if this is a development build
|
||||
if (mod_version.toLowerCase().contains("dev"))
|
||||
{
|
||||
// WARNING: only use this for logging, we don't want to have confusion
|
||||
// when a method doesn't work correctly in the release build.
|
||||
sb.append("DEV_BUILD=\n");
|
||||
}
|
||||
|
||||
new File(projectDir, "build.properties").text = sb.toString()
|
||||
// merged jars are named in the format:
|
||||
// "DistantHorizons-3.0.1-b-dev-26.1-fabric-neoforge.jar"
|
||||
archiveClassifier = modLoaders
|
||||
}
|
||||
|
||||
|
||||
// Transfers the values set in settings.gradle to the rest of the project
|
||||
project.gradle.ext.getProperties().each { prop ->
|
||||
rootProject.ext.set(prop.key, prop.value)
|
||||
//println "Added prop [key:" + prop.key + ", value:" + prop.value + "]"
|
||||
}
|
||||
// Sets up manifold stuff
|
||||
writeBuildGradlePredefine(rootProject.mcVers, rootProject.mcIndex)
|
||||
|
||||
// Sets up the version string (the name we use for our jar)
|
||||
rootProject.versionStr = rootProject.mod_version + "-" + rootProject.minecraft_version // + "-" + new Date().format("yyyy_MM_dd_HH_mm")
|
||||
|
||||
class NativeTransformer implements Transformer {
|
||||
private Predicate<String> fileMatcher
|
||||
private Function<String, String> filePathMapper
|
||||
|
||||
private final HashMap<String, String> replacements = new HashMap()
|
||||
private final HashMap<String, byte[]> rewrittenFiles = new HashMap()
|
||||
private var nativeRelocator
|
||||
|
||||
public File rootDir
|
||||
|
||||
void matchFiles(Predicate<String> matcher) {
|
||||
fileMatcher = matcher
|
||||
}
|
||||
|
||||
void mapPaths(Function<String, String> mapper) {
|
||||
filePathMapper = mapper
|
||||
}
|
||||
|
||||
void relocateNative(String target, String replacement) {
|
||||
if (replacement.length() > target.length()) {
|
||||
throw new GradleException("Length of value \"${replacement}\" exceeds the length of \"${target}\": ${replacement.length()} > ${target.length()}")
|
||||
}
|
||||
|
||||
replacements.put(target, replacement)
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean canTransformResource(@Nonnull FileTreeElement element) {
|
||||
return fileMatcher.test(element.name)
|
||||
}
|
||||
|
||||
@Override
|
||||
void transform(@Nonnull TransformerContext context) {
|
||||
byte[] content = context.is.readAllBytes()
|
||||
|
||||
if (nativeRelocator == null) {
|
||||
nativeRelocator = new NativeRelocator(rootDir.toPath().resolve("relocate_natives"))
|
||||
}
|
||||
|
||||
try {
|
||||
String path = filePathMapper != null
|
||||
? filePathMapper.apply(context.path)
|
||||
: context.path
|
||||
content = nativeRelocator.processBinary(path, content, replacements)
|
||||
|
||||
rewrittenFiles.put(path, content)
|
||||
}
|
||||
catch (Throwable e) {
|
||||
throw new GradleException("Failed to relocate", e)
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean hasTransformedResource() { return !rewrittenFiles.isEmpty() }
|
||||
|
||||
@Override
|
||||
void modifyOutputStream(@Nonnull ZipOutputStream os, boolean preserveFileTimestamps) {
|
||||
for (Map.Entry<String, byte[]> rewrittenFile : rewrittenFiles.entrySet()) {
|
||||
os.putNextEntry(new ZipEntry(rewrittenFile.key))
|
||||
os.write(rewrittenFile.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
subprojects { p ->
|
||||
// Does the same as "p == project(":common") || p == project(":fabric") || p == project(":quilt") || p == project(":forge") || p == project("WhateverWeAddLaterOn")"
|
||||
// Useful later on so we dont have duplicated code
|
||||
def isMinecraftSubProject = p != project(":core") && p != project(":api")
|
||||
|
||||
|
||||
// Apply plugins
|
||||
apply plugin: "java"
|
||||
apply plugin: "com.github.johnrengelman.shadow"
|
||||
if (isMinecraftSubProject)
|
||||
apply plugin: "systems.manifold.manifold-gradle-plugin"
|
||||
|
||||
// Apply forge's loom
|
||||
if ((findProject(":forge") && p == project(":forge")) ||
|
||||
(findProject(":neoforge") && p == project(":neoforge"))
|
||||
)
|
||||
{
|
||||
apply plugin: "dev.architectury.loom"
|
||||
}
|
||||
|
||||
|
||||
// Set the manifold version (may not be required tough)
|
||||
manifold {
|
||||
manifoldVersion = rootProject.manifold_version
|
||||
}
|
||||
|
||||
|
||||
// set up custom configurations (configurations are a way to handle dependencies)
|
||||
configurations {
|
||||
// extends the shadowJar configuration
|
||||
shadowMe
|
||||
// have implemented dependencies automatically embedded in the final jar
|
||||
implementation.extendsFrom(shadowMe)
|
||||
|
||||
// Configuration fpr core & api
|
||||
coreProjects
|
||||
shadowMe.extendsFrom(coreProjects)
|
||||
|
||||
|
||||
// FIXME this additional configuration is necessary because forge
|
||||
// needs forgeRuntimeLibrary, although adding it to shadowMe
|
||||
// causes runtime issues where the libraries aren't properly added
|
||||
forgeShadowMe
|
||||
// this should match shadowMe pretty closely
|
||||
implementation.extendsFrom(forgeShadowMe)
|
||||
shadowMe.extendsFrom(forgeShadowMe)
|
||||
forgeRuntimeLibrary.extendsFrom(forgeShadowMe)
|
||||
|
||||
|
||||
if (isMinecraftSubProject && p != project(":common")) {
|
||||
// Shadow common
|
||||
common
|
||||
shadowCommon // Don't use shadow from the shadow plugin because we don't want IDEA to index this.
|
||||
compileClasspath.extendsFrom common
|
||||
runtimeClasspath.extendsFrom common
|
||||
if (findProject(":forge"))
|
||||
developmentForge.extendsFrom common
|
||||
if (findProject(":neoforge"))
|
||||
developmentNeoForge.extendsFrom common
|
||||
compileClasspath.extendsFrom coreProjects
|
||||
runtimeClasspath.extendsFrom coreProjects
|
||||
if (findProject(":forge"))
|
||||
developmentForge.extendsFrom coreProjects
|
||||
if (findProject(":neoforge"))
|
||||
developmentNeoForge.extendsFrom coreProjects
|
||||
|
||||
// TODO remove unused fabricLike
|
||||
if (findProject(":fabricLike") && p != project(":fabricLike")) {
|
||||
// Shadow fabricLike
|
||||
fabricLike
|
||||
shadowFabricLike
|
||||
compileClasspath.extendsFrom fabricLike
|
||||
runtimeClasspath.extendsFrom fabricLike
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
dependencies {
|
||||
//=====================//
|
||||
// shared dependencies //
|
||||
//=====================//
|
||||
|
||||
// Manifold
|
||||
if (isMinecraftSubProject) {
|
||||
annotationProcessor("systems.manifold:manifold-preprocessor:${rootProject.manifold_version}")
|
||||
}
|
||||
|
||||
// Log4j
|
||||
if (p == project(":core"))
|
||||
{
|
||||
// the standalone core jar needs logging shaded otherwise it won't run
|
||||
forgeShadowMe("org.apache.logging.log4j:log4j-api:${rootProject.log4j_version}")
|
||||
forgeShadowMe("org.apache.logging.log4j:log4j-core:${rootProject.log4j_version}")
|
||||
}
|
||||
else
|
||||
{
|
||||
// When running in MC, MC already includes logging
|
||||
implementation("org.apache.logging.log4j:log4j-api:${rootProject.log4j_version}")
|
||||
implementation("org.apache.logging.log4j:log4j-core:${rootProject.log4j_version}")
|
||||
}
|
||||
|
||||
|
||||
// JOML
|
||||
if (project.hasProperty("embed_joml") && embed_joml == "true")
|
||||
forgeShadowMe("org.joml:joml:${rootProject.joml_version}")
|
||||
else
|
||||
implementation("org.joml:joml:${rootProject.joml_version}")
|
||||
|
||||
// JUnit tests
|
||||
implementation("org.junit.jupiter:junit-jupiter:5.8.2")
|
||||
implementation("org.junit.jupiter:junit-jupiter-engine:5.8.2")
|
||||
implementation("junit:junit:4.13")
|
||||
|
||||
// FastUtil
|
||||
// Note: MC 1.16 uses 8.2.1, and versions after use 8.5.12
|
||||
// We cannot relocate this library since we call some MC classes that reference it
|
||||
implementation("it.unimi.dsi:fastutil:${rootProject.fastutil_version}")
|
||||
|
||||
forgeShadowMe("com.github.luben:zstd-jni:${rootProject.zstd_version}")
|
||||
|
||||
// Compression
|
||||
forgeShadowMe("org.lz4:lz4-java:${rootProject.lz4_version}") // LZ4
|
||||
forgeShadowMe("org.tukaani:xz:${rootProject.xz_version}") // LZMA
|
||||
|
||||
// Sqlite Database
|
||||
forgeShadowMe("org.xerial:sqlite-jdbc:${rootProject.sqlite_jdbc_version}")
|
||||
|
||||
// NightConfig (includes Toml & Json)
|
||||
forgeShadowMe("com.electronwill.night-config:toml:${rootProject.nightconfig_version}")
|
||||
forgeShadowMe("com.electronwill.night-config:json:${rootProject.nightconfig_version}")
|
||||
|
||||
// SVG (not needed atm)
|
||||
// forgeShadowMe("com.formdev:svgSalamander:${rootProject.svgSalamander_version}")
|
||||
|
||||
// Netty
|
||||
implementation("io.netty:netty-buffer:${rootProject.netty_version}")
|
||||
|
||||
// Remember, for lwjgl dependencies that arent included in Minecraft, you need to also need to add it to the ShadowJar thing
|
||||
forgeShadowMe("org.lwjgl:lwjgl-jawt:${rootProject.lwjgl_version}") {
|
||||
exclude group: "org.lwjgl", module: "lwjgl" // This module is imported by Minecraft so exclude it
|
||||
}
|
||||
|
||||
|
||||
|
||||
//==========================//
|
||||
// conditional dependencies //
|
||||
//==========================//
|
||||
|
||||
|
||||
// Add core
|
||||
if (isMinecraftSubProject) {
|
||||
coreProjects(project(":core")) {
|
||||
// Remove Junit test libraries
|
||||
exclude group: "org.junit.jupiter", module: "junit-jupiter"
|
||||
exclude group: "org.junit.jupiter", module: "junit-jupiter-engine"
|
||||
exclude group: "junit", module: "junit"
|
||||
// Removed dependencies
|
||||
transitive false
|
||||
}
|
||||
}
|
||||
|
||||
// Add the api
|
||||
if (p != project(":api")) {
|
||||
coreProjects(project(":api")) {
|
||||
// Remove Junit test libraries
|
||||
exclude group: "org.junit.jupiter", module: "junit-jupiter"
|
||||
exclude group: "org.junit.jupiter", module: "junit-jupiter-engine"
|
||||
exclude group: "junit", module: "junit"
|
||||
// Removed dependencies
|
||||
transitive false
|
||||
}
|
||||
}
|
||||
|
||||
// Add common
|
||||
if (isMinecraftSubProject && p != project(":common")) {
|
||||
// Common
|
||||
common(project(":common")) { transitive false }
|
||||
shadowCommon(project(":common")) { transitive false }
|
||||
|
||||
// FabricLike
|
||||
if (findProject(":fabricLike") && p != project(":fabricLike")) {
|
||||
fabricLike(project(path: ":fabricLike")) { transitive false }
|
||||
shadowFabricLike(project(path: ":fabricLike")) { transitive false }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
shadowJar {
|
||||
configurations = [project.configurations.shadowMe]
|
||||
if (isMinecraftSubProject && p != project(":common")) {
|
||||
configurations.push(project.configurations.shadowCommon) // Shadow the common subproject
|
||||
relocate "com.seibel.distanthorizons.common", "loaderCommon.${p.name}.com.seibel.distanthorizons.common" // Move the loader files to a different location
|
||||
|
||||
if (findProject(":fabricLike") && p != project(":fabricLike")) {
|
||||
configurations.push(project.configurations.shadowFabricLike) // Shadow the fabricLike subproject
|
||||
relocate "com.seibel.distanthorizons.fabriclike", "loaderCommon.${p.name}.com.seibel.distanthorizons.fabriclike" // Move the loader files to a different location
|
||||
}
|
||||
}
|
||||
def librariesLocation = "DistantHorizons.libraries"
|
||||
|
||||
// LWJGL
|
||||
// Only ever shadow the dependencies we use otherwise some stuff would break when running on an external client
|
||||
relocate "org.lwjgl.system.jawt", "${librariesLocation}.lwjgl.system.jawt"
|
||||
|
||||
// Compression (LZ4)
|
||||
relocate "net.jpountz", "${librariesLocation}.jpountz"
|
||||
|
||||
// Logging
|
||||
relocate "org.slf4j", "${librariesLocation}.slf4j"
|
||||
|
||||
// Sqlite Database
|
||||
// librariesLocation isn't used because it's too long for replacing paths in native libraries
|
||||
// Allowing strings larger than the original string would require shifting the entire binary's contents
|
||||
relocate "org.sqlite", "dh_sqlite", {
|
||||
exclude "org/sqlite/native/**"
|
||||
}
|
||||
relocate "jdbc:sqlite", "jdbc:dh_sqlite"
|
||||
|
||||
transform(NativeTransformer) {
|
||||
rootDir = project.rootDir
|
||||
|
||||
matchFiles { it.startsWith("org/sqlite") }
|
||||
mapPaths { it.replace("org/sqlite", "dh_sqlite") }
|
||||
|
||||
relocateNative "org/sqlite", "dh_sqlite"
|
||||
relocateNative "org_sqlite", "dh_1sqlite"
|
||||
}
|
||||
|
||||
// ZStd
|
||||
// librariesLocation isn't used because it's too long for replacing paths in native libraries
|
||||
// Allowing strings larger than the original string would require shifting the entire binary's contents
|
||||
relocate "com.github.luben", "dhcomgithubluben"
|
||||
relocate "libzstd-jni", "libzstd-jni_dh"
|
||||
relocate "zstd-jni", "zstd-jni_dh"
|
||||
|
||||
transform(NativeTransformer) {
|
||||
rootDir = project.rootDir
|
||||
|
||||
matchFiles { it.contains("libzstd-jni") && !it.contains("aix/ppc64") }
|
||||
mapPaths { it.replace("libzstd-jni", "libzstd-jni_dh") }
|
||||
|
||||
relocateNative "com/github/luben", "dhcomgithubluben"
|
||||
relocateNative "com_github_luben", "dhcomgithubluben"
|
||||
}
|
||||
|
||||
|
||||
// JOML
|
||||
if (project.hasProperty("embed_joml") && embed_joml == "true")
|
||||
relocate "org.joml", "${librariesLocation}.joml"
|
||||
|
||||
// NightConfig (includes Toml & Json)
|
||||
relocate "com.electronwill.nightconfig", "${librariesLocation}.electronwill.nightconfig"
|
||||
|
||||
// SVG (not needed atm)
|
||||
// relocate "com.kitfox.svg", "${librariesLocation}.kitfox.svg"
|
||||
|
||||
// Netty
|
||||
// Don't relocate, it causes problems with using MC's FriendlyByteBufs
|
||||
// relocate "io.netty", "${librariesLocation}.netty"
|
||||
|
||||
mergeServiceFiles()
|
||||
}
|
||||
// Using jar.finalizedBy(shadowJar) causes issues so we do this scuffed bypass
|
||||
jar.dependsOn(shadowJar)
|
||||
|
||||
|
||||
// Put stuff from gradle.properties into the mod info
|
||||
processResources {
|
||||
def resourceTargets = [ // Location of where to inject the properties
|
||||
// Holds info like git commit
|
||||
// TODO: For some reason this script doesnt work with the core project
|
||||
"build_info.json",
|
||||
|
||||
// Properties for each of the loaders
|
||||
"fabric.mod.json",
|
||||
"quilt.mod.json",
|
||||
"META-INF/mods.toml",
|
||||
"META-INF/neoforge.mods.toml",
|
||||
|
||||
// The mixins for each of the loaders
|
||||
"DistantHorizons."+ p.name +".fabricLike.mixins.json"
|
||||
]
|
||||
def intoTargets = ["$buildDir/resources/main/"] // Location of the built resources folder
|
||||
|
||||
// Fix forge version numbering system as it is weird
|
||||
// For whatever reason forge uses [1.18, 1.18.1, 1.18.2) instead of the standard ["1.18", "1.18.1", "1.18.2"]
|
||||
def compatible_forgemc_versions = "${compatible_minecraft_versions}".replaceAll("\"", "").replaceAll("]", ",)")
|
||||
// println compatible_forgemc_versions
|
||||
|
||||
// Quilt's custom contributors system
|
||||
// This has to be like
|
||||
// "Person": "Developer", "Another person": "Developer"
|
||||
def quilt_contributors = []
|
||||
def mod_author_list = mod_authors.replaceAll("\"", "").replace("[", "").replace("]", "").split(",")
|
||||
for (dev in mod_author_list) {
|
||||
quilt_contributors.push("\"${dev.strip()}\": \"Developer\"")
|
||||
}
|
||||
quilt_contributors.reverse()
|
||||
//println quilt_contributors.join(", ")
|
||||
|
||||
// TODO: Find something we can use so we can basically re-map only when the jar is shadowed and relocated
|
||||
// println p.tasks.findByName('shadowJar')
|
||||
|
||||
|
||||
// These "hasProperty"'s are so that they can be passed through the cli (ie in the CI)
|
||||
try {
|
||||
if (infoGitCommit == "null")
|
||||
infoGitCommit = 'git rev-parse --verify HEAD'.execute().text.trim()
|
||||
if (infoGitBranch == "null")
|
||||
infoGitBranch = 'git symbolic-ref --short HEAD'.execute().text.trim()
|
||||
} catch (Exception e) {
|
||||
infoGitCommit = infoGitBranch = "Git not found"
|
||||
println "Git or Git project not found"
|
||||
}
|
||||
|
||||
// The left side is what gets replaced in the mod info and the right side is where to get it from in the gradle.properties
|
||||
def replaceProperties = [
|
||||
version : mod_version,
|
||||
mod_name : mod_readable_name,
|
||||
group : maven_group,
|
||||
authors : mod_authors,
|
||||
description : mod_description,
|
||||
homepage : mod_homepage,
|
||||
source : mod_source,
|
||||
issues : mod_issues,
|
||||
discord : mod_discord,
|
||||
minecraft_version : minecraft_version,
|
||||
compatible_minecraft_versions: compatible_minecraft_versions,
|
||||
compatible_forgemc_versions : compatible_forgemc_versions,
|
||||
java_version : java_version,
|
||||
quilt_contributors : "{"+quilt_contributors.join(", ")+"}",
|
||||
|
||||
info_git_commit : infoGitBranch,
|
||||
info_git_branch : infoGitCommit,
|
||||
info_build_source : infoBuildSource,
|
||||
|
||||
fabric_incompatibility_list : fabric_incompatibility_list,
|
||||
fabric_recommend_list : fabric_recommend_list,
|
||||
|
||||
neoforge_version_range : neoforge_version_range,
|
||||
]
|
||||
|
||||
// replace any properties in the sub-projects with the values defined here
|
||||
inputs.properties replaceProperties
|
||||
replaceProperties.put "project", project
|
||||
filesMatching(resourceTargets) {
|
||||
expand replaceProperties
|
||||
}
|
||||
|
||||
intoTargets.each { target ->
|
||||
if (file(target).exists()) {
|
||||
copy {
|
||||
from(sourceSets.main.resources) {
|
||||
include resourceTargets
|
||||
expand replaceProperties
|
||||
}
|
||||
into target
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ==================== Delete un-needed files ====================
|
||||
exclude "DistantHorizons.fabricLike.mixins.json" // This isnt required atm, but we will be using it later
|
||||
|
||||
// exclude "*.distanthorizons.accesswidener"
|
||||
//// include "${accessWidenerVersion}.distanthorizons.accesswidener"
|
||||
|
||||
// Jank solution to remove all unused accesswideners
|
||||
// The line above would work..., except that (neo)forge (well, mainly architectury) requires the original accesswidener file, meaning we require this jank solution to keep it
|
||||
exclude { file ->
|
||||
if (file.name.contains(".distanthorizons.accesswidener") && file.name != "${accessWidenerVersion}.distanthorizons.accesswidener") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Adds the standalone jar's entrypoint
|
||||
jar {
|
||||
from "LICENSE.txt"
|
||||
manifest {
|
||||
attributes(
|
||||
'Implementation-Title': rootProject.mod_name,
|
||||
'Implementation-Version': rootProject.mod_version,
|
||||
'Multi-Release': true, // needed for logging in the standalone core jar
|
||||
'Main-Class': 'com.seibel.distanthorizons.core.jar.JarMain', // When changing the main of the jar change this line
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// this can be un-commented if we ever wanted to make DH modular (AKA use a module-info.java file) again
|
||||
/*
|
||||
// Tells gradle where to look for other modules
|
||||
// Why isn't the classpath added to the modules path by default?
|
||||
if (p == project(":core")) {
|
||||
compileJava {
|
||||
inputs.property('moduleName', 'dhApi')
|
||||
doFirst {
|
||||
options.compilerArgs = [
|
||||
'--module-path', classpath.asPath
|
||||
]
|
||||
classpath = files()
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
allprojects { p ->
|
||||
// Does the same as "p == project(":common") || p == project(":fabric") || p == project(":quilt") || p == project(":forge") || p == project("WhateverWeAddLaterOn")"
|
||||
// Useful later on so we dont have duplicated code
|
||||
def isMinecraftSubProject = p != project(":core") && p != project(":api")
|
||||
|
||||
|
||||
apply plugin: "java"
|
||||
apply plugin: "maven-publish"
|
||||
|
||||
// Sets the name of the jar, the version will contain the name of the project if it isn't the root project
|
||||
archivesBaseName = rootProject.mod_name
|
||||
version = (project == rootProject ? "" : project.name + "-") + rootProject.versionStr
|
||||
group = rootProject.maven_group
|
||||
|
||||
// this is the text that appears at the top of the overview (home) page
|
||||
// and is used when bookmarking a page
|
||||
javadoc.title = rootProject.mod_name + "-" + project.name
|
||||
|
||||
// Some annotations arent "technically" part of the official java standard,
|
||||
// so we define it ourself here
|
||||
javadoc {
|
||||
configure( options ) {
|
||||
tags(
|
||||
'todo:X"',
|
||||
'apiNote:a:API Note:',
|
||||
'implSpec:a:Implementation Requirements:',
|
||||
'implNote:a:Implementation Note:'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
repositories {
|
||||
// Mojang overrides (added to fix downloading the wrong LWJGL libs on M1 Mac's and potentially other arm64 based machines)
|
||||
maven { url "https://libraries.minecraft.net/" }
|
||||
|
||||
// The central repo
|
||||
mavenCentral()
|
||||
|
||||
// Used for Google's Collect library
|
||||
maven { url "https://repo.enonic.com/public/" }
|
||||
|
||||
// For parchment mappings
|
||||
// versions can be found here: https://ldtteam.jfrog.io/ui/native/parchmentmc-public/org/parchmentmc/data/
|
||||
maven { url "https://maven.parchmentmc.org" }
|
||||
|
||||
// For Architectury API
|
||||
maven { url "https://maven.architectury.dev" }
|
||||
|
||||
// For Git repositories
|
||||
maven { url "https://jitpack.io" }
|
||||
|
||||
// For Manifold Preprocessor
|
||||
maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
|
||||
|
||||
// Required for importing Modrinth mods
|
||||
maven {
|
||||
name = "Modrinth"
|
||||
url = "https://api.modrinth.com/maven"
|
||||
content {
|
||||
includeGroup "maven.modrinth"
|
||||
}
|
||||
}
|
||||
|
||||
// Required for importing CursedForge mods
|
||||
maven {
|
||||
url "https://www.cursemaven.com"
|
||||
content {
|
||||
includeGroup "curse.maven"
|
||||
}
|
||||
}
|
||||
|
||||
// VanillaGradle and Mixins in common
|
||||
maven { url "https://repo.spongepowered.org/maven/" }
|
||||
|
||||
// Canvas mod
|
||||
maven { url "https://maven.vram.io/" }
|
||||
// ModMenu mod
|
||||
maven { url "https://maven.terraformersmc.com/" }
|
||||
|
||||
// neoforge
|
||||
maven { url "https://maven.neoforged.net/releases/" }
|
||||
|
||||
// These 3 are for importing mods that arnt on CursedForge, Modrinth, GitHub, GitLab or anywhere opensource
|
||||
flatDir {
|
||||
dirs "${rootDir}/mods/fabric"
|
||||
content {
|
||||
includeGroup "fabric-mod"
|
||||
}
|
||||
}
|
||||
flatDir {
|
||||
dirs "${rootDir}/mods/quilt"
|
||||
content {
|
||||
includeGroup "quilt-mod"
|
||||
}
|
||||
}
|
||||
flatDir {
|
||||
dirs "${rootDir}/mods/forge"
|
||||
content {
|
||||
includeGroup "forge-mod"
|
||||
}
|
||||
}
|
||||
// TODO: If neoforged is ever needed, should we use that, or call it a forge mod?
|
||||
}
|
||||
|
||||
// Adds some dependencies that are in vanilla but not in core
|
||||
if (p == project(":core")) {
|
||||
OperatingSystem os = org.gradle.nativeplatform.platform.internal.DefaultNativePlatform.currentOperatingSystem;
|
||||
|
||||
// Set the OS lwjgl is using to the current os
|
||||
project.ext.lwjglNatives = "natives-" + os.toFamilyName()
|
||||
|
||||
dependencies { // All of these dependencies are in Vanilla Minecraft, but we need to depend on it as we arent importing Minecraft in the core
|
||||
// Imports most of lwjgl's libraries (well, only the ones that we need)
|
||||
implementation platform("org.lwjgl:lwjgl-bom:${rootProject.lwjgl_version}") // TODO: Use Minecraft's version for lwjgl_version (which changes in nearly every version) instead of a hard defined version for all versions
|
||||
|
||||
// REMEMBER: Dont shadow stuff here, these are just the libs that are included in Minecraft so that the core can use
|
||||
implementation "org.lwjgl:lwjgl"
|
||||
implementation "org.lwjgl:lwjgl-assimp"
|
||||
implementation "org.lwjgl:lwjgl-glfw"
|
||||
implementation "org.lwjgl:lwjgl-openal"
|
||||
implementation "org.lwjgl:lwjgl-opengl"
|
||||
implementation "org.lwjgl:lwjgl-stb"
|
||||
implementation "org.lwjgl:lwjgl-tinyfd"
|
||||
runtimeOnly "org.lwjgl:lwjgl::$lwjglNatives"
|
||||
runtimeOnly "org.lwjgl:lwjgl-assimp::$lwjglNatives"
|
||||
runtimeOnly "org.lwjgl:lwjgl-glfw::$lwjglNatives"
|
||||
runtimeOnly "org.lwjgl:lwjgl-openal::$lwjglNatives"
|
||||
runtimeOnly "org.lwjgl:lwjgl-opengl::$lwjglNatives"
|
||||
runtimeOnly "org.lwjgl:lwjgl-stb::$lwjglNatives"
|
||||
runtimeOnly "org.lwjgl:lwjgl-tinyfd::$lwjglNatives"
|
||||
implementation "org.joml:joml:${rootProject.joml_version}"
|
||||
|
||||
|
||||
// Some other dependencies
|
||||
implementation("org.jetbrains:annotations:16.0.2")
|
||||
implementation("com.google.code.findbugs:jsr305:3.0.2")
|
||||
implementation("com.google.common:google-collect:0.5")
|
||||
implementation("com.google.guava:guava:31.1-jre")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
task copyCommonLoaderResources(type: Copy) {
|
||||
from project(":common").file("src/main/resources/${accessWidenerVersion}.distanthorizons.accesswidener")
|
||||
into(file(p.file("build/resources/main")))
|
||||
rename "${accessWidenerVersion}.distanthorizons.accesswidener", "distanthorizons.accesswidener"
|
||||
|
||||
|
||||
// Move the fabricLike mixin to its different places for each subproject
|
||||
if (findProject(":fabricLike")) {
|
||||
from project(":fabricLike").file("src/main/resources/DistantHorizons.fabricLike.mixins.json")
|
||||
into(file(p.file("build/resources/main")))
|
||||
rename "DistantHorizons.fabricLike.mixins.json", "DistantHorizons." + p.name + ".fabricLike.mixins.json"
|
||||
}
|
||||
}
|
||||
|
||||
task copyCoreResources(type: Copy) {
|
||||
from fileTree(project(":core").file("src/main/resources"))
|
||||
into p.file("build/resources/main")
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile) {
|
||||
if (isMinecraftSubProject) {
|
||||
options.release = rootProject.java_version as Integer
|
||||
} else {
|
||||
options.release = 8; // Core & Api should use Java 8 no matter what
|
||||
//options.release = rootProject.java_version as Integer // But if you want to test some stuff, then this can be enabled
|
||||
}
|
||||
options.encoding = "UTF-8"
|
||||
}
|
||||
|
||||
java {
|
||||
withSourcesJar()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
echo "==================== Note: All build jars will be in the folder called 'buildAllJars' ===================="
|
||||
mkdir -p buildAllJars
|
||||
rm -rf buildAllJars/*
|
||||
rm -rf build/forgix/*
|
||||
|
||||
# Loop trough everything in the version properties folder
|
||||
for d in versionProperties/*; do
|
||||
@@ -19,10 +20,6 @@ for d in versionProperties/*; do
|
||||
sh gradlew build -PmcVer=$version
|
||||
if [ $? != 0 ]; then continue; fi
|
||||
|
||||
echo "==================== Merging $version ===================="
|
||||
sh gradlew mergeJars -PmcVer=$version
|
||||
if [ $? != 0 ]; then continue; fi
|
||||
|
||||
echo "==================== Moving jar ===================="
|
||||
mv build/merged/*.jar buildAllJars/
|
||||
mv build/forgix/*.jar buildAllJars/
|
||||
done
|
||||
|
||||
+2
-4
@@ -6,6 +6,7 @@
|
||||
echo ==================== Note: All build jars will be in the folder called 'buildAllJars' ====================
|
||||
mkdir buildAllJars
|
||||
del buildAllJars/*
|
||||
del build/forgix/*
|
||||
|
||||
@rem Loop trough everything in the version properties folder
|
||||
for %%f in (versionProperties\*) do (
|
||||
@@ -19,11 +20,8 @@ for %%f in (versionProperties\*) do (
|
||||
echo ==================== Building !version! ====================
|
||||
call .\gradlew.bat build -PmcVer="!version!"
|
||||
|
||||
echo ==================== Merging !version! ====================
|
||||
call .\gradlew.bat mergeJars -PmcVer="!version!"
|
||||
|
||||
echo ==================== Moving jar ====================
|
||||
move build\merged\*.jar buildAllJars\
|
||||
move build\forgix\*.jar buildAllJars\
|
||||
)
|
||||
|
||||
endlocal
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
@echo off & setlocal enabledelayedexpansion
|
||||
|
||||
|
||||
echo ==================== Getting versions to build... ====================
|
||||
mkdir _buildAllJars 2>nul
|
||||
del _buildAllJars\* /Q 2>nul
|
||||
|
||||
set "ROOT=%~dp0"
|
||||
set "WORK_DIR=%ROOT%_buildWorkers"
|
||||
mkdir "%WORK_DIR%" 2>nul
|
||||
|
||||
|
||||
REM get the number of versions to compile
|
||||
set count=0
|
||||
for %%f in (versionProperties\*) do set /a count+=1
|
||||
echo ==================== Found %count% versions to build in parallel ====================
|
||||
|
||||
REM Launch a parallel job for each version
|
||||
for %%f in (%ROOT%versionProperties\*) do (
|
||||
set version=%%~nf
|
||||
|
||||
echo starting [!version!]...
|
||||
start "Build !version!" cmd /c ""%ROOT%build_worker.bat" "!version!" "%ROOT%" "%WORK_DIR%" ""..\..\_buildAllJars"""
|
||||
|
||||
REM Minor timeout between launches so we can stop the build early if we only want
|
||||
REM to test part of the script and to reduce startup load
|
||||
timeout /t 3 /nobreak
|
||||
|
||||
REM 2>nul to supress a harmless warning that the for loop
|
||||
REM "cannot find the drive specified"
|
||||
) 2>nul
|
||||
|
||||
|
||||
echo ==================== All builds started... Completed Jars will be in _buildAllJars ====================
|
||||
endlocal
|
||||
@@ -0,0 +1,24 @@
|
||||
plugins {
|
||||
id 'groovy-gradle-plugin'
|
||||
}
|
||||
|
||||
repositories {
|
||||
gradlePluginPortal()
|
||||
mavenCentral()
|
||||
maven { url = 'https://maven.wagyourtail.xyz/releases' } // Jvmdowngrader & unimined libs
|
||||
maven { url = 'https://maven.outlands.top/releases' } // Hosts the kappa fork of unimined
|
||||
maven { url = 'https://maven.wagyourtail.xyz/snapshots' } // The manifold gradle plugin we use
|
||||
maven { url = 'https://maven.architectury.dev/' } // Minecraft mod libs
|
||||
maven { url = 'https://maven.fabricmc.net/' } // Fabric
|
||||
maven { url = 'https://maven.neoforged.net/releases/' } // NeoForge
|
||||
maven { url = 'https://maven.minecraftforge.net/' } // Forge
|
||||
maven { url = 'https://repo.spongepowered.org/repository/maven-public/' } // Hosts minecraft libs
|
||||
maven { url = 'https://oss.sonatype.org/content/repositories/snapshots/' } // Hosts a few dependencies we use
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.gradleup.shadow:shadow-gradle-plugin:9.0.0'
|
||||
implementation 'xyz.wagyourtail.unimined:xyz.wagyourtail.unimined.gradle.plugin:1.4.18-kappa'
|
||||
implementation 'xyz.wagyourtail:manifold-gradle:1.0.0-SNAPSHOT'
|
||||
implementation 'xyz.wagyourtail.jvmdowngrader:xyz.wagyourtail.jvmdowngrader.gradle.plugin:1.3.4'
|
||||
}
|
||||
@@ -0,0 +1,516 @@
|
||||
import com.github.jengelman.gradle.plugins.shadow.transformers.ResourceTransformer
|
||||
import com.github.jengelman.gradle.plugins.shadow.transformers.TransformerContext
|
||||
import org.apache.tools.zip.ZipEntry
|
||||
import org.apache.tools.zip.ZipOutputStream
|
||||
|
||||
import javax.annotation.Nonnull
|
||||
import java.util.function.Function
|
||||
import java.util.function.Predicate
|
||||
|
||||
// Convention plugin for all MC-facing subprojects (common + loaders).
|
||||
// Common uses this directly; loaders use it via unimined-fabric/forge/neoforge.
|
||||
// IMPORTANT: unimined MUST be applied before shadow/jvmdowngrader
|
||||
// so its afterEvaluate runs first and can modify configs.
|
||||
|
||||
plugins {
|
||||
id 'java'
|
||||
id 'maven-publish'
|
||||
id 'xyz.wagyourtail.unimined'
|
||||
id 'com.gradleup.shadow'
|
||||
id 'xyz.wagyourtail.manifold'
|
||||
id 'xyz.wagyourtail.jvmdowngrader'
|
||||
}
|
||||
|
||||
def isNotCommonProject = project.name != "common"
|
||||
|
||||
|
||||
// ==================== Version Properties ====================
|
||||
|
||||
project.gradle.ext.getProperties().each { prop ->
|
||||
rootProject.ext.set(prop.key, prop.value)
|
||||
}
|
||||
|
||||
manifold {
|
||||
version = rootProject.manifold_version
|
||||
}
|
||||
|
||||
|
||||
// ==================== Repositories ====================
|
||||
|
||||
repositories {
|
||||
maven { url "https://libraries.minecraft.net/" }
|
||||
mavenCentral()
|
||||
maven { url "https://repo.enonic.com/public/" }
|
||||
maven { url "https://maven.parchmentmc.org" }
|
||||
maven { url "https://maven.architectury.dev" }
|
||||
maven { url "https://jitpack.io" }
|
||||
maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
|
||||
maven {
|
||||
name = "Modrinth"
|
||||
url = "https://api.modrinth.com/maven"
|
||||
content { includeGroup "maven.modrinth" }
|
||||
}
|
||||
maven {
|
||||
url "https://www.cursemaven.com"
|
||||
content { includeGroup "curse.maven" }
|
||||
}
|
||||
maven {
|
||||
url "https://repo.spongepowered.org/maven/"
|
||||
// exclusion is needed since sponge has a deprecated version of fabric
|
||||
// that gradle would prefer to get over the up-to-date version modrinth provides
|
||||
content { excludeGroupByRegex "net\\.fabricmc(\\..*)?" }
|
||||
}
|
||||
maven { url "https://maven.terraformersmc.com/" }
|
||||
maven { url "https://maven.neoforged.net/releases/" }
|
||||
flatDir {
|
||||
dirs "${rootDir}/mods/fabric"
|
||||
content { includeGroup "fabric-mod" }
|
||||
}
|
||||
flatDir {
|
||||
dirs "${rootDir}/mods/quilt"
|
||||
content { includeGroup "quilt-mod" }
|
||||
}
|
||||
flatDir {
|
||||
dirs "${rootDir}/mods/forge"
|
||||
content { includeGroup "forge-mod" }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ==================== Java Config ====================
|
||||
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
options.release = rootProject.java_version as Integer
|
||||
options.encoding = "UTF-8"
|
||||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.toVersion(gradle.ext.java_version as Integer)
|
||||
targetCompatibility = JavaVersion.toVersion(gradle.ext.java_version as Integer)
|
||||
withSourcesJar()
|
||||
}
|
||||
|
||||
|
||||
// ==================== Loader-Only Config ====================
|
||||
|
||||
if (isNotCommonProject) {
|
||||
base { archivesName = rootProject.mod_name }
|
||||
rootProject.ext.versionStr = rootProject.mod_version + "-" + rootProject.minecraft_version
|
||||
version = project.name + "-" + rootProject.versionStr
|
||||
group = rootProject.maven_group
|
||||
|
||||
javadoc.title = rootProject.mod_name + "-" + project.name
|
||||
|
||||
tasks.withType(GenerateModuleMetadata).configureEach {
|
||||
enabled = false
|
||||
}
|
||||
tasks.withType(Test).configureEach {
|
||||
enabled = false
|
||||
}
|
||||
compileTestJava.enabled = false
|
||||
tasks.withType(Sign).configureEach {
|
||||
enabled = false
|
||||
}
|
||||
|
||||
jar {
|
||||
from "LICENSE.txt"
|
||||
manifest {
|
||||
attributes(
|
||||
'Implementation-Title': rootProject.mod_name,
|
||||
'Implementation-Version': rootProject.mod_version,
|
||||
'Multi-Release': true,
|
||||
'Main-Class': 'com.seibel.distanthorizons.core.jar.JarMain',
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ==================== Unimined Minecraft Config ====================
|
||||
|
||||
unimined.minecraft(sourceSets.main, true) {
|
||||
version gradle.ext.minecraft_version
|
||||
|
||||
if (gradle.ext.minecraft_version.startsWith("1.")) { // 26.1+ doesn't use obfuscation
|
||||
mappings {
|
||||
mojmap()
|
||||
devNamespace "mojmap"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isNotCommonProject) {
|
||||
// Mixin remapping and common project wiring
|
||||
unimined.minecraft(sourceSets.main, true) {
|
||||
mods.modImplementation {
|
||||
mixinRemap {
|
||||
reset()
|
||||
enableBaseMixin()
|
||||
enableMixinExtra()
|
||||
}
|
||||
// Some Fabric API modules ship AW in 'named' namespace instead of 'intermediary'
|
||||
catchAWNamespaceAssertion()
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":common"))
|
||||
}
|
||||
|
||||
processResources {
|
||||
from project(":common").sourceSets.main.resources
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
source(project(":common").sourceSets.main.allSource)
|
||||
}
|
||||
} else {
|
||||
// Common: fabric for compilation + access widener, no jar remapping or runs
|
||||
unimined.minecraft {
|
||||
fabric {
|
||||
loader gradle.ext.fabric_loader_version
|
||||
accessWidener project.file("src/main/resources/${gradle.ext.accessWidenerVersion}.distanthorizons.accesswidener")
|
||||
}
|
||||
defaultRemapJar = false
|
||||
runs.off = true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ==================== Configurations ====================
|
||||
|
||||
evaluationDependsOn(":core")
|
||||
|
||||
configurations {
|
||||
shadowMe
|
||||
coreProjects
|
||||
shadowMe.extendsFrom(coreProjects)
|
||||
implementation.extendsFrom(shadowMe)
|
||||
|
||||
common
|
||||
implementation.extendsFrom(common)
|
||||
}
|
||||
|
||||
|
||||
// ==================== Dependencies ====================
|
||||
|
||||
// Copy core's compileOnly deps so MC-provided deps are visible without redeclaring them.
|
||||
project(":core").configurations.compileOnly.allDependencies.each { dep ->
|
||||
if (!(dep instanceof ProjectDependency))
|
||||
dependencies.add("compileOnly", dep)
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// Manifold preprocessor & strings
|
||||
annotationProcessor(manifold.module("preprocessor"))
|
||||
|
||||
// NightConfig: implementation in core (bundled) but Unimined strips it from compile classpath
|
||||
compileOnly("com.electronwill.night-config:toml:${rootProject.nightconfig_version}")
|
||||
|
||||
// Core & API projects — bundled into shadow jar
|
||||
coreProjects(project(":core"))
|
||||
coreProjects(project(":api"))
|
||||
|
||||
// JOML: shadow for old MC versions that don't bundle it (core has it compileOnly already)
|
||||
if (project.hasProperty("embed_joml") && embed_joml == "true")
|
||||
shadowMe("org.joml:joml:${rootProject.joml_version}")
|
||||
|
||||
// Common project dependency
|
||||
if (isNotCommonProject)
|
||||
common(project(":common")) { transitive false }
|
||||
}
|
||||
|
||||
|
||||
// ==================== NativeTransformer ====================
|
||||
|
||||
class NativeTransformer implements ResourceTransformer {
|
||||
private Predicate<String> fileMatcher
|
||||
private Function<String, String> filePathMapper
|
||||
|
||||
private final HashMap<String, String> replacements = new HashMap()
|
||||
private final HashMap<String, byte[]> rewrittenFiles = new HashMap()
|
||||
private nativeRelocator
|
||||
|
||||
public File rootDir
|
||||
|
||||
void matchFiles(Predicate<String> matcher) {
|
||||
fileMatcher = matcher
|
||||
}
|
||||
|
||||
void mapPaths(Function<String, String> mapper) {
|
||||
filePathMapper = mapper
|
||||
}
|
||||
|
||||
void relocateNative(String target, String replacement) {
|
||||
if (replacement.length() > target.length()) {
|
||||
throw new GradleException("Length of value \"${replacement}\" exceeds the length of \"${target}\": ${replacement.length()} > ${target.length()}")
|
||||
}
|
||||
replacements.put(target, replacement)
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean canTransformResource(@Nonnull FileTreeElement element) {
|
||||
return fileMatcher != null && fileMatcher.test(element.relativePath.pathString)
|
||||
}
|
||||
|
||||
@Override
|
||||
void transform(@Nonnull TransformerContext context) {
|
||||
byte[] content = context.inputStream.readAllBytes()
|
||||
|
||||
if (nativeRelocator == null) {
|
||||
nativeRelocator = new NativeRelocator(rootDir.toPath().resolve("relocate_natives"))
|
||||
}
|
||||
|
||||
try {
|
||||
String path = filePathMapper != null
|
||||
? filePathMapper.apply(context.path)
|
||||
: context.path
|
||||
content = nativeRelocator.processBinary(path, content, replacements)
|
||||
rewrittenFiles.put(path, content)
|
||||
}
|
||||
catch (Throwable e) {
|
||||
throw new GradleException("Failed to relocate", e)
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean hasTransformedResource() { return !rewrittenFiles.isEmpty() }
|
||||
|
||||
@Override
|
||||
void modifyOutputStream(@Nonnull ZipOutputStream os, boolean preserveFileTimestamps) {
|
||||
for (Map.Entry<String, byte[]> rewrittenFile : rewrittenFiles.entrySet()) {
|
||||
os.putNextEntry(new ZipEntry(rewrittenFile.key))
|
||||
os.write(rewrittenFile.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ==================== Shadow JAR (loaders only) ====================
|
||||
|
||||
if (isNotCommonProject) {
|
||||
shadowJar {
|
||||
configurations = [project.configurations.shadowMe]
|
||||
def librariesLocation = "DistantHorizons.libraries"
|
||||
|
||||
// LZ4
|
||||
relocate "net.jpountz", "${librariesLocation}.jpountz"
|
||||
|
||||
// SLF4J
|
||||
relocate "org.slf4j", "${librariesLocation}.slf4j"
|
||||
|
||||
// SQLite
|
||||
relocate "org.sqlite", "dh_sqlite", { exclude "org/sqlite/native/**" }
|
||||
relocate "jdbc:sqlite", "jdbc:dh_sqlite"
|
||||
|
||||
transform(NativeTransformer) {
|
||||
rootDir = project.rootDir
|
||||
matchFiles { it.startsWith("org/sqlite") }
|
||||
mapPaths { it.replace("org/sqlite", "dh_sqlite") }
|
||||
relocateNative "org/sqlite", "dh_sqlite"
|
||||
relocateNative "org_sqlite", "dh_1sqlite"
|
||||
}
|
||||
|
||||
// ZStd
|
||||
relocate "com.github.luben", "dhcomgithubluben"
|
||||
relocate "libzstd-jni", "libzstd-jni_dh"
|
||||
relocate "zstd-jni", "zstd-jni_dh"
|
||||
|
||||
transform(NativeTransformer) {
|
||||
rootDir = project.rootDir
|
||||
matchFiles { it.contains("libzstd-jni") && !it.contains("aix/ppc64") }
|
||||
mapPaths { it.replace("libzstd-jni", "libzstd-jni_dh") }
|
||||
relocateNative "com/github/luben", "dhcomgithubluben"
|
||||
relocateNative "com_github_luben", "dhcomgithubluben"
|
||||
}
|
||||
|
||||
// JOML (conditional)
|
||||
if (project.hasProperty("embed_joml") && embed_joml == "true")
|
||||
relocate "org.joml", "${librariesLocation}.joml"
|
||||
|
||||
// NightConfig
|
||||
relocate "com.electronwill.nightconfig", "${librariesLocation}.electronwill.nightconfig"
|
||||
|
||||
mergeServiceFiles()
|
||||
}
|
||||
afterEvaluate {
|
||||
tasks.named("remapJar").configure {
|
||||
dependsOn(shadowJar)
|
||||
inputFile.set(shadowJar.archiveFile)
|
||||
}
|
||||
|
||||
// Make run tasks use the shadow jar so relocated deps work in dev.
|
||||
// Filter out jars bundled in the shadow jar, but keep jars that the loader also
|
||||
// needs (e.g. NightConfig — DH relocates it, but NeoForge needs the original).
|
||||
def shadowedPaths = configurations.shadowMe.resolve().collect { it.path }.toSet()
|
||||
def loaderPaths = configurations.minecraftLibraries.resolve().collect { it.path }.toSet()
|
||||
tasks.withType(JavaExec).configureEach { runTask ->
|
||||
dependsOn(shadowJar)
|
||||
classpath = files(shadowJar.archiveFile) + classpath.filter { file ->
|
||||
!file.path.contains(project.buildDir.path) &&
|
||||
!file.path.contains("core${File.separator}build") &&
|
||||
!file.path.contains("api${File.separator}build") &&
|
||||
!file.path.contains("common${File.separator}build") &&
|
||||
!(shadowedPaths.contains(file.path) && !loaderPaths.contains(file.path))
|
||||
}
|
||||
|
||||
// Shared run directory so all loaders use the same worlds
|
||||
def isClient = runTask.name.toLowerCase().contains("client")
|
||||
runTask.workingDir = rootProject.file("run/${isClient ? 'client' : 'server'}")
|
||||
|
||||
// Minecraft automatically has G1GC args present,
|
||||
// remove them so we can use ZGC instead
|
||||
def filteredArgs = runTask.jvmArgs.findAll { arg ->
|
||||
!arg.startsWith("-XX:+UseG1GC") &&
|
||||
!arg.startsWith("-XX:G1") &&
|
||||
!arg.startsWith("-XX:MaxGCPauseMillis")
|
||||
}
|
||||
runTask.jvmArgs = filteredArgs
|
||||
|
||||
// fix (Neo)forge debug running
|
||||
doFirst {
|
||||
def modsDir = rootProject.file("run/${isClient ? 'client' : 'server'}/mods")
|
||||
modsDir.mkdirs()
|
||||
|
||||
// Remove any stale DH jars before copying the fresh one
|
||||
modsDir.listFiles()?.each { file ->
|
||||
if (file.name.startsWith(rootProject.mod_name)) file.delete()
|
||||
}
|
||||
|
||||
// Copy shadow jar into mods folder so (Neo)Forge discovers it properly
|
||||
copy {
|
||||
from shadowJar.archiveFile
|
||||
into modsDir
|
||||
}
|
||||
}
|
||||
|
||||
// JVM args
|
||||
runTask.jvmArgs(
|
||||
"-Dio.netty.leakDetection.level=advanced",
|
||||
// TODO only use for modern java versions
|
||||
"-XX:+UseZGC",
|
||||
// TODO don't use for even more modern-er java versions
|
||||
//"-XX:+ZGenerational",
|
||||
rootProject.minecraftMemoryJavaArg,
|
||||
)
|
||||
if (isClient)
|
||||
{
|
||||
runTask.jvmArgs(
|
||||
"-Dminecraft.api.auth.host=https://nope.invalid",
|
||||
"-Dminecraft.api.account.host=https://nope.invalid",
|
||||
"-Dminecraft.api.session.host=https://nope.invalid",
|
||||
"-Dminecraft.api.services.host=https://nope.invalid",
|
||||
)
|
||||
runTask.args(
|
||||
// use a consistent username for easier debugging in a given world (vs randomly teleporting to a new user each time the game boots)
|
||||
"--username", "Dev",
|
||||
// "--renderDebugLabels" is a Mojang command to show render names in RenderDoc
|
||||
"--renderDebugLabels"
|
||||
)
|
||||
|
||||
// enabling tracy causes constant memory growth so it isn't always desired
|
||||
if (rootProject.minecraftEnableTracy == "true")
|
||||
{
|
||||
// "--tracy" is a Mojang command to allow individual frames to be debugged using Tracy https://github.com/wolfpld/tracy/releases/tag/v0.13.1
|
||||
runTask.args("--tracy")
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ==================== Process Resources (loaders only) ====================
|
||||
|
||||
if (isNotCommonProject) {
|
||||
processResources {
|
||||
def resourceTargets = [
|
||||
"build_info.json",
|
||||
"fabric.mod.json",
|
||||
"quilt.mod.json",
|
||||
"META-INF/mods.toml",
|
||||
"META-INF/neoforge.mods.toml",
|
||||
]
|
||||
|
||||
def compatible_forgemc_versions = "${rootProject.compatible_minecraft_versions}".replaceAll("\"", "").replaceAll("]", ",)")
|
||||
|
||||
// Quilt contributors
|
||||
def quilt_contributors = []
|
||||
def mod_author_list = rootProject.mod_authors.replaceAll("\"", "").replace("[", "").replace("]", "").split(",")
|
||||
for (dev in mod_author_list) {
|
||||
quilt_contributors.push("\"${dev.strip()}\": \"Developer\"")
|
||||
}
|
||||
quilt_contributors.reverse()
|
||||
|
||||
try {
|
||||
if (rootProject.infoGitCommit == "null")
|
||||
rootProject.ext.infoGitCommit = 'git rev-parse --verify HEAD'.execute().text.trim()
|
||||
if (rootProject.infoGitBranch == "null")
|
||||
rootProject.ext.infoGitBranch = 'git symbolic-ref --short HEAD'.execute().text.trim()
|
||||
} catch (Exception e) {
|
||||
rootProject.ext.infoGitCommit = "Git not found"
|
||||
rootProject.ext.infoGitBranch = "Git not found"
|
||||
}
|
||||
|
||||
def replaceProperties = [
|
||||
version : rootProject.mod_version,
|
||||
mod_name : rootProject.mod_readable_name,
|
||||
group : rootProject.maven_group,
|
||||
authors : rootProject.mod_authors,
|
||||
description : rootProject.mod_description,
|
||||
homepage : rootProject.mod_homepage,
|
||||
source : rootProject.mod_source,
|
||||
issues : rootProject.mod_issues,
|
||||
discord : rootProject.mod_discord,
|
||||
minecraft_version : rootProject.minecraft_version,
|
||||
accessWidenerVersion : rootProject.accessWidenerVersion,
|
||||
compatible_minecraft_versions: rootProject.compatible_minecraft_versions,
|
||||
compatible_forgemc_versions : compatible_forgemc_versions,
|
||||
java_version : rootProject.java_version,
|
||||
quilt_contributors : "{" + quilt_contributors.join(", ") + "}",
|
||||
info_git_commit : rootProject.infoGitBranch,
|
||||
info_git_branch : rootProject.infoGitCommit,
|
||||
info_build_source : rootProject.infoBuildSource,
|
||||
fabric_incompatibility_list : rootProject.fabric_incompatibility_list,
|
||||
fabric_recommend_list : rootProject.fabric_recommend_list,
|
||||
neoforge_version_range : rootProject.neoforge_version_range,
|
||||
]
|
||||
|
||||
inputs.properties replaceProperties
|
||||
replaceProperties.put "project", project
|
||||
filesMatching(resourceTargets) {
|
||||
expand replaceProperties
|
||||
}
|
||||
|
||||
// Remove unused access wideners
|
||||
exclude { file ->
|
||||
if (file.name.contains(".distanthorizons.accesswidener") && file.name != "${rootProject.accessWidenerVersion}.distanthorizons.accesswidener") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ==================== Resource Copy Tasks ====================
|
||||
|
||||
// task copyCommonLoaderResources(type: Copy) {
|
||||
// from project(":common").file("src/main/resources/${rootProject.accessWidenerVersion}.distanthorizons.accesswidener")
|
||||
// into(file(project.file("build/resources/main")))
|
||||
// rename "${rootProject.accessWidenerVersion}.distanthorizons.accesswidener", "distanthorizons.accesswidener"
|
||||
// }
|
||||
|
||||
task copyCoreResources(type: Copy) {
|
||||
from fileTree(project(":core").file("src/main/resources"))
|
||||
into project.file("build/resources/main")
|
||||
}
|
||||
|
||||
|
||||
// ==================== JVMDowngrader ====================
|
||||
|
||||
jvmdg.downgradeTo = JavaVersion.toVersion(rootProject.java_version)
|
||||
downgradeJar.archiveClassifier.set(null)
|
||||
shadeDowngradedApi.archiveClassifier.set(null)
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
plugins {
|
||||
id 'java'
|
||||
}
|
||||
|
||||
// Transfer version properties from settings.gradle to project
|
||||
project.gradle.ext.getProperties().each { prop ->
|
||||
rootProject.ext.set(prop.key, prop.value)
|
||||
}
|
||||
|
||||
// Version string for archives
|
||||
rootProject.ext.versionStr = rootProject.mod_version + "-" + rootProject.minecraft_version
|
||||
rootProject.allprojects {
|
||||
version = (it == rootProject ? "" : it.name + "-") + rootProject.versionStr
|
||||
group = rootProject.maven_group
|
||||
|
||||
// Custom javadoc tags for all subprojects
|
||||
plugins.withType(JavaPlugin) {
|
||||
javadoc {
|
||||
options.tags(
|
||||
'todo:X"',
|
||||
'apiNote:a:API Note:',
|
||||
'implSpec:a:Implementation Requirements:',
|
||||
'implNote:a:Implementation Note:'
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create build.properties with preprocessor definitions
|
||||
def writePreprocessorDefinitions() {
|
||||
StringBuilder sb = new StringBuilder()
|
||||
sb.append("# DON'T TOUCH THIS FILE, This is handled by the build script\n")
|
||||
|
||||
gradle.ext.mcVers.eachWithIndex { ver, idx ->
|
||||
sb.append("MC_${ver.replace('.', '_')}=${idx}\n")
|
||||
if (gradle.ext.mcIndex == idx)
|
||||
sb.append("MC_VER=${idx}\n")
|
||||
}
|
||||
|
||||
if (rootProject.mod_version.toLowerCase().contains("dev")) {
|
||||
sb.append("DEV_BUILD=\n")
|
||||
}
|
||||
|
||||
new File(rootDir, "build.properties").text = sb.toString()
|
||||
}
|
||||
writePreprocessorDefinitions()
|
||||
|
||||
// Wire JVMDowngrader to process remapped jars
|
||||
gradle.projectsEvaluated {
|
||||
rootProject.subprojects.each {
|
||||
if (it.tasks.findByName('remapJar') == null) return
|
||||
it.tasks.downgradeJar.inputFile = it.tasks.remapJar.archiveFile
|
||||
it.tasks.jar.finalizedBy(it.tasks.remapJar)
|
||||
it.tasks.remapJar.finalizedBy(it.tasks.shadeDowngradedApi)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
plugins {
|
||||
id 'dh-loader'
|
||||
}
|
||||
|
||||
unimined.minecraft {
|
||||
fabric {
|
||||
loader gradle.ext.fabric_loader_version
|
||||
accessWidener project(":common").file("src/main/resources/${gradle.ext.accessWidenerVersion}.distanthorizons.accesswidener")
|
||||
}
|
||||
}
|
||||
|
||||
runClient.javaLauncher = null
|
||||
runServer.javaLauncher = null
|
||||
@@ -0,0 +1,17 @@
|
||||
plugins {
|
||||
id 'dh-loader'
|
||||
}
|
||||
|
||||
def awFile = project(":common").file("src/main/resources/${gradle.ext.accessWidenerVersion}.distanthorizons.accesswidener")
|
||||
|
||||
unimined.minecraft {
|
||||
forge {
|
||||
loader gradle.ext.forge_version
|
||||
useToolchains = false
|
||||
mixinConfig("DistantHorizons.forge.mixins.json")
|
||||
accessTransformer aw2at(awFile)
|
||||
}
|
||||
}
|
||||
|
||||
runClient.javaLauncher = null
|
||||
runServer.javaLauncher = null
|
||||
@@ -0,0 +1,16 @@
|
||||
plugins {
|
||||
id 'dh-loader'
|
||||
}
|
||||
|
||||
def awFile = project(":common").file("src/main/resources/${gradle.ext.accessWidenerVersion}.distanthorizons.accesswidener")
|
||||
|
||||
unimined.minecraft {
|
||||
neoForged {
|
||||
loader gradle.ext.neoforge_version
|
||||
useToolchains = false
|
||||
accessTransformer aw2at(awFile)
|
||||
}
|
||||
}
|
||||
|
||||
runClient.javaLauncher = null
|
||||
runServer.javaLauncher = null
|
||||
@@ -0,0 +1,41 @@
|
||||
@echo off & setlocal enabledelayedexpansion
|
||||
|
||||
set "VERSION=%~1"
|
||||
set "ROOT=%~2"
|
||||
set "WORK_DIR=%~3"
|
||||
set "WORKER=%WORK_DIR%\%VERSION%"
|
||||
set "JAR_OUTPUT_DIR=%~4"
|
||||
|
||||
REM remove the ending "\" from the root folder, otherwise the final quote
|
||||
REM in the robocopy command will be escaped and it won't run
|
||||
if "%ROOT:~-1%"=="\" set "ROOT=%ROOT:~0,-1%"
|
||||
set "WORKER=%~3\%~1"
|
||||
|
||||
set "BUILT_JAR_DIR=%WORKER%\build\forgix"
|
||||
|
||||
|
||||
|
||||
echo ==================== [%VERSION%] Copying workspace ====================
|
||||
mkdir "%WORKER%"
|
||||
robocopy "%ROOT%" "%WORKER%" /E /XD "%WORKER%" "_buildWorkers" "buildAllJars" ".gradle" "build" ".git" ".idea" ".gitlab" "run" "testScripts" /NFL /NDL
|
||||
|
||||
echo ==================== [%VERSION%] Cleaning ====================
|
||||
cd /d "%WORKER%"
|
||||
call .\gradlew.bat clean
|
||||
REM optional arg that can be added if we want to log the result to a file
|
||||
REM >"%WORK_DIR%\build_%VERSION%.log" 2>&1
|
||||
|
||||
echo ==================== [%VERSION%] Assembling ====================
|
||||
call .\gradlew.bat assemble -PmcVer="%VERSION%"
|
||||
REM optional arg that can be added if we want to log the result to a file
|
||||
REM >>"%WORK_DIR%\build_%VERSION%.log" 2>&1
|
||||
|
||||
echo ==================== [%VERSION%] Exporting ====================
|
||||
mkdir "%JAR_OUTPUT_DIR%"
|
||||
robocopy "%BUILT_JAR_DIR%" "%JAR_OUTPUT_DIR%" /NFL /NDL
|
||||
|
||||
echo ==================== [%VERSION%] Done ====================
|
||||
endlocal
|
||||
|
||||
REM can be uncommented for debugging
|
||||
REM pause
|
||||
+1
-39
@@ -1,41 +1,3 @@
|
||||
|
||||
// temporary fix for broken spongepowered version
|
||||
buildscript {
|
||||
configurations.configureEach {
|
||||
resolutionStrategy {
|
||||
force 'org.spongepowered:vanillagradle:0.2.1-20240507.024226-82'
|
||||
// newer versions can be found by going to the link:
|
||||
// https://repo.spongepowered.org/#browse/browse:maven-public:org%2Fspongepowered%2Fvanillagradle%2F0.2.1-SNAPSHOT
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id "org.spongepowered.gradle.vanilla" version "0.2.1-SNAPSHOT"
|
||||
id 'dh-loader'
|
||||
}
|
||||
|
||||
minecraft {
|
||||
accessWideners(project(":common").file("src/main/resources/${accessWidenerVersion}.distanthorizons.accesswidener"))
|
||||
version(rootProject.minecraft_version)
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// So mixins can be written in common
|
||||
compileOnly group:'org.spongepowered', name:'mixin', version:'0.8.5'
|
||||
}
|
||||
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
mavenCommon(MavenPublication) {
|
||||
artifactId = rootProject.mod_readable_name
|
||||
from components.java
|
||||
}
|
||||
}
|
||||
|
||||
// See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing.
|
||||
repositories {
|
||||
// Add repositories to publish to here.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+106
-8
@@ -1,14 +1,15 @@
|
||||
package com.seibel.distanthorizons.common;
|
||||
|
||||
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.DhApiBeforeDhInitEvent;
|
||||
import com.seibel.distanthorizons.common.commands.CommandInitializer;
|
||||
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.core.Initializer;
|
||||
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
||||
import com.seibel.distanthorizons.core.api.internal.SharedApi;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.config.ConfigHandler;
|
||||
import com.seibel.distanthorizons.core.config.eventHandlers.presets.ThreadPresetConfigEventHandler;
|
||||
@@ -18,6 +19,13 @@ import com.seibel.distanthorizons.core.enums.MinecraftTextFormat;
|
||||
import com.seibel.distanthorizons.core.jar.ModJarInfo;
|
||||
import com.seibel.distanthorizons.core.jar.updater.SelfUpdater;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.render.renderer.AbstractDebugWireframeRenderer;
|
||||
import com.seibel.distanthorizons.core.render.renderer.StubDebugWireframeRenderer;
|
||||
import com.seibel.distanthorizons.common.wrappers.gui.NativeDialogUtil;
|
||||
import com.seibel.distanthorizons.core.util.ThreadUtil;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IIrisAccessor;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModAccessor;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker;
|
||||
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
|
||||
@@ -27,6 +35,7 @@ import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.dedicated.DedicatedServer;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@@ -45,6 +54,7 @@ public abstract class AbstractModInitializer
|
||||
//==================//
|
||||
// abstract methods //
|
||||
//==================//
|
||||
//region
|
||||
|
||||
protected abstract void createInitialSharedBindings();
|
||||
protected abstract void createInitialClientBindings();
|
||||
@@ -58,11 +68,14 @@ public abstract class AbstractModInitializer
|
||||
protected abstract void subscribeServerStartingEvent(Consumer<MinecraftServer> eventHandler);
|
||||
protected abstract void runDelayedSetup();
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//===================//
|
||||
// initialize events //
|
||||
//===================//
|
||||
//region
|
||||
|
||||
public void onInitializeClient()
|
||||
{
|
||||
@@ -82,7 +95,8 @@ public abstract class AbstractModInitializer
|
||||
|
||||
// Client uses config for auto-updater, so it's initialized here instead of post-init stage
|
||||
this.initConfig();
|
||||
logModIncompatibilityWarnings(); // needs to be called after config loading
|
||||
logIncompatibilityWarnings(); // needs to be called after config loading
|
||||
Initializer.postConfigInit();
|
||||
|
||||
LOGGER.info(ModInfo.READABLE_NAME + " client Initialized.");
|
||||
|
||||
@@ -93,6 +107,7 @@ public abstract class AbstractModInitializer
|
||||
#endif
|
||||
|
||||
this.subscribeClientStartedEvent(this::postInit);
|
||||
this.subscribeClientStartedEvent(this::postClientInit);
|
||||
}
|
||||
|
||||
public void onInitializeServer()
|
||||
@@ -123,7 +138,9 @@ public abstract class AbstractModInitializer
|
||||
MinecraftServerWrapper.INSTANCE.dedicatedServer = (DedicatedServer)server;
|
||||
|
||||
this.initConfig();
|
||||
Initializer.postConfigInit();
|
||||
this.postInit();
|
||||
this.postServerInit();
|
||||
this.commandInitializer.onServerReady();
|
||||
|
||||
this.checkForUpdates();
|
||||
@@ -132,16 +149,19 @@ public abstract class AbstractModInitializer
|
||||
});
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//===========================//
|
||||
// inner initializer methods //
|
||||
//===========================//
|
||||
//region
|
||||
|
||||
private void startup()
|
||||
{
|
||||
DependencySetup.createSharedBindings();
|
||||
SharedApi.init();
|
||||
Initializer.preConfigInit();
|
||||
this.createInitialSharedBindings();
|
||||
}
|
||||
|
||||
@@ -209,11 +229,44 @@ public abstract class AbstractModInitializer
|
||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiAfterDhInitEvent.class, null);
|
||||
}
|
||||
|
||||
private void postClientInit()
|
||||
{
|
||||
CompletableFuture<Void> future = new CompletableFuture<>();
|
||||
|
||||
// This method may be called from either the render thread,
|
||||
// or some other random setup thread depending on the mod loader.
|
||||
// In order to avoid confusion/inconsistent problems, we're always going
|
||||
// to run setup on our own thread.
|
||||
Thread dhSetupThread = new Thread(() ->
|
||||
{
|
||||
try
|
||||
{
|
||||
DependencySetup.setRenderingApiBindings();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
future.completeExceptionally(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
future.complete(null);
|
||||
}
|
||||
});
|
||||
dhSetupThread.setName(ThreadUtil.THREAD_NAME_PREFIX + "PostClientInit Thread");
|
||||
dhSetupThread.start();
|
||||
|
||||
future.join();
|
||||
}
|
||||
private void postServerInit() { SingletonInjector.INSTANCE.bind(AbstractDebugWireframeRenderer.class, new StubDebugWireframeRenderer()); }
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
//==================================//
|
||||
// mod partial compatibility checks //
|
||||
//==================================//
|
||||
|
||||
//======================//
|
||||
// compatibility checks //
|
||||
//======================//
|
||||
//region
|
||||
|
||||
/**
|
||||
* Some mods will work with a few tweaks
|
||||
@@ -221,7 +274,7 @@ public abstract class AbstractModInitializer
|
||||
* This method will log (and display to chat if enabled)
|
||||
* these warnings and potential fixes.
|
||||
*/
|
||||
private static void logModIncompatibilityWarnings()
|
||||
private static void logIncompatibilityWarnings()
|
||||
{
|
||||
boolean showChatWarnings = Config.Common.Logging.Warning.showModCompatibilityWarningsOnStartup.get();
|
||||
IModChecker modChecker = SingletonInjector.INSTANCE.get(IModChecker.class);
|
||||
@@ -231,6 +284,7 @@ public abstract class AbstractModInitializer
|
||||
|
||||
|
||||
// Alex's caves
|
||||
//region
|
||||
if (modChecker.isModLoaded("alexscaves"))
|
||||
{
|
||||
// There've been a few reports about this mod breaking DH at a few different points in time
|
||||
@@ -247,8 +301,10 @@ public abstract class AbstractModInitializer
|
||||
|
||||
LOGGER.warn(startingString + "[Alex's Caves] may require some config changes in order to render Distant Horizons correctly.");
|
||||
}
|
||||
//endregion
|
||||
|
||||
// William Wythers' Overhauled Overworld (WWOO)
|
||||
//region
|
||||
if (modChecker.isModLoaded("wwoo"))
|
||||
{
|
||||
// WWOO has a bug with it's world gen that can't be fixed by DH or WWOO
|
||||
@@ -269,8 +325,11 @@ public abstract class AbstractModInitializer
|
||||
|
||||
LOGGER.warn(startingString + "[WWOO] "+ wwooWarning);
|
||||
}
|
||||
//endregion
|
||||
|
||||
// Chunky //
|
||||
//region
|
||||
|
||||
// Chunky
|
||||
boolean chunkyPresent = false;
|
||||
try
|
||||
{
|
||||
@@ -300,17 +359,56 @@ public abstract class AbstractModInitializer
|
||||
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 native OpenGL
|
||||
if (renderApi != EDhApiRenderApi.OPEN_GL)
|
||||
{
|
||||
String irisUnsupportedMessage = "Iris doesn't support DH when using the ["+EDhApiRenderApi.BLAZE_3D+"] rendering API, this will need to be fixed on Iris end. As a temporary fix please change the rendering API to ["+EDhApiRenderApi.OPEN_GL+"] in the DH config file.";
|
||||
LOGGER.fatal(irisUnsupportedMessage);
|
||||
NativeDialogUtil.showDialog(ModInfo.READABLE_NAME, irisUnsupportedMessage, "ok", "error");
|
||||
|
||||
IMinecraftClientWrapper mc = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
|
||||
String errorMessage = "loading Distant Horizons. "+irisUnsupportedMessage;
|
||||
String exceptionError = "Distant Horizons conditional mod config Exception";
|
||||
mc.crashMinecraft(errorMessage, new Exception(exceptionError));
|
||||
}
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// helper classes //
|
||||
//================//
|
||||
//region
|
||||
|
||||
public interface IEventProxy
|
||||
{
|
||||
void registerEvents();
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -4,14 +4,17 @@ import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
|
||||
import com.seibel.distanthorizons.core.api.internal.SharedApi;
|
||||
import com.seibel.distanthorizons.core.generation.PregenManager;
|
||||
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos2D;
|
||||
import com.seibel.distanthorizons.core.world.DhServerWorld;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.arguments.DimensionArgument;
|
||||
import net.minecraft.commands.arguments.coordinates.ColumnPosArgument;
|
||||
import net.minecraft.server.level.ColumnPos;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@@ -22,7 +25,11 @@ import static net.minecraft.commands.Commands.literal;
|
||||
|
||||
public class PregenCommand extends AbstractCommand
|
||||
{
|
||||
private final PregenManager pregenManager = new PregenManager();
|
||||
private PregenManager getPregenManager()
|
||||
{
|
||||
DhServerWorld world = (DhServerWorld) Objects.requireNonNull(SharedApi.getAbstractDhWorld());
|
||||
return world.getPregenManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LiteralArgumentBuilder<CommandSourceStack> buildCommand()
|
||||
@@ -48,7 +55,7 @@ public class PregenCommand extends AbstractCommand
|
||||
|
||||
private int pregenStatus(CommandContext<CommandSourceStack> c)
|
||||
{
|
||||
String statusString = this.pregenManager.getStatusString();
|
||||
String statusString = this.getPregenManager().getStatusString();
|
||||
//noinspection ReplaceNullCheck
|
||||
if (statusString != null)
|
||||
{
|
||||
@@ -68,7 +75,7 @@ public class PregenCommand extends AbstractCommand
|
||||
ColumnPos origin = ColumnPosArgument.getColumnPos(c, "origin");
|
||||
int chunkRadius = getInteger(c, "chunkRadius");
|
||||
|
||||
CompletableFuture<Void> future = this.pregenManager.startPregen(
|
||||
CompletableFuture<Void> future = this.getPregenManager().startPregen(
|
||||
ServerLevelWrapper.getWrapper(level),
|
||||
new DhBlockPos2D(#if MC_VER >= MC_1_19_2 origin.x(), origin.z() #else origin.x, origin.z #endif),
|
||||
chunkRadius
|
||||
@@ -94,7 +101,7 @@ public class PregenCommand extends AbstractCommand
|
||||
|
||||
private int pregenStop(CommandContext<CommandSourceStack> c)
|
||||
{
|
||||
CompletableFuture<Void> runningPregen = this.pregenManager.getRunningPregen();
|
||||
CompletableFuture<Void> runningPregen = this.getPregenManager().getRunningPregen();
|
||||
if (runningPregen == null)
|
||||
{
|
||||
return this.sendFailureResponse(c, "Pregen is not running");
|
||||
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
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
|
||||
{
|
||||
UpdateModScreen updateScreen = new UpdateModScreen(
|
||||
new TitleScreen(false),
|
||||
versionId
|
||||
);
|
||||
|
||||
#if MC_VER <= MC_26_1_2
|
||||
MC.setScreen(updateScreen);
|
||||
#else
|
||||
MC.setScreenAndShow(updateScreen);
|
||||
#endif
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// info instead of error since this can be ignored and probably just means
|
||||
// there isn't a new DH version available
|
||||
LOGGER.info("Unable to show DH update screen, reason: ["+e.getMessage()+"].");
|
||||
}
|
||||
};
|
||||
runnable.run();
|
||||
}
|
||||
|
||||
}
|
||||
+21
-10
@@ -4,8 +4,11 @@ import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
|
||||
import com.seibel.distanthorizons.core.api.internal.ServerApi;
|
||||
import com.seibel.distanthorizons.core.api.internal.SharedApi;
|
||||
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
import net.minecraft.world.level.chunk.ProtoChunk;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
public class MixinChunkMapCommon
|
||||
@@ -13,8 +16,20 @@ public class MixinChunkMapCommon
|
||||
|
||||
public static void onChunkSave(ServerLevel level, ChunkAccess chunk, CallbackInfoReturnable<Boolean> ci)
|
||||
{
|
||||
IServerLevelWrapper levelWrapper = ServerLevelWrapper.getWrapper(level);
|
||||
|
||||
int chunkPosX;
|
||||
int chunkPosZ;
|
||||
#if MC_VER <= MC_1_21_11
|
||||
chunkPosX = chunk.getPos().x;
|
||||
chunkPosZ = chunk.getPos().z;
|
||||
#else
|
||||
chunkPosX = chunk.getPos().x();
|
||||
chunkPosZ = chunk.getPos().z();
|
||||
#endif
|
||||
|
||||
// is this position already being updated?
|
||||
if (SharedApi.isChunkAtChunkPosAlreadyUpdating(chunk.getPos().x, chunk.getPos().z))
|
||||
if (SharedApi.isChunkAtChunkPosAlreadyUpdating(levelWrapper, chunkPosX, chunkPosZ))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -29,23 +44,19 @@ public class MixinChunkMapCommon
|
||||
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 //
|
||||
|
||||
// MC has a tendency to try saving incomplete or corrupted chunks (which show up as empty or black chunks)
|
||||
// this logic should prevent that from happening
|
||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
||||
#if MC_VER <= MC_1_17_1
|
||||
if (chunk.isUnsaved() || chunk.getUpgradeData() != null || !chunk.isLightCorrect())
|
||||
{
|
||||
return;
|
||||
}
|
||||
#else
|
||||
if (chunk.isUnsaved() || chunk.isUpgrading() || !chunk.isLightCorrect())
|
||||
if (chunk.isUnsaved() || chunk.isUpgrading() || !chunk.isLightCorrect() || chunk instanceof ProtoChunk)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -56,7 +67,7 @@ public class MixinChunkMapCommon
|
||||
// biome validation //
|
||||
|
||||
// some chunks may be missing their biomes, which cause issues when attempting to save them
|
||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
||||
#if MC_VER <= MC_1_17_1
|
||||
if (chunk.getBiomes() == null)
|
||||
{
|
||||
return;
|
||||
@@ -77,8 +88,8 @@ public class MixinChunkMapCommon
|
||||
|
||||
// submit the update event
|
||||
ServerApi.INSTANCE.serverChunkSaveEvent(
|
||||
new ChunkWrapper(chunk, ServerLevelWrapper.getWrapper(level)),
|
||||
ServerLevelWrapper.getWrapper(level)
|
||||
new ChunkWrapper(chunk, levelWrapper),
|
||||
levelWrapper
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
package com.seibel.distanthorizons.common.commonMixins;
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftClientWrapper;
|
||||
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.world.effect.MobEffects;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
|
||||
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.world.effect.MobEffects;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
|
||||
#if MC_VER < MC_1_17_1
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
import net.minecraft.client.renderer.FogRenderer;
|
||||
import net.minecraft.client.renderer.FogRenderer.FogMode;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
#elif MC_VER < MC_1_21_3
|
||||
import net.minecraft.world.level.material.FogType;
|
||||
import net.minecraft.client.renderer.FogRenderer;
|
||||
import net.minecraft.client.renderer.FogRenderer.FogMode;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
#elif MC_VER < MC_1_21_6
|
||||
import net.minecraft.world.level.material.FogType;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
import com.mojang.blaze3d.shaders.FogShape;
|
||||
import net.minecraft.client.renderer.FogRenderer;
|
||||
import net.minecraft.client.renderer.FogRenderer.FogMode;
|
||||
import net.minecraft.client.renderer.FogParameters;
|
||||
import org.joml.Vector4f;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
#else
|
||||
import net.minecraft.world.level.material.FogType;
|
||||
#endif
|
||||
|
||||
|
||||
public class MixinVanillaFogCommon
|
||||
{
|
||||
|
||||
|
||||
#if MC_VER < MC_1_21_6
|
||||
public static boolean cancelFog(Camera camera, FogRenderer.FogMode fogMode)
|
||||
#else
|
||||
public static boolean cancelFog()
|
||||
#endif
|
||||
{
|
||||
|
||||
|
||||
#if MC_VER < MC_1_21_6
|
||||
Entity entity = camera.getEntity();
|
||||
#elif MC_VER <= MC_1_21_10
|
||||
Camera camera = Minecraft.getInstance().gameRenderer.getMainCamera();
|
||||
Entity entity = camera.getEntity();
|
||||
#elif MC_VER <= MC_26_1_2
|
||||
Camera camera = Minecraft.getInstance().gameRenderer.getMainCamera();
|
||||
Entity entity = camera.entity();
|
||||
#else
|
||||
Camera camera = Minecraft.getInstance().gameRenderer.mainCamera();
|
||||
Entity entity = camera.entity();
|
||||
#endif
|
||||
|
||||
|
||||
boolean cameraNotInFluid = cameraNotInFluid(camera);
|
||||
boolean isSpecialFog = (entity instanceof LivingEntity) && ((LivingEntity) entity).hasEffect(MobEffects.BLINDNESS);
|
||||
|
||||
boolean cancelFog = !isSpecialFog;
|
||||
cancelFog = cancelFog && cameraNotInFluid;
|
||||
#if MC_VER < MC_1_21_6
|
||||
cancelFog = cancelFog && (fogMode == FogRenderer.FogMode.FOG_TERRAIN);
|
||||
#endif
|
||||
|
||||
cancelFog = cancelFog && !SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class).isFogStateSpecial();
|
||||
cancelFog = cancelFog && !Config.Client.Advanced.Graphics.Fog.enableVanillaFog.get();
|
||||
|
||||
|
||||
return cancelFog;
|
||||
}
|
||||
|
||||
private static boolean cameraNotInFluid(Camera camera)
|
||||
{
|
||||
#if MC_VER < MC_1_17_1
|
||||
FluidState fluidState = camera.getFluidInCamera();
|
||||
boolean cameraNotInFluid = fluidState.isEmpty();
|
||||
#else
|
||||
FogType fogTypes = camera.getFluidInCamera();
|
||||
boolean cameraNotInFluid = fogTypes == FogType.NONE;
|
||||
#endif
|
||||
|
||||
return cameraNotInFluid;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+331
@@ -0,0 +1,331 @@
|
||||
/*
|
||||
* 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.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.common.render.blaze.wrappers.RenderPipelineBuilderWrapper;
|
||||
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()
|
||||
{
|
||||
RenderPipelineBuilderWrapper pipelineBuilder = new RenderPipelineBuilderWrapper();
|
||||
{
|
||||
pipelineBuilder.withFaceCulling(false);
|
||||
pipelineBuilder.withDepthWrite(true);
|
||||
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.LESS);
|
||||
pipelineBuilder.withColorWrite(true);
|
||||
pipelineBuilder.withoutBlend();
|
||||
pipelineBuilder.withPolygonMode(RenderPipelineBuilderWrapper.EDhPolygonMode.WIREFRAME);
|
||||
pipelineBuilder.withName("debug_wireframe_renderer");
|
||||
|
||||
pipelineBuilder.withVertexShader("debug/blaze/vert");
|
||||
pipelineBuilder.withFragmentShader("debug/blaze/frag");
|
||||
|
||||
pipelineBuilder.withUniformBuffer("uniformBlock");
|
||||
|
||||
|
||||
VertexFormat vertexFormat = VertexFormat.builder()
|
||||
.add("vPosition", BlazeDhVertexFormatUtil.FLOAT_XYZ_POS)
|
||||
.build();
|
||||
pipelineBuilder.withVertexFormat(vertexFormat);
|
||||
pipelineBuilder.withVertexMode(RenderPipelineBuilderWrapper.EDhVertexMode.LINES);
|
||||
}
|
||||
this.pipeline = pipelineBuilder.build();
|
||||
|
||||
}
|
||||
private void createBuffers()
|
||||
{
|
||||
GpuDevice GPU_DEVICE = RenderSystem.getDevice();
|
||||
CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
|
||||
|
||||
|
||||
// box vertices
|
||||
ByteBuffer boxVerticesBuffer = MemoryUtil.memAlloc(BOX_VERTICES.length * Float.BYTES);
|
||||
boxVerticesBuffer.asFloatBuffer().put(BOX_VERTICES);
|
||||
boxVerticesBuffer.rewind();
|
||||
MemoryUtil.memFree(boxVerticesBuffer);
|
||||
|
||||
// upload vertex data
|
||||
{
|
||||
int usage = GpuBuffer.USAGE_COPY_DST
|
||||
| GpuBuffer.USAGE_VERTEX;
|
||||
int size = BOX_VERTICES.length * Float.BYTES;
|
||||
this.boxVertexBuffer = GPU_DEVICE.createBuffer(() -> "distantHorizons: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 renderBox(Box box)
|
||||
{
|
||||
this.init();
|
||||
|
||||
//if (BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.isEmpty()
|
||||
// || BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.isEmpty())
|
||||
//{
|
||||
// return;
|
||||
//}
|
||||
|
||||
// shouldn't happen, but just in case
|
||||
if (box == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// delayed getters since this class may be initialized before
|
||||
// the GPU device has been set
|
||||
GpuDevice gpuDevice = RenderSystem.getDevice();
|
||||
CommandEncoder commandEncoder = gpuDevice.createCommandEncoder();
|
||||
|
||||
|
||||
|
||||
// uniforms
|
||||
{
|
||||
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
|
||||
+642
@@ -0,0 +1,642 @@
|
||||
/*
|
||||
* 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.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.RenderPipelineBuilderWrapper;
|
||||
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.RenderThreadTaskHandler;
|
||||
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 RenderPipeline pipeline;
|
||||
|
||||
private GpuBuffer vertUniformBuffer;
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
//region
|
||||
|
||||
public BlazeDhGenericObjectRenderer() { }
|
||||
|
||||
public void init()
|
||||
{
|
||||
if (this.init)
|
||||
{
|
||||
return;
|
||||
}
|
||||
this.init = true;
|
||||
|
||||
this.createPipelines();
|
||||
|
||||
if (RENDER_DEBUG_OBJECTS)
|
||||
{
|
||||
this.addGenericDebugObjects();
|
||||
}
|
||||
}
|
||||
private void createPipelines()
|
||||
{
|
||||
RenderPipelineBuilderWrapper pipelineBuilder = new RenderPipelineBuilderWrapper();
|
||||
{
|
||||
pipelineBuilder.withFaceCulling(true);
|
||||
pipelineBuilder.withDepthWrite(true);
|
||||
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.LESS);
|
||||
pipelineBuilder.withBlend(BlendFunction.TRANSLUCENT); // TRANSLUCENT = new BlendFunction(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ONE_MINUS_SRC_ALPHA);
|
||||
pipelineBuilder.withColorWrite(true);
|
||||
pipelineBuilder.withPolygonMode(RenderPipelineBuilderWrapper.EDhPolygonMode.FILL);
|
||||
pipelineBuilder.withName("generic_objects");
|
||||
|
||||
pipelineBuilder.withVertexShader("generic/blaze/vert");
|
||||
pipelineBuilder.withFragmentShader("generic/blaze/frag");
|
||||
|
||||
pipelineBuilder.withSampler("uLightMap");
|
||||
|
||||
pipelineBuilder.withUniformBuffer("vertUniformBlock");
|
||||
|
||||
VertexFormat vertexFormat = VertexFormat.builder()
|
||||
.add("vPosition", BlazeDhVertexFormatUtil.FLOAT_XYZ_POS)
|
||||
.add("aColor", BlazeDhVertexFormatUtil.RGBA_UBYTE_COLOR)
|
||||
.add("aMaterial", BlazeDhVertexFormatUtil.IRIS_MATERIAL)
|
||||
|
||||
.add("paddingOne", BlazeDhVertexFormatUtil.BYTE_PAD)
|
||||
.add("paddingTwo", BlazeDhVertexFormatUtil.BYTE_PAD)
|
||||
.add("paddingThree", BlazeDhVertexFormatUtil.BYTE_PAD)
|
||||
.build();
|
||||
pipelineBuilder.withVertexFormat(vertexFormat);
|
||||
pipelineBuilder.withVertexMode(RenderPipelineBuilderWrapper.EDhVertexMode.TRIANGLES);
|
||||
}
|
||||
this.pipeline = pipelineBuilder.build();
|
||||
}
|
||||
private void addGenericDebugObjects()
|
||||
{
|
||||
GenericRenderObjectFactory factory = GenericRenderObjectFactory.INSTANCE;
|
||||
|
||||
|
||||
// single giant box
|
||||
IDhApiRenderableBoxGroup singleGiantBoxGroup = factory.createForSingleBox(
|
||||
ModInfo.NAME + ":CyanChunkBox",
|
||||
new DhApiRenderableBox(
|
||||
new DhApiVec3d(0,0,0), new DhApiVec3d(16,190,16),
|
||||
new Color(Color.CYAN.getRed(), Color.CYAN.getGreen(), Color.CYAN.getBlue(), 125),
|
||||
EDhApiBlockMaterial.WATER)
|
||||
);
|
||||
singleGiantBoxGroup.setSkyLight(LodUtil.MAX_MC_LIGHT);
|
||||
singleGiantBoxGroup.setBlockLight(LodUtil.MAX_MC_LIGHT);
|
||||
this.add(singleGiantBoxGroup);
|
||||
|
||||
|
||||
// single slender box
|
||||
IDhApiRenderableBoxGroup singleTallBoxGroup = factory.createForSingleBox(
|
||||
ModInfo.NAME + ":GreenBeacon",
|
||||
new DhApiRenderableBox(
|
||||
new DhApiVec3d(16,0,31), new DhApiVec3d(17,2000,32),
|
||||
new Color(Color.GREEN.getRed(), Color.GREEN.getGreen(), Color.GREEN.getBlue(), 125),
|
||||
EDhApiBlockMaterial.ILLUMINATED)
|
||||
);
|
||||
singleTallBoxGroup.setSkyLight(LodUtil.MAX_MC_LIGHT);
|
||||
singleTallBoxGroup.setBlockLight(LodUtil.MAX_MC_LIGHT);
|
||||
this.add(singleTallBoxGroup);
|
||||
|
||||
|
||||
// absolute box group
|
||||
ArrayList<DhApiRenderableBox> absBoxList = new ArrayList<>();
|
||||
for (int i = 0; i < 18; i++)
|
||||
{
|
||||
absBoxList.add(new DhApiRenderableBox(
|
||||
new DhApiVec3d(i,150+i,24), new DhApiVec3d(1+i,151+i,25),
|
||||
new Color(Color.ORANGE.getRed(), Color.ORANGE.getGreen(), Color.ORANGE.getBlue()),
|
||||
EDhApiBlockMaterial.LAVA
|
||||
)
|
||||
);
|
||||
}
|
||||
IDhApiRenderableBoxGroup absolutePosBoxGroup = factory.createAbsolutePositionedGroup(ModInfo.NAME + ":OrangeStairs", absBoxList);
|
||||
this.add(absolutePosBoxGroup);
|
||||
|
||||
|
||||
// relative box group
|
||||
ArrayList<DhApiRenderableBox> relBoxList = new ArrayList<>();
|
||||
for (int i = 0; i < 8; i+=2)
|
||||
{
|
||||
relBoxList.add(new DhApiRenderableBox(
|
||||
new DhApiVec3d(0,i,0), new DhApiVec3d(1,1+i,1),
|
||||
new Color(Color.MAGENTA.getRed(), Color.MAGENTA.getGreen(), Color.MAGENTA.getBlue()),
|
||||
EDhApiBlockMaterial.METAL
|
||||
)
|
||||
);
|
||||
}
|
||||
IDhApiRenderableBoxGroup relativePosBoxGroup = factory.createRelativePositionedGroup(
|
||||
ModInfo.NAME + ":MovingMagentaGroup",
|
||||
new DhApiVec3d(24, 140, 24),
|
||||
relBoxList);
|
||||
relativePosBoxGroup.setPreRenderFunc((event) ->
|
||||
{
|
||||
DhApiVec3d pos = relativePosBoxGroup.getOriginBlockPos();
|
||||
pos.x += event.partialTicks / 2;
|
||||
pos.x %= 32;
|
||||
relativePosBoxGroup.setOriginBlockPos(pos);
|
||||
});
|
||||
this.add(relativePosBoxGroup);
|
||||
|
||||
|
||||
// massive relative box group
|
||||
ArrayList<DhApiRenderableBox> massRelBoxList = new ArrayList<>();
|
||||
for (int x = 0; x < 50*2; x+=2)
|
||||
{
|
||||
for (int z = 0; z < 50*2; z+=2)
|
||||
{
|
||||
massRelBoxList.add(new DhApiRenderableBox(
|
||||
new DhApiVec3d(-x, 0, -z), new DhApiVec3d(1-x, 1, 1-z),
|
||||
new Color(Color.RED.getRed(), Color.RED.getGreen(), Color.RED.getBlue()),
|
||||
EDhApiBlockMaterial.TERRACOTTA
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
IDhApiRenderableBoxGroup massRelativePosBoxGroup = factory.createRelativePositionedGroup(
|
||||
ModInfo.NAME + ":MassRedGroup",
|
||||
new DhApiVec3d(-25, 140, 0),
|
||||
massRelBoxList);
|
||||
massRelativePosBoxGroup.setPreRenderFunc((event) ->
|
||||
{
|
||||
DhApiVec3d blockPos = massRelativePosBoxGroup.getOriginBlockPos();
|
||||
blockPos.y += event.partialTicks / 4;
|
||||
if (blockPos.y > 150f)
|
||||
{
|
||||
blockPos.y = 140f;
|
||||
|
||||
Color newColor = (massRelativePosBoxGroup.get(0).color == Color.RED) ? Color.RED.darker() : Color.RED;
|
||||
massRelativePosBoxGroup.forEach((box) -> { box.color = newColor; });
|
||||
massRelativePosBoxGroup.triggerBoxChange();
|
||||
}
|
||||
|
||||
massRelativePosBoxGroup.setOriginBlockPos(blockPos);
|
||||
});
|
||||
this.add(massRelativePosBoxGroup);
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// registration //
|
||||
//==============//
|
||||
//region
|
||||
|
||||
@Override
|
||||
public void add(IDhApiRenderableBoxGroup iBoxGroup) throws IllegalArgumentException
|
||||
{
|
||||
if (!(iBoxGroup instanceof RenderableBoxGroup))
|
||||
{
|
||||
throw new IllegalArgumentException("Box group must be of type ["+ RenderableBoxGroup.class.getSimpleName()+"], type received: ["+(iBoxGroup != null ? iBoxGroup.getClass() : "NULL")+"].");
|
||||
}
|
||||
RenderableBoxGroup boxGroup = (RenderableBoxGroup) iBoxGroup;
|
||||
if (boxGroup.size() != 0)
|
||||
{
|
||||
// trigger a box change to make sure the initial data is uploaded
|
||||
boxGroup.triggerBoxChange();
|
||||
}
|
||||
|
||||
long id = boxGroup.getId();
|
||||
if (this.boxGroupById.containsKey(id))
|
||||
{
|
||||
throw new IllegalArgumentException("A box group with the ID [" + id + "] is already present.");
|
||||
}
|
||||
|
||||
this.boxGroupById.put(id, boxGroup);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IDhApiRenderableBoxGroup remove(long id) { return this.boxGroupById.remove(id); }
|
||||
|
||||
public void clear() { this.boxGroupById.clear(); }
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//===========//
|
||||
// rendering //
|
||||
//===========//
|
||||
//region
|
||||
|
||||
/**
|
||||
* @param renderingWithSsao
|
||||
* if true that means this render call is happening before the SSAO pass
|
||||
* and any objects rendered in this pass will have SSAO applied to them.
|
||||
*/
|
||||
@Override
|
||||
public void render(RenderParams renderEventParam, IProfilerWrapper profiler, boolean renderingWithSsao)
|
||||
{
|
||||
|
||||
try (IProfilerWrapper.IProfileBlock generic_profile = profiler.push("setup"))
|
||||
{
|
||||
|
||||
|
||||
//==============//
|
||||
// render setup //
|
||||
//==============//
|
||||
//#region
|
||||
|
||||
this.init();
|
||||
|
||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericRenderSetupEvent.class, renderEventParam);
|
||||
|
||||
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");
|
||||
try (IProfilerWrapper.IProfileBlock namespace_profile = profiler.push(boxGroup.getResourceLocationNamespace());
|
||||
IProfilerWrapper.IProfileBlock location_profile = profiler.push(boxGroup.getResourceLocationPath()))
|
||||
{
|
||||
this.renderBoxGroupInstanced(renderEventParam, boxGroup, profiler);
|
||||
}
|
||||
|
||||
boxGroup.postRender(renderEventParam);
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
|
||||
|
||||
//==========//
|
||||
// clean up //
|
||||
//==========//
|
||||
//region
|
||||
|
||||
profiler.popPush("cleanup");
|
||||
|
||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericRenderCleanupEvent.class, renderEventParam);
|
||||
|
||||
//endregion
|
||||
}
|
||||
}
|
||||
private String getRenderPassName() { return "distantHorizons:McGenericObjectRenderer"; }
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//=====================//
|
||||
// instanced rendering //
|
||||
//=====================//
|
||||
//region
|
||||
|
||||
private void renderBoxGroupInstanced(
|
||||
RenderParams renderEventParam,
|
||||
RenderableBoxGroup boxGroup,
|
||||
IProfilerWrapper profiler)
|
||||
{
|
||||
try (RenderPass renderPass = COMMAND_ENCODER.createRenderPass(
|
||||
this::getRenderPassName,
|
||||
BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.textureView,
|
||||
/*optionalClearColorAsInt*/ OptionalInt.empty(),
|
||||
BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureView,
|
||||
/*optionalDepthValueAsDouble*/ OptionalDouble.empty()))
|
||||
{
|
||||
|
||||
// update instance data //
|
||||
|
||||
BlazeGenericObjectVertexContainer container = (BlazeGenericObjectVertexContainer) boxGroup.vertexBufferContainer;
|
||||
|
||||
LightMapWrapper lightMapWrapper = (LightMapWrapper) renderEventParam.lightmap;
|
||||
BlazeTextureViewWrapper lightmapTextureViewWrapper = lightMapWrapper.getTextureViewWrapper();
|
||||
renderPass.bindTexture("uLightMap", lightmapTextureViewWrapper.textureView, lightmapTextureViewWrapper.textureSampler);
|
||||
|
||||
|
||||
|
||||
// Bind instance data //
|
||||
|
||||
|
||||
renderPass.setUniform("vertUniformBlock", this.vertUniformBuffer);
|
||||
|
||||
// set pipeline
|
||||
renderPass.setPipeline(this.pipeline);
|
||||
renderPass.setIndexBuffer(container.indexGpuBuffer, VertexFormat.IndexType.INT);
|
||||
|
||||
renderPass.setVertexBuffer(0, container.vboGpuBuffer);
|
||||
|
||||
// Draw instanced
|
||||
if (container.uploadedBoxCount > 0)
|
||||
{
|
||||
renderPass.drawIndexed(
|
||||
/*indexStart*/ 0,
|
||||
/*firstIndex*/0,
|
||||
/*indexCount*/container.uploadedBoxCount * 36, // 36 = 6 faces * 6 verticies per face
|
||||
/*instanceCount*/1);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//=========//
|
||||
// F3 menu //
|
||||
//=========//
|
||||
//region
|
||||
|
||||
public String getVboRenderDebugMenuString()
|
||||
{
|
||||
// get counts
|
||||
int totalGroupCount = this.boxGroupById.size();
|
||||
int totalBoxCount = 0;
|
||||
|
||||
int activeGroupCount = 0;
|
||||
int activeBoxCount = 0;
|
||||
|
||||
for (long key : this.boxGroupById.keySet())
|
||||
{
|
||||
RenderableBoxGroup renderGroup = this.boxGroupById.get(key);
|
||||
if (renderGroup.active)
|
||||
{
|
||||
activeGroupCount++;
|
||||
activeBoxCount += renderGroup.size();
|
||||
}
|
||||
totalBoxCount += renderGroup.size();
|
||||
}
|
||||
|
||||
|
||||
return "Generic Obj #: " + F3Screen.NUMBER_FORMAT.format(activeGroupCount) + "/" + F3Screen.NUMBER_FORMAT.format(totalGroupCount) + ", " +
|
||||
"Cube #: " + F3Screen.NUMBER_FORMAT.format(activeBoxCount) + "/" + F3Screen.NUMBER_FORMAT.format(totalBoxCount);
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// base overrides //
|
||||
//================//
|
||||
//region
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
// close is called outside the render thread and buffer closing must be done on the render thread
|
||||
RenderThreadTaskHandler.INSTANCE.queueRunningOnRenderThread("Generic Obj Cleanup", () ->
|
||||
{
|
||||
if (this.vertUniformBuffer != null)
|
||||
{
|
||||
this.vertUniformBuffer.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
}
|
||||
#endif
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
package com.seibel.distanthorizons.common.render.blaze;
|
||||
|
||||
#if MC_VER <= MC_1_21_10
|
||||
public class BlazeDhMetaRenderer {}
|
||||
|
||||
#else
|
||||
|
||||
import com.mojang.blaze3d.textures.GpuTexture;
|
||||
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiAfterColorDepthTextureCreatedEvent;
|
||||
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiTextureCreatedParam;
|
||||
import com.seibel.distanthorizons.common.render.blaze.apply.BlazeDhApplyRenderer;
|
||||
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.render.RenderParams;
|
||||
import com.seibel.distanthorizons.coreapi.util.ColorUtil;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhMetaRenderer;
|
||||
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
public class BlazeDhMetaRenderer implements IDhMetaRenderer
|
||||
{
|
||||
public static final BlazeDhMetaRenderer INSTANCE = new BlazeDhMetaRenderer();
|
||||
|
||||
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
|
||||
|
||||
|
||||
private BlazeDhApplyRenderer applyRenderer;
|
||||
|
||||
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)
|
||||
{
|
||||
int oldWidth = this.dhDepthTextureWrapper.getWidth();
|
||||
int oldHeight = this.dhDepthTextureWrapper.getHeight();
|
||||
|
||||
boolean texturesChanged = false;
|
||||
texturesChanged = this.dhDepthTextureWrapper.tryCreateOrResize() | texturesChanged;
|
||||
texturesChanged = this.dhColorTextureWrapper.tryCreateOrResize() | texturesChanged;
|
||||
|
||||
if (texturesChanged)
|
||||
{
|
||||
int newTextureWidth = MC_RENDER.getTargetFramebufferViewportWidth();
|
||||
int newTextureHeight = MC_RENDER.getTargetFramebufferViewportHeight();
|
||||
|
||||
DhApiTextureCreatedParam textureCreatedParam = new DhApiTextureCreatedParam(
|
||||
oldWidth, oldHeight,
|
||||
newTextureWidth, newTextureHeight
|
||||
);
|
||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiAfterColorDepthTextureCreatedEvent.class, textureCreatedParam);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runRenderPassCleanup(RenderParams renderParams) {}
|
||||
|
||||
@Override
|
||||
public void applyToMcTexture(RenderParams renderParams)
|
||||
{
|
||||
GpuTexture mcColorTexture = MinecraftRenderWrapper.INSTANCE.getRenderTarget().getColorTexture();
|
||||
this.applyRenderer.render(this.dhColorTextureWrapper.texture, this.dhDepthTextureWrapper.texture, mcColorTexture);
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// clear textures //
|
||||
//================//
|
||||
//region
|
||||
|
||||
@Override
|
||||
public void clearDhDepthAndColorTextures(RenderParams renderParams)
|
||||
{
|
||||
this.dhDepthTextureWrapper.clearDepth(1.0f);
|
||||
|
||||
Color color = MC_RENDER.getSkyColor();
|
||||
this.dhColorTextureWrapper.clearColor(ColorUtil.toColorInt(color));
|
||||
}
|
||||
|
||||
//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
|
||||
+366
@@ -0,0 +1,366 @@
|
||||
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.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.api.methods.events.abstractEvents.DhApiBeforeRenderPassEvent;
|
||||
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.RenderPipelineBuilderWrapper;
|
||||
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureViewWrapper;
|
||||
import com.seibel.distanthorizons.common.render.blaze.wrappers.uniform.BlazeLodUniformBufferWrapper;
|
||||
import com.seibel.distanthorizons.common.render.blaze.wrappers.buffer.BlazeVertexBufferWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.misc.LightMapWrapper;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodBufferContainer;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.pos.DhSectionPos;
|
||||
import com.seibel.distanthorizons.core.render.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.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 fragUniformBuffer;
|
||||
private GpuBuffer vertSharedUniformBuffer;
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
//region
|
||||
|
||||
private BlazeDhTerrainRenderer() { }
|
||||
|
||||
private void tryInit()
|
||||
{
|
||||
if (this.init)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
RenderPipelineBuilderWrapper pipelineBuilder = new RenderPipelineBuilderWrapper();
|
||||
{
|
||||
pipelineBuilder.withFaceCulling(true);
|
||||
pipelineBuilder.withDepthWrite(true);
|
||||
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.LESS);
|
||||
pipelineBuilder.withColorWrite(true);
|
||||
pipelineBuilder.withPolygonMode(RenderPipelineBuilderWrapper.EDhPolygonMode.FILL);
|
||||
pipelineBuilder.withName("terrain");
|
||||
|
||||
pipelineBuilder.withSampler("uLightMap");
|
||||
|
||||
pipelineBuilder.withVertexShader("lod/blaze/vert");
|
||||
pipelineBuilder.withFragmentShader("lod/blaze/frag");
|
||||
|
||||
pipelineBuilder.withUniformBuffer("vertUniqueUniformBlock");
|
||||
pipelineBuilder.withUniformBuffer("vertSharedUniformBlock");
|
||||
pipelineBuilder.withUniformBuffer("fragUniformBlock");
|
||||
|
||||
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();
|
||||
pipelineBuilder.withVertexFormat(vertexFormat);
|
||||
|
||||
pipelineBuilder.withVertexMode(RenderPipelineBuilderWrapper.EDhVertexMode.TRIANGLES);
|
||||
}
|
||||
|
||||
// opaque
|
||||
{
|
||||
pipelineBuilder.withoutBlend();
|
||||
this.opaquePipeline = pipelineBuilder.build();
|
||||
}
|
||||
|
||||
// transparent
|
||||
{
|
||||
// TRANSLUCENT = new BlendFunction(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ONE_MINUS_SRC_ALPHA);
|
||||
pipelineBuilder.withBlend(BlendFunction.TRANSLUCENT);
|
||||
this.transparentPipeline = pipelineBuilder.build();
|
||||
}
|
||||
|
||||
this.init = true;
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//========//
|
||||
// render //
|
||||
//========//
|
||||
//region
|
||||
|
||||
@Override
|
||||
public void render(
|
||||
RenderParams renderEventParam,
|
||||
boolean opaquePass,
|
||||
SortedArraySet<LodBufferContainer> bufferContainers,
|
||||
IProfilerWrapper profiler)
|
||||
{
|
||||
this.tryInit();
|
||||
|
||||
try(IProfilerWrapper.IProfileBlock terrain_profile = profiler.push("terrain render"))
|
||||
{
|
||||
profiler.popPush("vert unique uniforms");
|
||||
{
|
||||
// create data //
|
||||
|
||||
for (int lodIndex = 0; lodIndex < bufferContainers.size(); lodIndex++)
|
||||
{
|
||||
LodBufferContainer bufferContainer = bufferContainers.get(lodIndex);
|
||||
bufferContainer.uniformContainer.tryUpload();
|
||||
}
|
||||
}
|
||||
|
||||
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 = MemoryUtil.memAlloc(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);
|
||||
|
||||
MemoryUtil.memFree(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 = MemoryUtil.memAlloc(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);
|
||||
MemoryUtil.memFree(buffer);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// render pass setup
|
||||
{
|
||||
profiler.popPush("rendering");
|
||||
|
||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeRenderPassEvent.class, renderEventParam);
|
||||
|
||||
// create a render pass
|
||||
try (RenderPass renderPass = COMMAND_ENCODER.createRenderPass(
|
||||
this::getRenderPassName,
|
||||
BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.textureView,
|
||||
/*optionalClearColorAsInt*/ OptionalInt.empty(),
|
||||
BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.textureView,
|
||||
/*optionalDepthValueAsDouble*/ OptionalDouble.empty())
|
||||
)
|
||||
{
|
||||
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);
|
||||
|
||||
// shared uniforms
|
||||
renderPass.setUniform("fragUniformBlock", this.fragUniformBuffer);
|
||||
renderPass.setUniform("vertSharedUniformBlock", this.vertSharedUniformBuffer);
|
||||
|
||||
|
||||
|
||||
for (int lodIndex = 0; lodIndex < bufferContainers.size(); lodIndex++)
|
||||
{
|
||||
LodBufferContainer bufferContainer = bufferContainers.get(lodIndex);
|
||||
BlazeLodUniformBufferWrapper uniformWrapper = (BlazeLodUniformBufferWrapper) bufferContainer.uniformContainer;
|
||||
|
||||
boolean columnBuilderDebugEnabled = Config.Client.Advanced.Debugging.ColumnBuilderDebugging.columnBuilderDebugEnable.get();
|
||||
if (columnBuilderDebugEnabled)
|
||||
{
|
||||
if (DhSectionPos.getDetailLevel(bufferContainer.pos) == Config.Client.Advanced.Debugging.ColumnBuilderDebugging.columnBuilderDebugDetailLevel.get()
|
||||
&& DhSectionPos.getX(bufferContainer.pos) == Config.Client.Advanced.Debugging.ColumnBuilderDebugging.columnBuilderDebugXPos.get()
|
||||
&& DhSectionPos.getZ(bufferContainer.pos) == Config.Client.Advanced.Debugging.ColumnBuilderDebugging.columnBuilderDebugZPos.get())
|
||||
{
|
||||
int breakpoint = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
renderPass.setUniform("vertUniqueUniformBlock", uniformWrapper.gpuBuffer);
|
||||
|
||||
|
||||
|
||||
// render each buffer
|
||||
IVertexBufferWrapper[] bufferWrapperList = opaquePass ? bufferContainer.vboOpaqueWrappers : bufferContainer.vboTransparentWrappers;
|
||||
for (int i = 0; i < bufferWrapperList.length; i++)
|
||||
{
|
||||
BlazeVertexBufferWrapper bufferWrapper = (BlazeVertexBufferWrapper) bufferWrapperList[i];
|
||||
if (!bufferWrapper.uploaded
|
||||
|| bufferWrapper.vertexCount == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// fire render event
|
||||
{
|
||||
Vec3d camPos = renderEventParam.exactCameraPosition;
|
||||
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.setIndexBuffer(bufferWrapper.getIndexGpuBuffer(), VertexFormat.IndexType.INT);
|
||||
renderPass.setVertexBuffer(0, bufferWrapper.vertexGpuBuffer); // vertex buffer can only be "0" lol
|
||||
|
||||
if (!bufferWrapper.vertexGpuBuffer.isClosed())
|
||||
{
|
||||
renderPass.drawIndexed(
|
||||
/*indexStart*/ 0,
|
||||
/*firstIndex*/0,
|
||||
/*indexCount*/bufferWrapper.indexCount,
|
||||
/*instanceCount*/1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private String getIndexBufferName() { return "distantHorizons:LodIndexBuffer"; }
|
||||
private String getRenderPassName() { return "distantHorizons:McLodRenderer"; }
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
}
|
||||
#endif
|
||||
+270
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.common.render.blaze.apply;
|
||||
|
||||
#if MC_VER <= MC_1_21_10
|
||||
public class BlazeDhApplyRenderer {}
|
||||
|
||||
#else
|
||||
|
||||
import com.mojang.blaze3d.buffers.GpuBuffer;
|
||||
import com.mojang.blaze3d.pipeline.BlendFunction;
|
||||
import com.mojang.blaze3d.pipeline.RenderPipeline;
|
||||
import com.mojang.blaze3d.systems.CommandEncoder;
|
||||
import com.mojang.blaze3d.systems.GpuDevice;
|
||||
import com.mojang.blaze3d.systems.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.RenderPipelineBuilderWrapper;
|
||||
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureViewWrapper;
|
||||
import com.seibel.distanthorizons.common.render.blaze.util.BlazePostProcessUtil;
|
||||
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureWrapper;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||
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();
|
||||
/** We don't want to actually write any depth data, but blaze3D complains if we don't bind a depth texture. */
|
||||
private final BlazeTextureWrapper dummyDepthTextureWrapper = BlazeTextureWrapper.createDepth("apply_dummy_depth");
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Can be set for special application shaders that need
|
||||
* extra information. <br><br>
|
||||
*
|
||||
* will be an empty array if unneeded
|
||||
*/
|
||||
private final String[] uniformNames;
|
||||
/** will be an empty array if unneeded */
|
||||
private final 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)
|
||||
{
|
||||
// one-time setup
|
||||
if (this.pipeline == null)
|
||||
{
|
||||
this.createPipeline();
|
||||
this.vboGpuBuffer = BlazePostProcessUtil.createAndUploadScreenVertexData(this.name);
|
||||
}
|
||||
|
||||
this.sourceColorTextureViewWrapper.tryWrap(sourceColorTexture);
|
||||
this.sourceDepthTextureViewWrapper.tryWrap(sourceDepthTexture);
|
||||
|
||||
this.destinationColorTextureViewWrapper.tryWrap(destinationColorTexture);
|
||||
|
||||
}
|
||||
private void createPipeline()
|
||||
{
|
||||
RenderPipelineBuilderWrapper pipelineBuilder = new RenderPipelineBuilderWrapper();
|
||||
{
|
||||
pipelineBuilder.withFaceCulling(false);
|
||||
pipelineBuilder.withDepthWrite(false);
|
||||
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.NONE);
|
||||
pipelineBuilder.withColorWrite(true);
|
||||
|
||||
if (this.blendFunction != null)
|
||||
{
|
||||
pipelineBuilder.withBlend(this.blendFunction);
|
||||
}
|
||||
else
|
||||
{
|
||||
pipelineBuilder.withoutBlend();
|
||||
}
|
||||
|
||||
pipelineBuilder.withPolygonMode(RenderPipelineBuilderWrapper.EDhPolygonMode.FILL);
|
||||
pipelineBuilder.withName(this.name);
|
||||
|
||||
pipelineBuilder.withVertexShader(this.vertexShaderPath);
|
||||
pipelineBuilder.withFragmentShader(this.fragmentShaderPath);
|
||||
|
||||
for (int i = 0; i < this.uniformNames.length; i++)
|
||||
{
|
||||
String uniformName = this.uniformNames[i];
|
||||
pipelineBuilder.withUniformBuffer(uniformName);
|
||||
}
|
||||
|
||||
pipelineBuilder.withSampler("uSourceColorTexture");
|
||||
pipelineBuilder.withSampler("uSourceDepthTexture");
|
||||
|
||||
VertexFormat vertexFormat = VertexFormat.builder()
|
||||
.add("vPosition", BlazeDhVertexFormatUtil.SCREEN_POS)
|
||||
.build();
|
||||
pipelineBuilder.withVertexFormat(vertexFormat);
|
||||
pipelineBuilder.withVertexMode(RenderPipelineBuilderWrapper.EDhVertexMode.TRIANGLE_FAN);
|
||||
}
|
||||
this.pipeline = pipelineBuilder.build();
|
||||
}
|
||||
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//========//
|
||||
// render //
|
||||
//========//
|
||||
//region
|
||||
|
||||
public void setUniform(String uniformName, 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);
|
||||
|
||||
this.dummyDepthTextureWrapper.tryCreateOrResize();
|
||||
|
||||
try (RenderPass renderPass = COMMAND_ENCODER.createRenderPass(
|
||||
this::getIdentifierName,
|
||||
this.destinationColorTextureViewWrapper.textureView,
|
||||
/*optionalClearColorAsInt*/ OptionalInt.empty(),
|
||||
this.dummyDepthTextureWrapper.textureView,
|
||||
/*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
|
||||
+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.blaze.apply;
|
||||
|
||||
#if MC_VER <= MC_1_21_10
|
||||
public class BlazeDhCopyRenderer {}
|
||||
|
||||
#else
|
||||
|
||||
import com.mojang.blaze3d.buffers.GpuBuffer;
|
||||
import com.mojang.blaze3d.pipeline.RenderPipeline;
|
||||
import com.mojang.blaze3d.systems.CommandEncoder;
|
||||
import com.mojang.blaze3d.systems.GpuDevice;
|
||||
import com.mojang.blaze3d.systems.RenderPass;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.mojang.blaze3d.textures.*;
|
||||
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPipelineBuilderWrapper;
|
||||
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureViewWrapper;
|
||||
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureWrapper;
|
||||
import com.seibel.distanthorizons.common.render.blaze.util.BlazePostProcessUtil;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
|
||||
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;
|
||||
|
||||
private BlazeTextureWrapper dummyDepthTextureWrapper;
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
//region
|
||||
|
||||
private BlazeDhCopyRenderer() { }
|
||||
|
||||
private void tryInit()
|
||||
{
|
||||
if (this.init)
|
||||
{
|
||||
return;
|
||||
}
|
||||
this.init = true;
|
||||
|
||||
|
||||
this.dummyDepthTextureWrapper = BlazeTextureWrapper.createDepth("dh_copy_depth_texture");
|
||||
|
||||
RenderPipelineBuilderWrapper pipelineBuilder = new RenderPipelineBuilderWrapper();
|
||||
{
|
||||
pipelineBuilder.withFaceCulling(false);
|
||||
pipelineBuilder.withDepthWrite(false);
|
||||
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.NONE);
|
||||
pipelineBuilder.withColorWrite(true);
|
||||
pipelineBuilder.withoutBlend();
|
||||
pipelineBuilder.withPolygonMode(RenderPipelineBuilderWrapper.EDhPolygonMode.FILL);
|
||||
pipelineBuilder.withName("copy");
|
||||
|
||||
pipelineBuilder.withVertexShader("copy/blaze/vert");
|
||||
pipelineBuilder.withFragmentShader("copy/blaze/frag");
|
||||
|
||||
pipelineBuilder.withSampler("uCopyTexture");
|
||||
|
||||
pipelineBuilder.withVertexFormat(BlazePostProcessUtil.createVertexFormat());
|
||||
pipelineBuilder.withVertexMode(RenderPipelineBuilderWrapper.EDhVertexMode.TRIANGLE_FAN);
|
||||
}
|
||||
this.pipeline = pipelineBuilder.build();
|
||||
|
||||
|
||||
this.vboGpuBuffer = BlazePostProcessUtil.createAndUploadScreenVertexData("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();
|
||||
|
||||
this.dummyDepthTextureWrapper.tryCreateOrResize();
|
||||
|
||||
try (RenderPass renderPass = COMMAND_ENCODER.createRenderPass(
|
||||
this::getRenderPassName,
|
||||
destinationTextureView,
|
||||
/*optionalClearColorAsInt*/ OptionalInt.empty(),
|
||||
this.dummyDepthTextureWrapper.textureView,
|
||||
/*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
|
||||
+299
@@ -0,0 +1,299 @@
|
||||
package com.seibel.distanthorizons.common.render.blaze.objects;
|
||||
|
||||
#if MC_VER <= MC_1_21_10
|
||||
public class BlazeGenericObjectVertexContainer {}
|
||||
|
||||
#else
|
||||
|
||||
import com.mojang.blaze3d.buffers.GpuBuffer;
|
||||
import com.mojang.blaze3d.buffers.GpuBufferSlice;
|
||||
import com.mojang.blaze3d.systems.CommandEncoder;
|
||||
import com.mojang.blaze3d.systems.GpuDevice;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.common.render.openGl.glObject.enums.GLEnums;
|
||||
import com.seibel.distanthorizons.core.render.RenderThreadTaskHandler;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IDhGenericObjectVertexBufferContainer;
|
||||
import com.seibel.distanthorizons.core.render.renderer.RenderableBoxGroup;
|
||||
import com.seibel.distanthorizons.coreapi.util.ColorUtil;
|
||||
import org.lwjgl.opengl.GL32;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* For use by {@link RenderableBoxGroup}
|
||||
*
|
||||
* @see RenderableBoxGroup
|
||||
*/
|
||||
public class BlazeGenericObjectVertexContainer implements IDhGenericObjectVertexBufferContainer
|
||||
{
|
||||
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||
|
||||
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
|
||||
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
|
||||
|
||||
private static final int[] BOX_INDICES = {
|
||||
//region
|
||||
// min X, vertical face
|
||||
2, 1, 0,
|
||||
0, 3, 2,
|
||||
// max X, vertical face
|
||||
6, 5, 4,
|
||||
4, 7, 6,
|
||||
|
||||
// min Z, vertical face
|
||||
10, 9, 8,
|
||||
8, 11, 10,
|
||||
// max Z, vertical face
|
||||
14, 13, 12,
|
||||
12, 15, 14,
|
||||
|
||||
// min Y, horizontal face
|
||||
18, 17, 16,
|
||||
16, 19, 18,
|
||||
// max Y, horizontal face
|
||||
20, 21, 22,
|
||||
22, 23, 20,
|
||||
//endregion
|
||||
};
|
||||
|
||||
|
||||
|
||||
public GpuBuffer vboGpuBuffer;
|
||||
public GpuBuffer indexGpuBuffer;
|
||||
|
||||
private ByteBuffer vertexBuffer = ByteBuffer.allocateDirect(0);
|
||||
private ByteBuffer indexBuffer = ByteBuffer.allocateDirect(0);
|
||||
|
||||
public int uploadedBoxCount = 0;
|
||||
|
||||
private EState state = EState.NEW;
|
||||
@Override
|
||||
public IDhGenericObjectVertexBufferContainer.EState getState() { return this.state; }
|
||||
@Override
|
||||
public void setState(IDhGenericObjectVertexBufferContainer.EState state) { this.state = state; }
|
||||
|
||||
|
||||
|
||||
//===========================//
|
||||
// render building/uploading //
|
||||
//===========================//
|
||||
//region
|
||||
|
||||
@Override
|
||||
public void updateVertexData(List<DhApiRenderableBox> uploadBoxList)
|
||||
{
|
||||
int boxCount = uploadBoxList.size();
|
||||
|
||||
// recreate the data arrays if their size is different
|
||||
if (this.uploadedBoxCount != boxCount)
|
||||
{
|
||||
this.uploadedBoxCount = boxCount;
|
||||
|
||||
int vertexBufferSize = this.vertexBufferSize();
|
||||
this.vertexBuffer = ByteBuffer.allocateDirect(vertexBufferSize);
|
||||
this.vertexBuffer.order(ByteOrder.nativeOrder());
|
||||
|
||||
int indexBufferSize = this.indexBufferSize();
|
||||
this.indexBuffer = ByteBuffer.allocateDirect(indexBufferSize);
|
||||
this.indexBuffer.order(ByteOrder.nativeOrder());
|
||||
}
|
||||
this.vertexBuffer.position(0);
|
||||
this.indexBuffer.position(0);
|
||||
|
||||
|
||||
|
||||
for (int boxIndex = 0; boxIndex < boxCount; boxIndex++)
|
||||
{
|
||||
// index
|
||||
int indexOffset = (boxIndex * 24 /*24 is the number of vertices in a box*/);
|
||||
for (int i = 0; i < BOX_INDICES.length; i++)
|
||||
{
|
||||
this.indexBuffer.putInt(BOX_INDICES[i] + indexOffset);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// vertex
|
||||
DhApiRenderableBox box = uploadBoxList.get(boxIndex);
|
||||
|
||||
final double[] boxVertices =
|
||||
{
|
||||
//region
|
||||
// Pos x y z
|
||||
|
||||
// min X, vertical face
|
||||
box.minPos.x, box.minPos.y, box.minPos.z,
|
||||
box.maxPos.x, box.minPos.y, box.minPos.z,
|
||||
box.maxPos.x, box.maxPos.y, box.minPos.z,
|
||||
box.minPos.x, box.maxPos.y, box.minPos.z,
|
||||
// max X, vertical face
|
||||
box.minPos.x, box.maxPos.y, box.maxPos.z,
|
||||
box.maxPos.x, box.maxPos.y, box.maxPos.z,
|
||||
box.maxPos.x, box.minPos.y, box.maxPos.z,
|
||||
box.minPos.x, box.minPos.y, box.maxPos.z,
|
||||
|
||||
// min Z, vertical face
|
||||
box.minPos.x, box.minPos.y, box.maxPos.z,
|
||||
box.minPos.x, box.minPos.y, box.minPos.z,
|
||||
box.minPos.x, box.maxPos.y, box.minPos.z,
|
||||
box.minPos.x, box.maxPos.y, box.maxPos.z,
|
||||
// max Z, vertical face
|
||||
box.maxPos.x, box.minPos.y, box.maxPos.z,
|
||||
box.maxPos.x, box.maxPos.y, box.maxPos.z,
|
||||
box.maxPos.x, box.maxPos.y, box.minPos.z,
|
||||
box.maxPos.x, box.minPos.y, box.minPos.z,
|
||||
|
||||
// min Y, horizontal face
|
||||
box.minPos.x, box.minPos.y, box.maxPos.z,
|
||||
box.maxPos.x, box.minPos.y, box.maxPos.z,
|
||||
box.maxPos.x, box.minPos.y, box.minPos.z,
|
||||
box.minPos.x, box.minPos.y, box.minPos.z,
|
||||
// max Y, horizontal face
|
||||
box.minPos.x, box.maxPos.y, box.maxPos.z,
|
||||
box.maxPos.x, box.maxPos.y, box.maxPos.z,
|
||||
box.maxPos.x, box.maxPos.y, box.minPos.z,
|
||||
box.minPos.x, box.maxPos.y, box.minPos.z,
|
||||
//endregion
|
||||
};
|
||||
|
||||
for (int vertexIndex = 0; vertexIndex < boxVertices.length; vertexIndex+=3)
|
||||
{
|
||||
this.vertexBuffer.putFloat((float)boxVertices[vertexIndex]); // x
|
||||
this.vertexBuffer.putFloat((float)boxVertices[vertexIndex+1]); // y
|
||||
this.vertexBuffer.putFloat((float)boxVertices[vertexIndex+2]); // z
|
||||
|
||||
int color = ColorUtil.toColorInt(box.color);
|
||||
byte r = (byte) ColorUtil.getRed(color);
|
||||
byte g = (byte) ColorUtil.getGreen(color);
|
||||
byte b = (byte) ColorUtil.getBlue(color);
|
||||
byte a = (byte) ColorUtil.getAlpha(color);
|
||||
this.vertexBuffer.put(r);
|
||||
this.vertexBuffer.put(g);
|
||||
this.vertexBuffer.put(b);
|
||||
this.vertexBuffer.put(a);
|
||||
|
||||
this.vertexBuffer.put(box.material);
|
||||
|
||||
// padding so the vertex format's byte count is a multiple of 4
|
||||
this.vertexBuffer.put((byte)0);
|
||||
this.vertexBuffer.put((byte)0);
|
||||
this.vertexBuffer.put((byte)0);
|
||||
}
|
||||
}
|
||||
this.vertexBuffer.flip();
|
||||
this.indexBuffer.flip();
|
||||
}
|
||||
|
||||
private int vertexBufferSize()
|
||||
{
|
||||
// minimum of 1 box to prevent trying to create a buffer of size 0
|
||||
int boxCount = Math.max(this.uploadedBoxCount, 1);
|
||||
|
||||
int faceCount = boxCount * 6; // 6 faces on a cube
|
||||
int vertexCount = faceCount * 6; // 6 vertices per cube
|
||||
|
||||
int byteSize = vertexCount * 3 * Float.BYTES; // x,y,z
|
||||
byteSize += vertexCount * 4; // r,g,b,a
|
||||
byteSize += 1; // material
|
||||
return byteSize;
|
||||
}
|
||||
private int indexBufferSize()
|
||||
{
|
||||
// minimum of 1 box to prevent trying to create a buffer of size 0
|
||||
int boxCount = Math.max(this.uploadedBoxCount, 1);
|
||||
|
||||
int quadCount = boxCount * 6 * 6; // 6 faces with 6 vertices each
|
||||
int byteSize = quadCount * GLEnums.getTypeSize(GL32.GL_UNSIGNED_INT);
|
||||
return byteSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uploadDataToGpu()
|
||||
{
|
||||
// vertex
|
||||
{
|
||||
int totalVertexByteSize = this.vertexBufferSize();
|
||||
if (this.vboGpuBuffer == null
|
||||
// recreating if the size changes is always necessary (even if we only need a smaller amount)
|
||||
// due to a bug on Mac where it will attempt to render anything allocated in the buffer
|
||||
|| this.vboGpuBuffer.size() != totalVertexByteSize)
|
||||
{
|
||||
if (this.vboGpuBuffer != null)
|
||||
{
|
||||
this.vboGpuBuffer.close();
|
||||
}
|
||||
|
||||
int usage = GpuBuffer.USAGE_COPY_DST
|
||||
| GpuBuffer.USAGE_VERTEX;
|
||||
this.vboGpuBuffer = GPU_DEVICE.createBuffer(this::getVertexBufferName, usage, totalVertexByteSize);
|
||||
}
|
||||
|
||||
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.vboGpuBuffer, /*offset*/0, totalVertexByteSize);
|
||||
COMMAND_ENCODER.writeToBuffer(bufferSlice, this.vertexBuffer);
|
||||
}
|
||||
|
||||
// index
|
||||
{
|
||||
int totalVertexByteSize = this.indexBufferSize();
|
||||
if (this.indexGpuBuffer == null
|
||||
// recreating if the size changes is always necessary (even if we only need a smaller amount)
|
||||
// due to a bug on Mac where it will attempt to render anything allocated in the buffer
|
||||
|| this.indexGpuBuffer.size() != totalVertexByteSize)
|
||||
{
|
||||
if (this.indexGpuBuffer != null)
|
||||
{
|
||||
this.indexGpuBuffer.close();
|
||||
}
|
||||
|
||||
int usage = GpuBuffer.USAGE_COPY_DST
|
||||
| GpuBuffer.USAGE_INDEX;
|
||||
this.indexGpuBuffer = GPU_DEVICE.createBuffer(this::getIndexBufferName, usage, totalVertexByteSize);
|
||||
}
|
||||
|
||||
int offset = 0;
|
||||
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.indexGpuBuffer, offset, totalVertexByteSize);
|
||||
|
||||
COMMAND_ENCODER.writeToBuffer(bufferSlice, this.indexBuffer);
|
||||
}
|
||||
}
|
||||
private String getVertexBufferName() { return "distantHorizons:GenericVertexBuffer"; }
|
||||
private String getIndexBufferName() { return "distantHorizons:GenericIndexBuffer"; }
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// base overrides //
|
||||
//================//
|
||||
//region
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
RenderThreadTaskHandler.INSTANCE.queueRunningOnRenderThread("BlazeGenericObjectVertexContainer close", () ->
|
||||
{
|
||||
if (this.vboGpuBuffer != null)
|
||||
{
|
||||
this.vboGpuBuffer.close();
|
||||
}
|
||||
|
||||
if (this.indexGpuBuffer != null)
|
||||
{
|
||||
this.indexGpuBuffer.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
}
|
||||
#endif
|
||||
+238
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
* 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.systems.CommandEncoder;
|
||||
import com.mojang.blaze3d.systems.GpuDevice;
|
||||
import com.mojang.blaze3d.systems.RenderPass;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.seibel.distanthorizons.common.render.blaze.BlazeDhMetaRenderer;
|
||||
import com.seibel.distanthorizons.common.render.blaze.apply.BlazeDhCopyRenderer;
|
||||
import com.seibel.distanthorizons.common.render.blaze.util.BlazePostProcessUtil;
|
||||
import com.seibel.distanthorizons.common.render.blaze.util.BlazeUniformUtil;
|
||||
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPipelineBuilderWrapper;
|
||||
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureViewWrapper;
|
||||
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.render.RenderParams;
|
||||
import com.seibel.distanthorizons.core.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 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;
|
||||
|
||||
private final BlazeTextureWrapper dhFadeColorTextureWrapper = BlazeTextureWrapper.createColor("dh_far_fade_color_texture");
|
||||
/** We don't want to actually write any depth data, but blaze3D complains if we don't bind a depth texture. */
|
||||
private final BlazeTextureWrapper dhFadeDepthTextureWrapper = BlazeTextureWrapper.createDepth("dh_far_fade_depth_texture");
|
||||
|
||||
private final BlazeTextureViewWrapper mcColorTextureViewWrapper = new BlazeTextureViewWrapper();
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
//region
|
||||
|
||||
private BlazeDhFarFadeRenderer() { }
|
||||
|
||||
private void tryInit()
|
||||
{
|
||||
if (this.init)
|
||||
{
|
||||
return;
|
||||
}
|
||||
this.init = true;
|
||||
|
||||
|
||||
|
||||
RenderPipelineBuilderWrapper pipelineBuilder = new RenderPipelineBuilderWrapper();
|
||||
{
|
||||
pipelineBuilder.withFaceCulling(false);
|
||||
pipelineBuilder.withDepthWrite(false);
|
||||
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.NONE);
|
||||
pipelineBuilder.withColorWrite(true);
|
||||
pipelineBuilder.withoutBlend();
|
||||
pipelineBuilder.withPolygonMode(RenderPipelineBuilderWrapper.EDhPolygonMode.FILL);
|
||||
pipelineBuilder.withName("far_fade");
|
||||
|
||||
pipelineBuilder.withVertexShader("fade/blaze/vert");
|
||||
pipelineBuilder.withFragmentShader("fade/blaze/dh_fade");
|
||||
|
||||
pipelineBuilder.withSampler("uMcColorTexture");
|
||||
|
||||
pipelineBuilder.withSampler("uDhDepthTexture");
|
||||
pipelineBuilder.withSampler("uDhColorTexture");
|
||||
|
||||
pipelineBuilder.withUniformBuffer("fragUniformBlock");
|
||||
|
||||
pipelineBuilder.withVertexFormat(BlazePostProcessUtil.createVertexFormat());
|
||||
pipelineBuilder.withVertexMode(RenderPipelineBuilderWrapper.EDhVertexMode.TRIANGLE_FAN);
|
||||
}
|
||||
this.pipeline = pipelineBuilder.build();
|
||||
|
||||
|
||||
this.vboGpuBuffer = BlazePostProcessUtil.createAndUploadScreenVertexData("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(MinecraftRenderWrapper.INSTANCE.getRenderTarget().getColorTexture());
|
||||
|
||||
this.dhFadeDepthTextureWrapper.tryCreateOrResize();
|
||||
|
||||
{
|
||||
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(),
|
||||
this.dhFadeDepthTextureWrapper.textureView,
|
||||
/*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
|
||||
+373
@@ -0,0 +1,373 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.common.render.blaze.postProcessing;
|
||||
|
||||
#if MC_VER <= MC_1_21_10
|
||||
public class BlazeDhFogRenderer {}
|
||||
|
||||
#else
|
||||
|
||||
import com.seibel.distanthorizons.api.enums.rendering.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.RenderPipelineBuilderWrapper;
|
||||
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureWrapper;
|
||||
import com.seibel.distanthorizons.common.render.blaze.util.BlazePostProcessUtil;
|
||||
import com.seibel.distanthorizons.common.render.blaze.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 java.awt.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.OptionalDouble;
|
||||
import java.util.OptionalInt;
|
||||
|
||||
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.systems.CommandEncoder;
|
||||
import com.mojang.blaze3d.systems.GpuDevice;
|
||||
import com.mojang.blaze3d.systems.RenderPass;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
|
||||
#if MC_VER <= MC_26_1_2
|
||||
import com.mojang.blaze3d.platform.DestFactor;
|
||||
import com.mojang.blaze3d.platform.SourceFactor;
|
||||
#else
|
||||
import com.mojang.blaze3d.platform.BlendFactor;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Renders fog onto the LODs.
|
||||
*/
|
||||
public class BlazeDhFogRenderer implements IDhFogRenderer
|
||||
{
|
||||
public static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||
|
||||
private static final IMinecraftClientWrapper MC = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
|
||||
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
|
||||
|
||||
private static final 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;
|
||||
|
||||
private final BlazeTextureWrapper fogColorTextureWrapper = BlazeTextureWrapper.createColor("dh_fog_color_texture");
|
||||
/** We don't want to actually write any depth data, but blaze3D complains if we don't bind a depth texture. */
|
||||
private final BlazeTextureWrapper fogDepthTextureWrapper = BlazeTextureWrapper.createDepth("dh_fog_depth_texture");
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
//region
|
||||
|
||||
private BlazeDhFogRenderer() { }
|
||||
|
||||
private void tryInit()
|
||||
{
|
||||
if (this.init)
|
||||
{
|
||||
return;
|
||||
}
|
||||
this.init = true;
|
||||
|
||||
|
||||
BlendFunction blendFunc;
|
||||
#if MC_VER <= MC_26_1_2
|
||||
blendFunc = new BlendFunction(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ONE_MINUS_SRC_ALPHA);
|
||||
#else
|
||||
blendFunc = new BlendFunction(BlendFactor.SRC_ALPHA, BlendFactor.ONE_MINUS_SRC_ALPHA, BlendFactor.ONE, BlendFactor.ONE_MINUS_SRC_ALPHA);
|
||||
#endif
|
||||
|
||||
this.applyRenderer = new BlazeDhApplyRenderer(
|
||||
"fog_apply_to_dh",
|
||||
blendFunc,
|
||||
"apply/blaze/vert", "apply/blaze/frag"
|
||||
);
|
||||
|
||||
RenderPipelineBuilderWrapper pipelineBuilder = new RenderPipelineBuilderWrapper();
|
||||
{
|
||||
pipelineBuilder.withFaceCulling(false);
|
||||
pipelineBuilder.withDepthWrite(false);
|
||||
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.NONE);
|
||||
pipelineBuilder.withColorWrite(true);
|
||||
pipelineBuilder.withoutBlend();
|
||||
pipelineBuilder.withPolygonMode(RenderPipelineBuilderWrapper.EDhPolygonMode.FILL);
|
||||
pipelineBuilder.withName("fog_render");
|
||||
|
||||
pipelineBuilder.withVertexShader("fog/blaze/vert");
|
||||
pipelineBuilder.withFragmentShader("fog/blaze/frag");
|
||||
|
||||
pipelineBuilder.withSampler("uDhDepthTexture");
|
||||
|
||||
pipelineBuilder.withUniformBuffer("fragUniformBlock");
|
||||
|
||||
pipelineBuilder.withVertexFormat(BlazePostProcessUtil.createVertexFormat());
|
||||
pipelineBuilder.withVertexMode(RenderPipelineBuilderWrapper.EDhVertexMode.TRIANGLE_FAN);
|
||||
}
|
||||
this.pipeline = pipelineBuilder.build();
|
||||
|
||||
|
||||
this.vboGpuBuffer = BlazePostProcessUtil.createAndUploadScreenVertexData("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();
|
||||
this.fogDepthTextureWrapper.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(),
|
||||
this.fogDepthTextureWrapper.textureView,
|
||||
/*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
|
||||
+298
@@ -0,0 +1,298 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.common.render.blaze.postProcessing;
|
||||
|
||||
#if MC_VER <= MC_1_21_10
|
||||
public class BlazeDhSsaoRenderer {}
|
||||
|
||||
#else
|
||||
|
||||
import com.seibel.distanthorizons.common.render.blaze.BlazeDhMetaRenderer;
|
||||
import com.seibel.distanthorizons.common.render.blaze.apply.BlazeDhApplyRenderer;
|
||||
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPipelineBuilderWrapper;
|
||||
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureWrapper;
|
||||
import com.seibel.distanthorizons.common.render.blaze.util.BlazePostProcessUtil;
|
||||
import com.seibel.distanthorizons.common.render.blaze.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 java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.OptionalDouble;
|
||||
import java.util.OptionalInt;
|
||||
|
||||
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.BlendFactor;
|
||||
import com.mojang.blaze3d.systems.CommandEncoder;
|
||||
import com.mojang.blaze3d.systems.GpuDevice;
|
||||
import com.mojang.blaze3d.systems.RenderPass;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
|
||||
#if MC_VER <= MC_26_1_2
|
||||
import com.mojang.blaze3d.platform.DestFactor;
|
||||
import com.mojang.blaze3d.platform.SourceFactor;
|
||||
#else
|
||||
import com.mojang.blaze3d.platform.BlendFactor;
|
||||
#endif
|
||||
|
||||
/** Renders SSAO to the DH LODs. */
|
||||
public class BlazeDhSsaoRenderer implements IDhSsaoRenderer
|
||||
{
|
||||
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||
|
||||
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
|
||||
|
||||
private static final 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;
|
||||
|
||||
private final BlazeTextureWrapper ssaoColorTextureWrapper = BlazeTextureWrapper.createColor("dh_ssao_color_texture");
|
||||
/** We don't want to actually write any depth data, but blaze3D complains if we don't bind a depth texture. */
|
||||
private final BlazeTextureWrapper ssaoDepthTextureWrapper = BlazeTextureWrapper.createDepth("dh_ssao_depth_texture");
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
//region
|
||||
|
||||
private BlazeDhSsaoRenderer() { }
|
||||
|
||||
private void tryInit()
|
||||
{
|
||||
if (this.init)
|
||||
{
|
||||
return;
|
||||
}
|
||||
this.init = true;
|
||||
|
||||
|
||||
|
||||
BlendFunction blendFunc;
|
||||
#if MC_VER <= MC_26_1_2
|
||||
blendFunc = new BlendFunction(SourceFactor.ZERO, DestFactor.SRC_ALPHA, SourceFactor.ZERO, DestFactor.ONE);
|
||||
#else
|
||||
blendFunc = new BlendFunction(BlendFactor.ZERO, BlendFactor.SRC_ALPHA, BlendFactor.ZERO, BlendFactor.ONE);
|
||||
#endif
|
||||
|
||||
this.applyRenderer = new BlazeDhApplyRenderer(
|
||||
"ssao_apply_to_dh",
|
||||
blendFunc,
|
||||
"apply/blaze/vert", "ssao/blaze/apply",
|
||||
/*uniforms*/ new String[] { "applyFragUniformBlock" }
|
||||
);
|
||||
|
||||
RenderPipelineBuilderWrapper pipelineBuilder = new RenderPipelineBuilderWrapper();
|
||||
{
|
||||
pipelineBuilder.withFaceCulling(false);
|
||||
pipelineBuilder.withDepthWrite(false);
|
||||
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.NONE);
|
||||
pipelineBuilder.withColorWrite(true);
|
||||
pipelineBuilder.withoutBlend();
|
||||
pipelineBuilder.withPolygonMode(RenderPipelineBuilderWrapper.EDhPolygonMode.FILL);
|
||||
pipelineBuilder.withName("ssao_render");
|
||||
|
||||
pipelineBuilder.withVertexShader("ssao/blaze/vert");
|
||||
pipelineBuilder.withFragmentShader("ssao/blaze/frag");
|
||||
|
||||
pipelineBuilder.withSampler("uDhDepthTexture");
|
||||
|
||||
pipelineBuilder.withUniformBuffer("fragUniformBlock");
|
||||
|
||||
pipelineBuilder.withVertexFormat(BlazePostProcessUtil.createVertexFormat());
|
||||
pipelineBuilder.withVertexMode(RenderPipelineBuilderWrapper.EDhVertexMode.TRIANGLE_FAN);
|
||||
}
|
||||
this.pipeline = pipelineBuilder.build();
|
||||
|
||||
|
||||
this.vboGpuBuffer = BlazePostProcessUtil.createAndUploadScreenVertexData("McSsao");
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//========//
|
||||
// render //
|
||||
//========//
|
||||
//region
|
||||
|
||||
@Override
|
||||
public void render(RenderParams renderParams)
|
||||
{
|
||||
this.tryInit();
|
||||
|
||||
|
||||
if (BlazeDhMetaRenderer.INSTANCE.dhDepthTextureWrapper.isEmpty()
|
||||
|| BlazeDhMetaRenderer.INSTANCE.dhColorTextureWrapper.isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// textures
|
||||
this.ssaoColorTextureWrapper.tryCreateOrResize();
|
||||
this.ssaoDepthTextureWrapper.tryCreateOrResize();
|
||||
|
||||
// frag uniforms
|
||||
{
|
||||
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(),
|
||||
this.ssaoDepthTextureWrapper.textureView,
|
||||
/*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
|
||||
+265
@@ -0,0 +1,265 @@
|
||||
/*
|
||||
* 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.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.RenderPipelineBuilderWrapper;
|
||||
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureViewWrapper;
|
||||
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.render.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("DhVanillaFadeColorTexture");
|
||||
/** We don't want to actually write any depth data, but blaze3D complains if we don't bind a depth texture. */
|
||||
private final BlazeTextureWrapper fadeDepthTextureWrapper = BlazeTextureWrapper.createDepth("DhVanillaFadeDepthTexture");
|
||||
|
||||
|
||||
public final BlazeTextureViewWrapper mcDepthTextureWrapper = new BlazeTextureViewWrapper();
|
||||
public final BlazeTextureViewWrapper mcColorTextureWrapper = new BlazeTextureViewWrapper();
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
//region
|
||||
|
||||
private BlazeVanillaFadeRenderer() { }
|
||||
|
||||
private void tryInit()
|
||||
{
|
||||
if (this.init)
|
||||
{
|
||||
return;
|
||||
}
|
||||
this.init = true;
|
||||
|
||||
|
||||
|
||||
RenderPipelineBuilderWrapper pipelineBuilder = new RenderPipelineBuilderWrapper();
|
||||
{
|
||||
pipelineBuilder.withFaceCulling(false);
|
||||
pipelineBuilder.withDepthWrite(false);
|
||||
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.NONE);
|
||||
pipelineBuilder.withColorWrite(true);
|
||||
pipelineBuilder.withoutBlend();
|
||||
pipelineBuilder.withPolygonMode(RenderPipelineBuilderWrapper.EDhPolygonMode.FILL);
|
||||
pipelineBuilder.withName("vanilla_fade");
|
||||
|
||||
pipelineBuilder.withVertexShader("fade/blaze/vert");
|
||||
pipelineBuilder.withFragmentShader("fade/blaze/vanilla_fade");
|
||||
|
||||
pipelineBuilder.withSampler("uMcDepthTexture");
|
||||
pipelineBuilder.withSampler("uCombinedMcDhColorTexture");
|
||||
|
||||
pipelineBuilder.withSampler("uDhDepthTexture");
|
||||
pipelineBuilder.withSampler("uDhColorTexture");
|
||||
|
||||
pipelineBuilder.withUniformBuffer("fragUniformBlock");
|
||||
|
||||
pipelineBuilder.withVertexFormat(BlazePostProcessUtil.createVertexFormat());
|
||||
pipelineBuilder.withVertexMode(RenderPipelineBuilderWrapper.EDhVertexMode.TRIANGLE_FAN);
|
||||
}
|
||||
this.pipeline = pipelineBuilder.build();
|
||||
|
||||
|
||||
this.vboGpuBuffer = BlazePostProcessUtil.createAndUploadScreenVertexData("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.fadeDepthTextureWrapper.tryCreateOrResize();
|
||||
|
||||
this.mcDepthTextureWrapper.tryWrap(MinecraftRenderWrapper.INSTANCE.getRenderTarget().getDepthTexture());
|
||||
this.mcColorTextureWrapper.tryWrap(MinecraftRenderWrapper.INSTANCE.getRenderTarget().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 inverseDhModelViewProjectionMatrix = new Mat4f(renderParams.dhProjectionMatrix);
|
||||
inverseDhModelViewProjectionMatrix.multiply(renderParams.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(),
|
||||
this.fadeDepthTextureWrapper.textureView,
|
||||
/*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
|
||||
+190
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.common.render.blaze.test;
|
||||
|
||||
#if MC_VER <= MC_1_21_10
|
||||
public class BlazeDhTestTriangleRenderer {}
|
||||
|
||||
#else
|
||||
|
||||
import com.mojang.blaze3d.buffers.GpuBuffer;
|
||||
import com.mojang.blaze3d.buffers.GpuBufferSlice;
|
||||
import com.mojang.blaze3d.pipeline.RenderPipeline;
|
||||
import com.mojang.blaze3d.platform.PolygonMode;
|
||||
import com.mojang.blaze3d.systems.CommandEncoder;
|
||||
import com.mojang.blaze3d.systems.GpuDevice;
|
||||
import com.mojang.blaze3d.systems.RenderPass;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.mojang.blaze3d.textures.*;
|
||||
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||
import com.seibel.distanthorizons.common.render.blaze.util.BlazeDhVertexFormatUtil;
|
||||
import com.seibel.distanthorizons.common.render.blaze.wrappers.RenderPipelineBuilderWrapper;
|
||||
import com.seibel.distanthorizons.common.render.blaze.wrappers.texture.BlazeTextureViewWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.render.RenderParams;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhTestTriangleRenderer;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.resources.Identifier;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.OptionalDouble;
|
||||
import java.util.OptionalInt;
|
||||
|
||||
#if MC_VER <= MC_1_21_11
|
||||
#else
|
||||
import com.mojang.blaze3d.pipeline.DepthStencilState;
|
||||
import com.mojang.blaze3d.platform.CompareOp;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Renders the OpenGL/Vulkan triangle
|
||||
* to the center of the screen to confirm DH's
|
||||
* apply shader is running correctly
|
||||
*/
|
||||
public class BlazeDhTestTriangleRenderer implements IDhTestTriangleRenderer
|
||||
{
|
||||
public static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||
|
||||
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
|
||||
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
|
||||
|
||||
public static final BlazeDhTestTriangleRenderer INSTANCE = new BlazeDhTestTriangleRenderer();
|
||||
|
||||
private RenderPipeline pipeline;
|
||||
private boolean init = false;
|
||||
|
||||
public final BlazeTextureViewWrapper mcColorTextureViewWrapper = new BlazeTextureViewWrapper();
|
||||
public final BlazeTextureViewWrapper mcDepthTextureViewWrapper = new BlazeTextureViewWrapper();
|
||||
|
||||
private GpuBuffer vboGpuBuffer;
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
//region
|
||||
|
||||
private BlazeDhTestTriangleRenderer() { }
|
||||
|
||||
private void tryInit()
|
||||
{
|
||||
if (this.init)
|
||||
{
|
||||
return;
|
||||
}
|
||||
this.init = true;
|
||||
|
||||
RenderPipelineBuilderWrapper pipelineBuilder = new RenderPipelineBuilderWrapper();
|
||||
{
|
||||
pipelineBuilder.withFaceCulling(false);
|
||||
pipelineBuilder.withDepthWrite(false);
|
||||
pipelineBuilder.withDepthTest(RenderPipelineBuilderWrapper.EDhDepthTest.NONE);
|
||||
pipelineBuilder.withColorWrite(true);
|
||||
pipelineBuilder.withoutBlend();
|
||||
pipelineBuilder.withName("triangle_test");
|
||||
|
||||
pipelineBuilder.withVertexShader("test/blaze/vert");
|
||||
pipelineBuilder.withFragmentShader("test/blaze/frag");
|
||||
|
||||
VertexFormat vertexFormat = VertexFormat.builder()
|
||||
.add("vPosition", BlazeDhVertexFormatUtil.SCREEN_POS)
|
||||
.add("vColor", BlazeDhVertexFormatUtil.RGBA_FLOAT_COLOR)
|
||||
.build();
|
||||
pipelineBuilder.withVertexFormat(vertexFormat);
|
||||
|
||||
pipelineBuilder.withVertexMode(RenderPipelineBuilderWrapper.EDhVertexMode.TRIANGLES);
|
||||
}
|
||||
this.pipeline = pipelineBuilder.build();
|
||||
|
||||
this.uploadVertexData();
|
||||
}
|
||||
private void uploadVertexData()
|
||||
{
|
||||
// vertices for the OpenGL/Vulkan Triangle
|
||||
float[] vertices = new float[]
|
||||
{
|
||||
// PosX,Y, ColorR,G,B,A
|
||||
-0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f,
|
||||
0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f,
|
||||
0.0f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f,
|
||||
};
|
||||
|
||||
|
||||
int usage = GpuBuffer.USAGE_COPY_DST
|
||||
| GpuBuffer.USAGE_VERTEX;
|
||||
int size = vertices.length * Float.BYTES;
|
||||
this.vboGpuBuffer = GPU_DEVICE.createBuffer(this::getRenderPassName, usage, size);
|
||||
|
||||
{
|
||||
int offset = 0;
|
||||
int length = vertices.length * Float.BYTES;
|
||||
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.vboGpuBuffer, offset, length);
|
||||
|
||||
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(vertices.length * Float.BYTES);
|
||||
// Fill buffer with vertices.
|
||||
byteBuffer.order(ByteOrder.nativeOrder());
|
||||
byteBuffer.asFloatBuffer().put(vertices);
|
||||
byteBuffer.rewind();
|
||||
|
||||
COMMAND_ENCODER.writeToBuffer(bufferSlice, byteBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//========//
|
||||
// render //
|
||||
//========//
|
||||
//region
|
||||
|
||||
@Override
|
||||
public void render(RenderParams renderParams)
|
||||
{
|
||||
this.tryInit();
|
||||
|
||||
this.mcColorTextureViewWrapper.tryWrap(MinecraftRenderWrapper.INSTANCE.getRenderTarget().getColorTexture());
|
||||
this.mcDepthTextureViewWrapper.tryWrap(MinecraftRenderWrapper.INSTANCE.getRenderTarget().getDepthTexture());
|
||||
|
||||
try (RenderPass renderPass = COMMAND_ENCODER.createRenderPass(
|
||||
this::getRenderPassName,
|
||||
this.mcColorTextureViewWrapper.textureView,
|
||||
/*optionalClearColorAsInt*/ OptionalInt.empty(),
|
||||
this.mcDepthTextureViewWrapper.textureView,
|
||||
/*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
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
package com.seibel.distanthorizons.common.render.blaze.util;
|
||||
|
||||
#if MC_VER <= MC_1_21_10
|
||||
public class BlazeDhVertexFormatUtil {}
|
||||
|
||||
#else
|
||||
|
||||
import com.mojang.blaze3d.GpuFormat;
|
||||
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;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @see LodQuadBuilder
|
||||
*/
|
||||
@SuppressWarnings("DataFlowIssue") // ignore null setter warnings in the static constructor (those will only be null if the render API is GL and in that case we should never use these objects)
|
||||
public class BlazeDhVertexFormatUtil
|
||||
{
|
||||
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||
|
||||
|
||||
@NotNull public static final VertexFormatElement SCREEN_POS;
|
||||
@NotNull public static final VertexFormatElement RGBA_FLOAT_COLOR;
|
||||
|
||||
@NotNull public static final VertexFormatElement SHORT_XYZ_POS;
|
||||
@NotNull public static final VertexFormatElement BYTE_PAD;
|
||||
/** contains light and micro-offset */
|
||||
@NotNull public static final VertexFormatElement META;
|
||||
@NotNull public static final VertexFormatElement RGBA_UBYTE_COLOR;
|
||||
@NotNull public static final VertexFormatElement IRIS_MATERIAL;
|
||||
@NotNull public static final VertexFormatElement IRIS_NORMAL;
|
||||
|
||||
@NotNull public static final VertexFormatElement FLOAT_XYZ_POS;
|
||||
|
||||
|
||||
|
||||
|
||||
static
|
||||
{
|
||||
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
|
||||
{
|
||||
#if MC_VER <= MC_1_21_11
|
||||
SCREEN_POS = VertexFormatElement.register(/*id*/22, /*index*/0, VertexFormatElement.Type.FLOAT, VertexFormatElement.Usage.POSITION, /*count*/ 2);
|
||||
RGBA_FLOAT_COLOR = VertexFormatElement.register(/*id*/23, /*index*/0, VertexFormatElement.Type.FLOAT, VertexFormatElement.Usage.COLOR, /*count*/ 4);
|
||||
|
||||
SHORT_XYZ_POS = VertexFormatElement.register(/*id*/24, /*index*/0, VertexFormatElement.Type.USHORT, VertexFormatElement.Usage.POSITION, /*count*/ 3);
|
||||
BYTE_PAD = VertexFormatElement.register(/*id*/25, /*index*/0, VertexFormatElement.Type.BYTE, VertexFormatElement.Usage.GENERIC, /*count*/ 1);
|
||||
|
||||
META = VertexFormatElement.register(/*id*/26, /*index*/0, VertexFormatElement.Type.USHORT, VertexFormatElement.Usage.GENERIC, /*count*/ 1);
|
||||
RGBA_UBYTE_COLOR = VertexFormatElement.register(/*id*/27, /*index*/0, VertexFormatElement.Type.UBYTE, VertexFormatElement.Usage.COLOR, /*count*/ 4);
|
||||
IRIS_MATERIAL = VertexFormatElement.register(/*id*/28, /*index*/0, VertexFormatElement.Type.BYTE, VertexFormatElement.Usage.GENERIC, /*count*/ 1);
|
||||
IRIS_NORMAL = VertexFormatElement.register(/*id*/29, /*index*/0, VertexFormatElement.Type.BYTE, VertexFormatElement.Usage.GENERIC, /*count*/ 1);
|
||||
|
||||
FLOAT_XYZ_POS = VertexFormatElement.register(/*id*/30, /*index*/0, VertexFormatElement.Type.FLOAT, VertexFormatElement.Usage.POSITION, /*count*/ 3);
|
||||
#elif MC_VER <= MC_26_1_2
|
||||
SCREEN_POS = VertexFormatElement.register(/*id*/22, /*index*/0, VertexFormatElement.Type.FLOAT, false, /*count*/ 2);
|
||||
RGBA_FLOAT_COLOR = VertexFormatElement.register(/*id*/23, /*index*/0, VertexFormatElement.Type.FLOAT, false, /*count*/ 4);
|
||||
|
||||
SHORT_XYZ_POS = VertexFormatElement.register(/*id*/24, /*index*/0, VertexFormatElement.Type.USHORT, false, /*count*/ 3);
|
||||
BYTE_PAD = VertexFormatElement.register(/*id*/25, /*index*/0, VertexFormatElement.Type.BYTE, false, /*count*/ 1);
|
||||
|
||||
META = VertexFormatElement.register(/*id*/26, /*index*/0, VertexFormatElement.Type.USHORT, false, /*count*/ 1);
|
||||
RGBA_UBYTE_COLOR = VertexFormatElement.register(/*id*/27, /*index*/0, VertexFormatElement.Type.UBYTE, true, /*count*/ 4);
|
||||
IRIS_MATERIAL = VertexFormatElement.register(/*id*/28, /*index*/0, VertexFormatElement.Type.BYTE, false, /*count*/ 1);
|
||||
IRIS_NORMAL = VertexFormatElement.register(/*id*/29, /*index*/0, VertexFormatElement.Type.BYTE, false, /*count*/ 1);
|
||||
|
||||
FLOAT_XYZ_POS = VertexFormatElement.register(/*id*/30, /*index*/0, VertexFormatElement.Type.FLOAT, false, /*count*/ 3);
|
||||
#else
|
||||
|
||||
SCREEN_POS = VertexFormatElement.register(/*id*/22, /*index*/0, GpuFormat.RG32_FLOAT); // 2 floats
|
||||
RGBA_FLOAT_COLOR = VertexFormatElement.register(/*id*/23, /*index*/0, GpuFormat.RGBA32_FLOAT); // 4 floats
|
||||
|
||||
SHORT_XYZ_POS = VertexFormatElement.register(/*id*/24, /*index*/0, GpuFormat.RGB16_UINT); // 3 ushorts
|
||||
BYTE_PAD = VertexFormatElement.register(/*id*/25, /*index*/0, GpuFormat.R8_UINT); // 1 byte
|
||||
|
||||
META = VertexFormatElement.register(/*id*/26, /*index*/0, GpuFormat.R16_UINT); // 1 ushort
|
||||
RGBA_UBYTE_COLOR = VertexFormatElement.register(/*id*/27, /*index*/0, GpuFormat.RGBA8_UNORM); // 4 ubytes
|
||||
IRIS_MATERIAL = VertexFormatElement.register(/*id*/28, /*index*/0, GpuFormat.R8_UINT); // 1 byte
|
||||
IRIS_NORMAL = VertexFormatElement.register(/*id*/29, /*index*/0, GpuFormat.R8_UINT); // 1 byte
|
||||
|
||||
FLOAT_XYZ_POS = VertexFormatElement.register(/*id*/30, /*index*/0, GpuFormat.RGB32_FLOAT); // 3 floats
|
||||
#endif
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
String message = "Unable to register one or more ["+VertexFormatElement.class.getSimpleName()+"] this is likely caused by another mod registering their own custom ["+VertexFormatElement.class.getSimpleName()+"]'s. This should be fixed in the next major Minecraft version.";
|
||||
|
||||
IMinecraftClientWrapper mc = SingletonInjector.INSTANCE.get(IMinecraftClientWrapper.class);
|
||||
mc.crashMinecraft(message, new Exception(message, e));
|
||||
|
||||
// here to make the compiler happy, the process should shut down before this
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
LOGGER.debug("Successfully registered ["+VertexFormatElement.class.getSimpleName()+"].");
|
||||
}
|
||||
else
|
||||
{
|
||||
// set to null so we can fail fast with a null pointer if we ever attempt to incorrectly use these
|
||||
SCREEN_POS = null;
|
||||
RGBA_FLOAT_COLOR = null;
|
||||
|
||||
SHORT_XYZ_POS = null;
|
||||
BYTE_PAD = null;
|
||||
|
||||
META = null;
|
||||
RGBA_UBYTE_COLOR = null;
|
||||
IRIS_MATERIAL = null;
|
||||
IRIS_NORMAL = null;
|
||||
|
||||
FLOAT_XYZ_POS = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
#endif
|
||||
+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
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
package com.seibel.distanthorizons.common.render.blaze.util;
|
||||
|
||||
#if MC_VER <= MC_1_21_10
|
||||
public class BlazeUniformUtil {}
|
||||
|
||||
#else
|
||||
|
||||
import com.mojang.blaze3d.buffers.GpuBuffer;
|
||||
import com.mojang.blaze3d.systems.CommandEncoder;
|
||||
import com.mojang.blaze3d.systems.GpuDevice;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
|
||||
public class BlazeUniformUtil
|
||||
{
|
||||
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||
|
||||
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
|
||||
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
|
||||
|
||||
|
||||
public static GpuBuffer createBuffer(String uniformName, int size, GpuBuffer vboGpuBuffer)
|
||||
{
|
||||
// create VBO if needed
|
||||
if (vboGpuBuffer == null
|
||||
|| vboGpuBuffer.size() < size)
|
||||
{
|
||||
if (vboGpuBuffer != null)
|
||||
{
|
||||
vboGpuBuffer.close();
|
||||
}
|
||||
|
||||
int usage = GpuBuffer.USAGE_COPY_DST
|
||||
| GpuBuffer.USAGE_VERTEX
|
||||
| GpuBuffer.USAGE_UNIFORM;
|
||||
vboGpuBuffer = GPU_DEVICE.createBuffer(() -> uniformName, usage, size);
|
||||
}
|
||||
|
||||
return vboGpuBuffer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
#endif
|
||||
+404
@@ -0,0 +1,404 @@
|
||||
package com.seibel.distanthorizons.common.render.blaze.wrappers;
|
||||
|
||||
|
||||
#if MC_VER <= MC_1_21_10
|
||||
public class RenderPipelineBuilderWrapper {}
|
||||
|
||||
#else
|
||||
|
||||
import com.mojang.blaze3d.GpuFormat;
|
||||
import com.mojang.blaze3d.pipeline.*;
|
||||
import com.mojang.blaze3d.platform.PolygonMode;
|
||||
import com.mojang.blaze3d.shaders.UniformType;
|
||||
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||
import net.minecraft.resources.Identifier;
|
||||
|
||||
#if MC_VER <= MC_1_21_11
|
||||
import com.mojang.blaze3d.platform.DepthTestFunction;
|
||||
#else
|
||||
import com.mojang.blaze3d.platform.CompareOp;
|
||||
#endif
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Optional;
|
||||
|
||||
public class RenderPipelineBuilderWrapper
|
||||
{
|
||||
public static final String NAME_PREFIX = "distanthorizons:";
|
||||
|
||||
private static final String SHADER_RESOURCE_FOLDER = "assets/distanthorizons/shaders/";
|
||||
|
||||
private static final ClassLoader CLASS_LOADER = RenderPipelineBuilderWrapper.class.getClassLoader();
|
||||
|
||||
|
||||
private final RenderPipeline.Builder blazePipelineBuilder;
|
||||
|
||||
// variables for specific builder options should be put next to their builder methods for simpler organization
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
//region
|
||||
|
||||
public RenderPipelineBuilderWrapper()
|
||||
{
|
||||
this.blazePipelineBuilder = RenderPipeline.builder();
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//==========//
|
||||
// building //
|
||||
//==========//
|
||||
//region
|
||||
|
||||
private boolean writeDepth = false;
|
||||
public RenderPipelineBuilderWrapper withDepthWrite(boolean write)
|
||||
{
|
||||
this.writeDepth = write;
|
||||
return this;
|
||||
}
|
||||
|
||||
private boolean writeColor = false;
|
||||
public RenderPipelineBuilderWrapper withColorWrite(boolean write)
|
||||
{
|
||||
this.writeColor = write;
|
||||
return this;
|
||||
}
|
||||
|
||||
private BlendFunction blendFunction = null;
|
||||
public RenderPipelineBuilderWrapper withBlend(BlendFunction blendFunction)
|
||||
{
|
||||
this.blendFunction = blendFunction;
|
||||
return this;
|
||||
}
|
||||
public RenderPipelineBuilderWrapper withoutBlend()
|
||||
{
|
||||
this.blendFunction = null;
|
||||
return this;
|
||||
}
|
||||
|
||||
private EDhDepthTest depthTest;
|
||||
public RenderPipelineBuilderWrapper withDepthTest(EDhDepthTest depthTest)
|
||||
{
|
||||
this.depthTest = depthTest;
|
||||
return this;
|
||||
}
|
||||
|
||||
public RenderPipelineBuilderWrapper withFaceCulling(boolean culling)
|
||||
{
|
||||
this.blazePipelineBuilder.withCull(culling);
|
||||
return this;
|
||||
}
|
||||
|
||||
public RenderPipelineBuilderWrapper withPolygonMode(EDhPolygonMode dhMode)
|
||||
{
|
||||
PolygonMode blazeMode;
|
||||
switch (dhMode)
|
||||
{
|
||||
case FILL:
|
||||
blazeMode = PolygonMode.FILL;
|
||||
break;
|
||||
case WIREFRAME:
|
||||
blazeMode = PolygonMode.WIREFRAME;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new UnsupportedOperationException("No polygonMode defined for type ["+dhMode+"].");
|
||||
}
|
||||
|
||||
this.blazePipelineBuilder.withPolygonMode(blazeMode);
|
||||
return this;
|
||||
}
|
||||
|
||||
public RenderPipelineBuilderWrapper withName(String name) throws IllegalArgumentException
|
||||
{
|
||||
// Identifiers must be of a specific format
|
||||
if (!isValidIdentifier(name))
|
||||
{
|
||||
throw new IllegalArgumentException("Non [a-z0-9/._-] character in name: ["+name+"].");
|
||||
}
|
||||
|
||||
this.blazePipelineBuilder.withLocation(Identifier.parse(NAME_PREFIX + name));
|
||||
return this;
|
||||
}
|
||||
|
||||
private final ArrayList<String> samplerNames = new ArrayList<>();
|
||||
public RenderPipelineBuilderWrapper withSampler(String name) throws IllegalArgumentException
|
||||
{
|
||||
#if MC_VER <= MC_26_1_2
|
||||
this.blazePipelineBuilder.withSampler(name);
|
||||
#else
|
||||
samplerNames.add(name);
|
||||
#endif
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private final ArrayList<String> uniformBufferNames = new ArrayList<>();
|
||||
public RenderPipelineBuilderWrapper withUniformBuffer(String name) throws IllegalArgumentException
|
||||
{
|
||||
#if MC_VER <= MC_26_1_2
|
||||
this.blazePipelineBuilder.withUniform(name, UniformType.UNIFORM_BUFFER);
|
||||
#else
|
||||
uniformBufferNames.add(name);
|
||||
#endif
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private VertexFormat vertexFormat = null;
|
||||
public RenderPipelineBuilderWrapper withVertexFormat(VertexFormat vertexFormat)
|
||||
{
|
||||
this.vertexFormat = vertexFormat;
|
||||
return this;
|
||||
}
|
||||
|
||||
private EDhVertexMode vertexMode = null;
|
||||
public RenderPipelineBuilderWrapper withVertexMode(EDhVertexMode vertexMode)
|
||||
{
|
||||
this.vertexMode = vertexMode;
|
||||
return this;
|
||||
}
|
||||
|
||||
public RenderPipelineBuilderWrapper withVertexShader(String scriptResourcePath) { return this.withShader(EDhShaderType.VERTEX, scriptResourcePath); }
|
||||
public RenderPipelineBuilderWrapper withFragmentShader(String scriptResourcePath) { return this.withShader(EDhShaderType.FRAGMENT, scriptResourcePath); }
|
||||
private RenderPipelineBuilderWrapper withShader(EDhShaderType shaderType, String scriptResourcePath)
|
||||
{
|
||||
String fullShaderResourcePath = SHADER_RESOURCE_FOLDER + scriptResourcePath + shaderType.fileExtension;
|
||||
|
||||
// confirm the shader file exists
|
||||
try (InputStream scriptListInputStream = CLASS_LOADER.getResourceAsStream(fullShaderResourcePath))
|
||||
{
|
||||
if (scriptListInputStream == null)
|
||||
{
|
||||
throw new NullPointerException("Failed to find the SQL Script list file [" + fullShaderResourcePath + "], no auto update scripts can be run.");
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
// shouldn't happen, but just in case
|
||||
throw new RuntimeException("Unexpected issue closing resource stream for shader type: ["+shaderType+"] at: ["+fullShaderResourcePath+"], error: ["+e.getMessage()+"].", e);
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (shaderType == EDhShaderType.VERTEX)
|
||||
{
|
||||
this.blazePipelineBuilder.withVertexShader(Identifier.parse(NAME_PREFIX + scriptResourcePath));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.blazePipelineBuilder.withFragmentShader(Identifier.parse(NAME_PREFIX + scriptResourcePath));
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//=====//
|
||||
// end //
|
||||
//=====//
|
||||
//region
|
||||
|
||||
public RenderPipeline build() throws UnsupportedOperationException
|
||||
{
|
||||
// depth/color
|
||||
{
|
||||
#if MC_VER <= MC_1_21_11
|
||||
|
||||
this.blazePipelineBuilder.withDepthWrite(this.writeDepth);
|
||||
this.blazePipelineBuilder.withColorWrite(this.writeColor);
|
||||
|
||||
if (this.blendFunction != null)
|
||||
{
|
||||
this.blazePipelineBuilder.withBlend(this.blendFunction);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.blazePipelineBuilder.withoutBlend();
|
||||
}
|
||||
|
||||
DepthTestFunction depthTestFunction;
|
||||
switch (this.depthTest)
|
||||
{
|
||||
case NONE:
|
||||
depthTestFunction = DepthTestFunction.NO_DEPTH_TEST;
|
||||
break;
|
||||
case LESS:
|
||||
depthTestFunction = DepthTestFunction.LESS_DEPTH_TEST;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new UnsupportedOperationException("No depth test defined for type ["+this.depthTest+"].");
|
||||
}
|
||||
this.blazePipelineBuilder.withDepthTestFunction(depthTestFunction);
|
||||
|
||||
#else
|
||||
|
||||
CompareOp compareOp;
|
||||
switch (this.depthTest)
|
||||
{
|
||||
case NONE:
|
||||
compareOp = CompareOp.ALWAYS_PASS;
|
||||
break;
|
||||
case LESS:
|
||||
compareOp = CompareOp.LESS_THAN;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new UnsupportedOperationException("No depth test defined for type ["+this.depthTest+"].");
|
||||
}
|
||||
this.blazePipelineBuilder.withDepthStencilState(new DepthStencilState(compareOp, this.writeDepth));
|
||||
|
||||
this.blazePipelineBuilder.withColorTargetState(
|
||||
new ColorTargetState(
|
||||
Optional.ofNullable(this.blendFunction),
|
||||
this.writeColor ? ColorTargetState.WRITE_ALL : ColorTargetState.WRITE_NONE
|
||||
)
|
||||
);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// vertex format
|
||||
{
|
||||
VertexFormat.Mode blazeVertexMode;
|
||||
switch (this.vertexMode)
|
||||
{
|
||||
case TRIANGLES:
|
||||
blazeVertexMode = VertexFormat.Mode.TRIANGLES;
|
||||
break;
|
||||
case TRIANGLE_FAN:
|
||||
blazeVertexMode = VertexFormat.Mode.TRIANGLE_FAN;
|
||||
break;
|
||||
case LINES:
|
||||
blazeVertexMode = VertexFormat.Mode.DEBUG_LINES;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new UnsupportedOperationException("No vertex mode defined for type ["+this.vertexMode+"].");
|
||||
}
|
||||
|
||||
this.blazePipelineBuilder.withVertexFormat(vertexFormat, blazeVertexMode);
|
||||
}
|
||||
|
||||
|
||||
// uniform buffers
|
||||
{
|
||||
#if MC_VER <= MC_26_1_2
|
||||
// handled before this point
|
||||
#else
|
||||
|
||||
BindGroupLayout.Builder bindGroupBuilder = BindGroupLayout.builder();
|
||||
|
||||
for (String name : this.samplerNames)
|
||||
{
|
||||
bindGroupBuilder.withSampler(name);
|
||||
}
|
||||
|
||||
for (String name : this.uniformBufferNames)
|
||||
{
|
||||
bindGroupBuilder.withUniform(name, UniformType.UNIFORM_BUFFER);
|
||||
}
|
||||
|
||||
BindGroupLayout bindGroup = bindGroupBuilder.build();
|
||||
this.blazePipelineBuilder.withBindGroupLayout(bindGroup);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
return this.blazePipelineBuilder.build();
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// helper methods //
|
||||
//================//
|
||||
//region
|
||||
|
||||
private static boolean isValidIdentifier(String identifier)
|
||||
{
|
||||
for (int i = 0; i < identifier.length(); i++)
|
||||
{
|
||||
char ch = identifier.charAt(i);
|
||||
if (!isValidNamespaceChar(ch))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
private static boolean isValidNamespaceChar(final char ch)
|
||||
{
|
||||
return ch == '_'
|
||||
|| ch == '-'
|
||||
// only lower case characters
|
||||
|| (ch >= 'a' && ch <= 'z')
|
||||
|| (ch >= '0' && ch <= '9')
|
||||
|| ch == '.';
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// helper classes //
|
||||
//================//
|
||||
//region
|
||||
|
||||
public enum EDhPolygonMode
|
||||
{
|
||||
FILL,
|
||||
WIREFRAME;
|
||||
}
|
||||
|
||||
public enum EDhVertexMode
|
||||
{
|
||||
TRIANGLES,
|
||||
TRIANGLE_FAN,
|
||||
LINES;
|
||||
}
|
||||
|
||||
public enum EDhDepthTest
|
||||
{
|
||||
NONE,
|
||||
LESS;
|
||||
}
|
||||
|
||||
private enum EDhShaderType
|
||||
{
|
||||
FRAGMENT(".fsh"),
|
||||
VERTEX(".vsh");
|
||||
|
||||
|
||||
public final String fileExtension;
|
||||
|
||||
EDhShaderType(String fileExtension)
|
||||
{
|
||||
this.fileExtension = fileExtension;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
}
|
||||
#endif
|
||||
+214
@@ -0,0 +1,214 @@
|
||||
package com.seibel.distanthorizons.common.render.blaze.wrappers.buffer;
|
||||
|
||||
#if MC_VER <= MC_1_21_10
|
||||
public class BlazeVertexBufferWrapper {}
|
||||
|
||||
#else
|
||||
|
||||
import com.mojang.blaze3d.buffers.GpuBuffer;
|
||||
import com.mojang.blaze3d.buffers.GpuBufferSlice;
|
||||
import com.mojang.blaze3d.systems.CommandEncoder;
|
||||
import com.mojang.blaze3d.systems.GpuDevice;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.IndexBufferBuilder;
|
||||
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodQuadBuilder;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.render.RenderThreadTaskHandler;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IVertexBufferWrapper;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class BlazeVertexBufferWrapper implements IVertexBufferWrapper
|
||||
{
|
||||
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||
|
||||
private static final AbstractDhRenderApiDefinition RENDER_DEF = SingletonInjector.INSTANCE.get(AbstractDhRenderApiDefinition.class);
|
||||
|
||||
private static final GpuDevice GPU_DEVICE = RenderSystem.getDevice();
|
||||
private static final CommandEncoder COMMAND_ENCODER = GPU_DEVICE.createCommandEncoder();
|
||||
|
||||
private static final AtomicInteger BUFFER_COUNT_REF = new AtomicInteger(0);
|
||||
|
||||
|
||||
public final String name;
|
||||
public String getName() { return this.name; }
|
||||
|
||||
public GpuBuffer vertexGpuBuffer = null;
|
||||
|
||||
public int vertexCount = -1;
|
||||
public int indexCount = -1;
|
||||
public boolean uploaded = false;
|
||||
|
||||
|
||||
private GpuBuffer indexGpuBuffer = null;
|
||||
private static GpuBuffer GLOBAL_INDEX_GPU_BUFFER = null;
|
||||
public GpuBuffer getIndexGpuBuffer()
|
||||
{
|
||||
if (RENDER_DEF.useSingleIbo())
|
||||
{
|
||||
return GLOBAL_INDEX_GPU_BUFFER;
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.indexGpuBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
//region
|
||||
|
||||
static
|
||||
{
|
||||
if (RENDER_DEF.useSingleIbo())
|
||||
{
|
||||
RenderThreadTaskHandler.INSTANCE.queueRunningOnRenderThread("Global IBO Creation", () ->
|
||||
{
|
||||
int maxSize = LodQuadBuilder.getMaxBufferByteSize();
|
||||
int maxVertexCount = maxSize / LodQuadBuilder.BYTES_PER_VERTEX;
|
||||
int maxQuadCount = (maxVertexCount / 4);
|
||||
ByteBuffer indexBuffer = IndexBufferBuilder.createBuffer(maxQuadCount);
|
||||
|
||||
int usage = GpuBuffer.USAGE_COPY_DST
|
||||
| GpuBuffer.USAGE_INDEX;
|
||||
GLOBAL_INDEX_GPU_BUFFER = GPU_DEVICE.createBuffer(BlazeVertexBufferWrapper::getIndexBufferName, usage, indexBuffer.capacity());
|
||||
|
||||
GpuBufferSlice bufferSlice = new GpuBufferSlice(GLOBAL_INDEX_GPU_BUFFER, /*offset*/ 0, indexBuffer.capacity());
|
||||
COMMAND_ENCODER.writeToBuffer(bufferSlice, indexBuffer);
|
||||
|
||||
MemoryUtil.memFree(indexBuffer);
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public BlazeVertexBufferWrapper(String name) { this.name = name; }
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//========//
|
||||
// upload //
|
||||
//========//
|
||||
//region
|
||||
|
||||
@Override
|
||||
public void uploadVertexBuffer(ByteBuffer vertexBuffer, int vertexCount)
|
||||
{
|
||||
int oldVertexCount = this.vertexCount;
|
||||
|
||||
this.vertexCount = vertexCount;
|
||||
// 4 vertices per face, but 6 indices (IE 2 triangles) per face, aka need to multiply by 1.5
|
||||
this.indexCount = (int)(vertexCount * 1.5);
|
||||
this.uploaded = true;
|
||||
|
||||
|
||||
|
||||
if (this.vertexGpuBuffer == null
|
||||
// recreating if the size changes is always necessary (even if we only need a smaller amount)
|
||||
// due to a bug on Mac where it will attempt to render anything allocated in the buffer
|
||||
|| oldVertexCount != vertexCount)
|
||||
{
|
||||
if (this.vertexGpuBuffer == null)
|
||||
{
|
||||
BUFFER_COUNT_REF.incrementAndGet();
|
||||
//LOGGER.info("Create, count: ["+BUFFER_COUNT_REF.get()+"]");
|
||||
}
|
||||
|
||||
if (this.vertexGpuBuffer != null)
|
||||
{
|
||||
this.vertexGpuBuffer.close();
|
||||
}
|
||||
|
||||
int usage = GpuBuffer.USAGE_COPY_DST
|
||||
| GpuBuffer.USAGE_VERTEX;
|
||||
int byteSize = (vertexBuffer.limit() - vertexBuffer.position());
|
||||
this.vertexGpuBuffer = GPU_DEVICE.createBuffer(this::getName, usage, byteSize);
|
||||
|
||||
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.vertexGpuBuffer, /*offset*/0, byteSize);
|
||||
COMMAND_ENCODER.writeToBuffer(bufferSlice, vertexBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uploadIndexBuffer(ByteBuffer indexBuffer, int vertexCount)
|
||||
{
|
||||
int oldIndexCount = this.indexCount;
|
||||
// 4 vertices per face, but 6 indices (IE 2 triangles) per face, aka need to multiply by 1.5
|
||||
this.indexCount = (int)(vertexCount * 1.5);
|
||||
|
||||
if (RENDER_DEF.useSingleIbo())
|
||||
{
|
||||
// ignore index uploading when running a single IBO
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// recreating if the size changes is always necessary (even if we only need a smaller amount)
|
||||
// due to a bug on Mac where it will attempt to render anything allocated in the buffer
|
||||
if (this.indexGpuBuffer == null
|
||||
|| oldIndexCount != this.indexCount)
|
||||
{
|
||||
if (this.indexGpuBuffer == null)
|
||||
{
|
||||
BUFFER_COUNT_REF.incrementAndGet();
|
||||
}
|
||||
|
||||
if (this.indexGpuBuffer != null)
|
||||
{
|
||||
this.indexGpuBuffer.close();
|
||||
}
|
||||
|
||||
int usage = GpuBuffer.USAGE_COPY_DST
|
||||
| GpuBuffer.USAGE_INDEX;
|
||||
this.indexGpuBuffer = GPU_DEVICE.createBuffer(BlazeVertexBufferWrapper::getIndexBufferName, usage, indexBuffer.capacity());
|
||||
|
||||
GpuBufferSlice bufferSlice = new GpuBufferSlice(this.indexGpuBuffer, /*offset*/ 0, indexBuffer.capacity());
|
||||
COMMAND_ENCODER.writeToBuffer(bufferSlice, indexBuffer);
|
||||
}
|
||||
}
|
||||
private static String getIndexBufferName() { return "distantHorizons:LodIndexBuffer"; }
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// base overrides //
|
||||
//================//
|
||||
//region
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
if (this.vertexGpuBuffer != null)
|
||||
{
|
||||
BUFFER_COUNT_REF.decrementAndGet();
|
||||
this.vertexGpuBuffer.close();
|
||||
}
|
||||
|
||||
if (this.indexGpuBuffer != null)
|
||||
{
|
||||
BUFFER_COUNT_REF.decrementAndGet();
|
||||
this.indexGpuBuffer.close();
|
||||
}
|
||||
|
||||
//LOGGER.info("Close, count: ["+BUFFER_COUNT_REF.get()+"]");
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
}
|
||||
#endif
|
||||
+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
|
||||
+206
@@ -0,0 +1,206 @@
|
||||
package com.seibel.distanthorizons.common.render.blaze.wrappers.texture;
|
||||
|
||||
#if MC_VER <= MC_1_21_10
|
||||
public class BlazeTextureWrapper {}
|
||||
|
||||
#else
|
||||
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.coreapi.util.ColorUtil;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||
|
||||
import java.util.OptionalDouble;
|
||||
|
||||
import com.mojang.blaze3d.systems.CommandEncoder;
|
||||
import com.mojang.blaze3d.systems.GpuDevice;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.mojang.blaze3d.textures.*;
|
||||
|
||||
#if MC_VER <= MC_26_1_2
|
||||
|
||||
#else
|
||||
import com.mojang.blaze3d.GpuFormat;
|
||||
#endif
|
||||
|
||||
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;
|
||||
#if MC_VER <= MC_26_1_2
|
||||
public final TextureFormat textureFormat;
|
||||
#else
|
||||
public final GpuFormat textureFormat;
|
||||
#endif
|
||||
|
||||
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)
|
||||
{
|
||||
#if MC_VER <= MC_26_1_2
|
||||
return new BlazeTextureWrapper(name, TextureFormat.DEPTH32);
|
||||
#else
|
||||
return new BlazeTextureWrapper(name, GpuFormat.D32_FLOAT);
|
||||
#endif
|
||||
}
|
||||
public static BlazeTextureWrapper createColor(String name)
|
||||
{
|
||||
#if MC_VER <= MC_26_1_2
|
||||
return new BlazeTextureWrapper(name, TextureFormat.RGBA8);
|
||||
#else
|
||||
return new BlazeTextureWrapper(name, GpuFormat.RGBA8_UNORM);
|
||||
#endif
|
||||
}
|
||||
|
||||
private BlazeTextureWrapper(
|
||||
String name,
|
||||
#if MC_VER <= MC_26_1_2 TextureFormat #else GpuFormat #endif textureFormat
|
||||
)
|
||||
{
|
||||
this.name = name;
|
||||
this.textureFormat = textureFormat;
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//=========//
|
||||
// getters //
|
||||
//=========//
|
||||
//region
|
||||
|
||||
public boolean isEmpty() { return this.texture == null; }
|
||||
|
||||
/** @return -1 if the texture is null */
|
||||
public int getWidth() { return this.width; }
|
||||
/** @return -1 if the texture is null */
|
||||
public int getHeight() { return this.height; }
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//=======//
|
||||
// setup //
|
||||
//=======//
|
||||
//region
|
||||
|
||||
/**
|
||||
* does nothing if the texture is already created and the correct size
|
||||
* @return true if the texture was (re)created
|
||||
*/
|
||||
public boolean tryCreateOrResize()
|
||||
{
|
||||
boolean textureChanged = this.tryCreateTexture();
|
||||
this.tryCreateSampler();
|
||||
return textureChanged;
|
||||
}
|
||||
private boolean tryCreateTexture()
|
||||
{
|
||||
int viewWidth = MC_RENDER.getTargetFramebufferViewportWidth();
|
||||
int viewHeight = MC_RENDER.getTargetFramebufferViewportHeight();
|
||||
|
||||
if (this.texture != null
|
||||
&& this.width == viewWidth
|
||||
&& this.height == viewHeight)
|
||||
{
|
||||
// no changes needed
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (this.texture != null)
|
||||
{
|
||||
this.texture.close();
|
||||
this.textureView.close();
|
||||
}
|
||||
|
||||
this.width = viewWidth;
|
||||
this.height = viewHeight;
|
||||
|
||||
int usage = GpuTexture.USAGE_COPY_DST
|
||||
| GpuTexture.USAGE_TEXTURE_BINDING
|
||||
| GpuTexture.USAGE_COPY_SRC
|
||||
| GpuTexture.USAGE_RENDER_ATTACHMENT;
|
||||
|
||||
this.texture = GPU_DEVICE.createTexture(
|
||||
this.name,
|
||||
usage,
|
||||
this.textureFormat,
|
||||
viewWidth, viewHeight,
|
||||
/*depthOrLayers*/ 1, /*mipLevels*/ 1
|
||||
);
|
||||
this.textureView = GPU_DEVICE.createTextureView(this.texture);
|
||||
|
||||
return true;
|
||||
}
|
||||
private void tryCreateSampler()
|
||||
{
|
||||
if (this.textureSampler == null)
|
||||
{
|
||||
this.textureSampler = GPU_DEVICE.createSampler(
|
||||
AddressMode.CLAMP_TO_EDGE, AddressMode.CLAMP_TO_EDGE, // U,V
|
||||
FilterMode.LINEAR, FilterMode.LINEAR, // minFilter, magFilter
|
||||
1, // maxAnisotropy
|
||||
OptionalDouble.empty() // maxLod
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//==========//
|
||||
// clearing //
|
||||
//==========//
|
||||
//region
|
||||
|
||||
/**
|
||||
* Will throw an exception if not a color texture.
|
||||
* @see ColorUtil#argbToInt
|
||||
*/
|
||||
public void clearColor(int clearArgbColor)
|
||||
{
|
||||
if (this.texture != null)
|
||||
{
|
||||
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
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
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
|
||||
|
||||
|
||||
|
||||
//========//
|
||||
// upload //
|
||||
//========//
|
||||
//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.GLIndexBuffer;
|
||||
import com.seibel.distanthorizons.common.render.openGl.glObject.buffer.GLVertexBuffer;
|
||||
import com.seibel.distanthorizons.common.render.openGl.glObject.shader.GlShaderProgram;
|
||||
import com.seibel.distanthorizons.common.render.openGl.glObject.vertexAttribute.GlAbstractVertexAttribute;
|
||||
import com.seibel.distanthorizons.common.render.openGl.glObject.vertexAttribute.GlVertexPointer;
|
||||
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.render.RenderParams;
|
||||
import com.seibel.distanthorizons.core.render.renderer.AbstractDebugWireframeRenderer;
|
||||
import com.seibel.distanthorizons.core.util.math.Mat4f;
|
||||
import org.lwjgl.opengl.GL32;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
/**
|
||||
* Handles rendering the wireframe particles
|
||||
* that are used for seeing what the system's doing.
|
||||
*/
|
||||
public class GlDhDebugWireframeRenderer extends AbstractDebugWireframeRenderer
|
||||
{
|
||||
public static GlDhDebugWireframeRenderer INSTANCE = new GlDhDebugWireframeRenderer();
|
||||
|
||||
public static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||
|
||||
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
|
||||
|
||||
|
||||
|
||||
// rendering setup
|
||||
private GlShaderProgram basicShader;
|
||||
private GLVertexBuffer vertexBuffer;
|
||||
private GLIndexBuffer indexBuffer;
|
||||
private GlAbstractVertexAttribute va;
|
||||
private boolean init = false;
|
||||
|
||||
|
||||
|
||||
/** A box from 0,0,0 to 1,1,1 */
|
||||
private static final float[] BOX_VERTICES = {
|
||||
//region
|
||||
// Pos x y z
|
||||
0, 0, 0,
|
||||
1, 0, 0,
|
||||
1, 1, 0,
|
||||
0, 1, 0,
|
||||
0, 0, 1,
|
||||
1, 0, 1,
|
||||
1, 1, 1,
|
||||
0, 1, 1,
|
||||
//endregion
|
||||
};
|
||||
|
||||
private static final int[] BOX_OUTLINE_INDICES = {
|
||||
//region
|
||||
0, 1,
|
||||
1, 2,
|
||||
2, 3,
|
||||
3, 0,
|
||||
|
||||
4, 5,
|
||||
5, 6,
|
||||
6, 7,
|
||||
7, 4,
|
||||
|
||||
0, 4,
|
||||
1, 5,
|
||||
2, 6,
|
||||
3, 7,
|
||||
//endregion
|
||||
};
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
//region
|
||||
|
||||
private GlDhDebugWireframeRenderer() { }
|
||||
|
||||
public void init()
|
||||
{
|
||||
if (this.init)
|
||||
{
|
||||
return;
|
||||
}
|
||||
this.init = true;
|
||||
|
||||
this.va = GlAbstractVertexAttribute.create();
|
||||
this.va.bind();
|
||||
// Pos
|
||||
this.va.setVertexAttribute(0, 0, GlVertexPointer.addVec3Pointer(false));
|
||||
this.va.completeAndCheck(Float.BYTES * 3);
|
||||
this.basicShader = new GlShaderProgram(
|
||||
"assets/distanthorizons/shaders/debug/gl/vert.vert",
|
||||
"assets/distanthorizons/shaders/debug/gl/frag.frag",
|
||||
"vPosition"
|
||||
);
|
||||
this.createBuffer();
|
||||
}
|
||||
|
||||
private void createBuffer()
|
||||
{
|
||||
// box vertices
|
||||
ByteBuffer boxVerticesBuffer = ByteBuffer.allocateDirect(BOX_VERTICES.length * Float.BYTES);
|
||||
boxVerticesBuffer.order(ByteOrder.nativeOrder());
|
||||
boxVerticesBuffer.asFloatBuffer().put(BOX_VERTICES);
|
||||
boxVerticesBuffer.rewind();
|
||||
this.vertexBuffer = new GLVertexBuffer(false);
|
||||
this.vertexBuffer.bind();
|
||||
this.vertexBuffer.uploadBuffer(boxVerticesBuffer, 8, EDhApiGpuUploadMethod.DATA, BOX_VERTICES.length * Float.BYTES);
|
||||
|
||||
|
||||
// outline vertex indexes
|
||||
ByteBuffer boxOutlineBuffer = ByteBuffer.allocateDirect(BOX_OUTLINE_INDICES.length * Integer.BYTES);
|
||||
boxOutlineBuffer.order(ByteOrder.nativeOrder());
|
||||
boxOutlineBuffer.asIntBuffer().put(BOX_OUTLINE_INDICES);
|
||||
boxOutlineBuffer.rewind();
|
||||
this.indexBuffer = new GLIndexBuffer(false);
|
||||
this.indexBuffer.uploadBuffer(boxOutlineBuffer, EDhApiGpuUploadMethod.DATA, BOX_OUTLINE_INDICES.length * Integer.BYTES, GL32.GL_STATIC_DRAW);
|
||||
|
||||
}
|
||||
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//===========//
|
||||
// rendering //
|
||||
//===========//
|
||||
//region
|
||||
|
||||
@Override
|
||||
public void render(RenderParams renderParams)
|
||||
{
|
||||
this.init();
|
||||
|
||||
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_LINE);
|
||||
GLMC.enableDepthTest();
|
||||
|
||||
this.basicShader.bind();
|
||||
this.va.bind();
|
||||
this.va.bindBufferToAllBindingPoints(this.vertexBuffer.getId());
|
||||
|
||||
this.indexBuffer.bind();
|
||||
|
||||
super.render(renderParams);
|
||||
|
||||
// revert to prevent issues with the following passes
|
||||
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_FILL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderBox(Box box)
|
||||
{
|
||||
Mat4f boxTransform = Mat4f.createTranslateMatrix(box.minPos.x - this.camPosFloatThisFrame.x, box.minPos.y - this.camPosFloatThisFrame.y, box.minPos.z - this.camPosFloatThisFrame.z);
|
||||
boxTransform.multiply(Mat4f.createScaleMatrix(box.maxPos.x - box.minPos.x, box.maxPos.y - box.minPos.y, box.maxPos.z - box.minPos.z));
|
||||
|
||||
Mat4f transformMatrix = this.dhMvmProjMatrixThisFrame.copy();
|
||||
transformMatrix.multiply(boxTransform);
|
||||
this.basicShader.setUniform(this.basicShader.getUniformLocation("uTransform"), transformMatrix);
|
||||
|
||||
this.basicShader.setUniform(this.basicShader.getUniformLocation("uColor"), box.color);
|
||||
|
||||
GL32.glDrawElements(GL32.GL_LINES, BOX_OUTLINE_INDICES.length, GL32.GL_UNSIGNED_INT, 0);
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
}
|
||||
+465
@@ -0,0 +1,465 @@
|
||||
package com.seibel.distanthorizons.common.render.openGl;
|
||||
|
||||
import com.seibel.distanthorizons.api.enums.rendering.EDhApiRenderPass;
|
||||
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiFramebuffer;
|
||||
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiShaderProgram;
|
||||
import com.seibel.distanthorizons.api.methods.events.abstractEvents.*;
|
||||
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
|
||||
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiTextureCreatedParam;
|
||||
import com.seibel.distanthorizons.common.render.openGl.glObject.GLProxy;
|
||||
import com.seibel.distanthorizons.common.render.openGl.glObject.GlDhFramebuffer;
|
||||
import com.seibel.distanthorizons.common.render.openGl.glObject.texture.*;
|
||||
import com.seibel.distanthorizons.common.render.openGl.postProcessing.apply.GlDhApplyShader;
|
||||
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.misc.LightMapWrapper;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.render.DhApiRenderProxy;
|
||||
import com.seibel.distanthorizons.core.render.RenderParams;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.ILightMapWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IOptifineAccessor;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhMetaRenderer;
|
||||
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
|
||||
import com.seibel.distanthorizons.coreapi.DependencyInjection.OverrideInjector;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.lwjgl.opengl.GL32;
|
||||
|
||||
public class GlDhMetaRenderer implements IDhMetaRenderer
|
||||
{
|
||||
public static final DhLogger LOGGER = new DhLoggerBuilder()
|
||||
.fileLevelConfig(Config.Common.Logging.logRendererEventToFile)
|
||||
.build();
|
||||
|
||||
public static final DhLogger RATE_LIMITED_LOGGER = new DhLoggerBuilder()
|
||||
.fileLevelConfig(Config.Common.Logging.logRendererEventToFile)
|
||||
.maxCountPerSecond(4)
|
||||
.build();
|
||||
|
||||
public static final GlDhMetaRenderer INSTANCE = new GlDhMetaRenderer();
|
||||
|
||||
|
||||
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
|
||||
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
|
||||
|
||||
private static final IOptifineAccessor OPTIFINE_ACCESSOR = ModAccessorInjector.INSTANCE.get(IOptifineAccessor.class);
|
||||
|
||||
|
||||
private int activeFramebufferId = -1;
|
||||
private int activeColorTextureId = -1;
|
||||
private int activeDepthTextureId = -1;
|
||||
private int textureWidth;
|
||||
private int textureHeight;
|
||||
|
||||
|
||||
// framebuffer and texture ID's for this renderer
|
||||
private IDhApiFramebuffer framebuffer;
|
||||
/** will be null if MC's framebuffer is being used since MC already has a color texture */
|
||||
@Nullable
|
||||
private GlDhColorTexture nullableColorTexture;
|
||||
private GlDhDepthTexture depthTexture;
|
||||
/**
|
||||
* If true the {@link GlDhMetaRenderer#framebuffer} is the same as MC's.
|
||||
* This should only be true in the case of Optifine so LODs won't be overwritten when shaders are enabled.
|
||||
*/
|
||||
private boolean usingMcFramebuffer = false;
|
||||
|
||||
private boolean renderObjectsCreated = false;
|
||||
/** used in case there's an API override */
|
||||
public IDhApiShaderProgram shaderProgramForThisFrame;
|
||||
|
||||
|
||||
|
||||
//============//
|
||||
// pre render //
|
||||
//============//
|
||||
//region
|
||||
|
||||
@Override
|
||||
public void runRenderPassSetup(RenderParams renderParams)
|
||||
{
|
||||
boolean firstPass =
|
||||
(renderParams.renderPass == EDhApiRenderPass.OPAQUE
|
||||
|| renderParams.renderPass == EDhApiRenderPass.OPAQUE_AND_TRANSPARENT);
|
||||
|
||||
if (!this.renderObjectsCreated)
|
||||
{
|
||||
boolean setupSuccess = this.createRenderObjects();
|
||||
if (!setupSuccess)
|
||||
{
|
||||
// shouldn't normally happen, but just in case
|
||||
return;
|
||||
}
|
||||
|
||||
this.renderObjectsCreated = true;
|
||||
}
|
||||
|
||||
this.shaderProgramForThisFrame = GlDhTerrainRenderer.INSTANCE.getTerrainShaderProgram();
|
||||
IDhApiShaderProgram lodShaderProgramOverride = OverrideInjector.INSTANCE.get(IDhApiShaderProgram.class);
|
||||
if (lodShaderProgramOverride != null && this.shaderProgramForThisFrame.overrideThisFrame())
|
||||
{
|
||||
this.shaderProgramForThisFrame = lodShaderProgramOverride;
|
||||
}
|
||||
|
||||
|
||||
this.setGLState(renderParams, firstPass);
|
||||
|
||||
this.bindLightmap(renderParams.lightmap);
|
||||
}
|
||||
private void setGLState(
|
||||
DhApiRenderParam renderEventParam,
|
||||
boolean firstPass)
|
||||
{
|
||||
//===================//
|
||||
// framebuffer setup //
|
||||
//===================//
|
||||
|
||||
// get the active framebuffer
|
||||
IDhApiFramebuffer framebuffer = this.framebuffer;
|
||||
IDhApiFramebuffer framebufferOverride = OverrideInjector.INSTANCE.get(IDhApiFramebuffer.class);
|
||||
if (framebufferOverride != null && framebufferOverride.overrideThisFrame())
|
||||
{
|
||||
framebuffer = framebufferOverride;
|
||||
}
|
||||
this.setActiveFramebufferId(framebuffer.getId());
|
||||
framebuffer.bind();
|
||||
|
||||
|
||||
|
||||
//==========//
|
||||
// bindings //
|
||||
//==========//
|
||||
|
||||
// by default draw everything as triangles
|
||||
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_FILL);
|
||||
GLMC.enableFaceCulling();
|
||||
|
||||
GLMC.glBlendFunc(GL32.GL_SRC_ALPHA, GL32.GL_ONE_MINUS_SRC_ALPHA);
|
||||
GLMC.glBlendFuncSeparate(GL32.GL_SRC_ALPHA, GL32.GL_ONE_MINUS_SRC_ALPHA, GL32.GL_ONE, GL32.GL_ZERO);
|
||||
|
||||
GL32.glDisable(GL32.GL_SCISSOR_TEST);
|
||||
|
||||
// Enable depth test and depth mask
|
||||
GLMC.enableDepthTest();
|
||||
GLMC.glDepthFunc(GL32.GL_LESS);
|
||||
GLMC.enableDepthMask();
|
||||
|
||||
// This is required for MC versions 1.21.5+
|
||||
// due to MC updating the lightmap by changing the viewport size
|
||||
GL32.glViewport(0, 0, this.textureWidth, this.textureHeight);
|
||||
|
||||
this.shaderProgramForThisFrame.bind();
|
||||
|
||||
|
||||
|
||||
//==========//
|
||||
// uniforms //
|
||||
//==========//
|
||||
|
||||
IDhApiShaderProgram shaderProgramOverride = OverrideInjector.INSTANCE.get(IDhApiShaderProgram.class);
|
||||
if (shaderProgramOverride != null)
|
||||
{
|
||||
shaderProgramOverride.fillUniformData(renderEventParam);
|
||||
}
|
||||
|
||||
this.shaderProgramForThisFrame.fillUniformData(renderEventParam);
|
||||
|
||||
|
||||
|
||||
//===============//
|
||||
// texture setup //
|
||||
//===============//
|
||||
|
||||
// resize the textures if needed
|
||||
if (MC_RENDER.getTargetFramebufferViewportWidth() != this.textureWidth
|
||||
|| MC_RENDER.getTargetFramebufferViewportHeight() != this.textureHeight)
|
||||
{
|
||||
// just resizing the textures doesn't work when Optifine is present,
|
||||
// so recreate the textures with the new size instead
|
||||
this.createAndBindTextures();
|
||||
}
|
||||
|
||||
|
||||
// set the active textures
|
||||
int depthTextureId = this.depthTexture.getTextureId();
|
||||
this.setActiveDepthTextureId(depthTextureId);
|
||||
|
||||
if (this.nullableColorTexture != null)
|
||||
{
|
||||
int colorTextureId = this.nullableColorTexture.getTextureId();
|
||||
this.setActiveColorTextureId(colorTextureId);
|
||||
}
|
||||
else
|
||||
{
|
||||
// get MC's color texture
|
||||
int colorTextureId = GL32.glGetFramebufferAttachmentParameteri(GL32.GL_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
|
||||
this.setActiveColorTextureId(colorTextureId);
|
||||
}
|
||||
|
||||
|
||||
// needs to be fired after all the textures have been created/bound
|
||||
boolean clearTextures = !ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeTextureClearEvent.class, renderEventParam);
|
||||
if (clearTextures)
|
||||
{
|
||||
GL32.glClearDepth(1.0);
|
||||
|
||||
float[] clearColorValues = new float[4];
|
||||
GL32.glGetFloatv(GL32.GL_COLOR_CLEAR_VALUE, clearColorValues);
|
||||
GL32.glClearColor(clearColorValues[0], clearColorValues[1], clearColorValues[2], 1.0f);
|
||||
|
||||
if (this.usingMcFramebuffer && framebufferOverride == null)
|
||||
{
|
||||
// Due to using MC/Optifine's framebuffer we need to re-bind the depth texture,
|
||||
// otherwise we'll be writing to MC/Optifine's depth texture which causes rendering issues
|
||||
framebuffer.addDepthAttachment(this.depthTexture.getTextureId(), EGlDhDepthBufferFormat.DEPTH32F.isCombinedStencil());
|
||||
|
||||
|
||||
// don't clear the color texture, that removes the sky
|
||||
GL32.glClear(GL32.GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
else if (firstPass)
|
||||
{
|
||||
GL32.glClear(GL32.GL_COLOR_BUFFER_BIT | GL32.GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean createRenderObjects()
|
||||
{
|
||||
if (this.renderObjectsCreated)
|
||||
{
|
||||
LOGGER.warn("Renderer setup called but it has already completed setup!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// GLProxy should have already been created by this point, but just in case create it now
|
||||
GLProxy.getInstance();
|
||||
|
||||
|
||||
|
||||
LOGGER.info("Setting up renderer");
|
||||
|
||||
|
||||
// create or get the frame buffer
|
||||
if (OPTIFINE_ACCESSOR != null)
|
||||
{
|
||||
// use MC/Optifine's default Framebuffer so shaders won't remove the LODs
|
||||
int currentFramebufferId = MC_RENDER.getTargetFramebuffer();
|
||||
this.framebuffer = new GlDhFramebuffer(currentFramebufferId);
|
||||
this.usingMcFramebuffer = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// normal use case
|
||||
this.framebuffer = new GlDhFramebuffer();
|
||||
this.usingMcFramebuffer = false;
|
||||
}
|
||||
|
||||
// create and bind the necessary textures
|
||||
this.createAndBindTextures();
|
||||
|
||||
if(this.framebuffer.getStatus() != GL32.GL_FRAMEBUFFER_COMPLETE)
|
||||
{
|
||||
// This generally means something wasn't bound, IE missing either the color or depth texture
|
||||
LOGGER.warn("Framebuffer ["+this.framebuffer.getId()+"] isn't complete.");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
LOGGER.info("Renderer setup complete");
|
||||
return true;
|
||||
}
|
||||
|
||||
@SuppressWarnings( "deprecation" ) // done to ignore DhApiColorDepthTextureCreatedEvent
|
||||
private void createAndBindTextures()
|
||||
{
|
||||
int oldWidth = this.textureWidth;
|
||||
int oldHeight = this.textureHeight;
|
||||
this.textureWidth = MC_RENDER.getTargetFramebufferViewportWidth();
|
||||
this.textureHeight = MC_RENDER.getTargetFramebufferViewportHeight();
|
||||
|
||||
DhApiTextureCreatedParam textureCreatedParam = new DhApiTextureCreatedParam(
|
||||
oldWidth, oldHeight,
|
||||
this.textureWidth, this.textureHeight
|
||||
);
|
||||
|
||||
|
||||
// DhApiColorDepthTextureCreatedEvent needs to be kept around since old versions of Iris need it
|
||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiColorDepthTextureCreatedEvent.class, new DhApiColorDepthTextureCreatedEvent.EventParam(textureCreatedParam));
|
||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeColorDepthTextureCreatedEvent.class, textureCreatedParam);
|
||||
|
||||
|
||||
// also update the framebuffer override if present
|
||||
IDhApiFramebuffer framebufferOverride = OverrideInjector.INSTANCE.get(IDhApiFramebuffer.class);
|
||||
|
||||
|
||||
this.depthTexture = new GlDhDepthTexture(this.textureWidth, this.textureHeight, EGlDhDepthBufferFormat.DEPTH32F);
|
||||
this.framebuffer.addDepthAttachment(this.depthTexture.getTextureId(), EGlDhDepthBufferFormat.DEPTH32F.isCombinedStencil());
|
||||
if (framebufferOverride != null)
|
||||
{
|
||||
framebufferOverride.addDepthAttachment(this.depthTexture.getTextureId(), EGlDhDepthBufferFormat.DEPTH32F.isCombinedStencil());
|
||||
}
|
||||
|
||||
|
||||
// if we are using MC's frame buffer, a color texture is already present and shouldn't need to be bound
|
||||
if (!this.usingMcFramebuffer)
|
||||
{
|
||||
this.nullableColorTexture = GlDhColorTexture.builder()
|
||||
.setDimensions(this.textureWidth, this.textureHeight)
|
||||
.setInternalFormat(EGlDhInternalTextureFormat.RGBA8)
|
||||
.setPixelType(EGlDhPixelType.UNSIGNED_BYTE)
|
||||
.setPixelFormat(EGlDhPixelFormat.RGBA)
|
||||
.build();
|
||||
|
||||
this.framebuffer.addColorAttachment(0, this.nullableColorTexture.getTextureId());
|
||||
if (framebufferOverride != null)
|
||||
{
|
||||
framebufferOverride.addColorAttachment(0, this.nullableColorTexture.getTextureId());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.nullableColorTexture = null;
|
||||
}
|
||||
|
||||
|
||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiAfterColorDepthTextureCreatedEvent.class, textureCreatedParam);
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// post render //
|
||||
//=============//
|
||||
//region
|
||||
|
||||
@Override
|
||||
public void runRenderPassCleanup(RenderParams renderParams)
|
||||
{
|
||||
boolean runningDeferredPass = (renderParams.renderPass == EDhApiRenderPass.TRANSPARENT);
|
||||
if (!runningDeferredPass)
|
||||
{
|
||||
//===================//
|
||||
// optifine clean up //
|
||||
//===================//
|
||||
|
||||
if (this.usingMcFramebuffer)
|
||||
{
|
||||
// If MC's framebuffer is being used the depth needs to be cleared to prevent rendering on top of MC.
|
||||
// This should only happen when Optifine shaders are being used.
|
||||
GL32.glClear(GL32.GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
this.unbindLightmap();
|
||||
this.shaderProgramForThisFrame.unbind();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyToMcTexture(RenderParams renderParams) { GlDhApplyShader.INSTANCE.render(renderParams); }
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// clear textures //
|
||||
//================//
|
||||
//region
|
||||
|
||||
@Override
|
||||
public void clearDhDepthAndColorTextures(RenderParams renderParams)
|
||||
{
|
||||
IDhApiFramebuffer framebufferOverride = OverrideInjector.INSTANCE.get(IDhApiFramebuffer.class);
|
||||
|
||||
boolean firstPass =
|
||||
(renderParams.renderPass == EDhApiRenderPass.OPAQUE
|
||||
|| renderParams.renderPass == EDhApiRenderPass.OPAQUE_AND_TRANSPARENT);
|
||||
|
||||
|
||||
|
||||
GL32.glClearDepth(1.0);
|
||||
|
||||
float[] clearColorValues = new float[4];
|
||||
GL32.glGetFloatv(GL32.GL_COLOR_CLEAR_VALUE, clearColorValues);
|
||||
GL32.glClearColor(clearColorValues[0], clearColorValues[1], clearColorValues[2], 1.0f);
|
||||
|
||||
if (this.usingMcFramebuffer
|
||||
&& framebufferOverride == null)
|
||||
{
|
||||
//// Due to using MC/Optifine's framebuffer we need to re-bind the depth texture,
|
||||
//// otherwise we'll be writing to MC/Optifine's depth texture which causes rendering issues
|
||||
//this.framebuffer.addDepthAttachment(this.depthTexture.getTextureId(), EDhDepthBufferFormat.DEPTH32F.isCombinedStencil());
|
||||
|
||||
|
||||
// don't clear the color texture, that removes the sky
|
||||
GL32.glClear(GL32.GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
else if (firstPass)
|
||||
{
|
||||
GL32.glClear(GL32.GL_COLOR_BUFFER_BIT | GL32.GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//===============//
|
||||
// API functions //
|
||||
//===============//
|
||||
//region
|
||||
|
||||
public void setActiveFramebufferId(int id) { this.activeFramebufferId = id; }
|
||||
/** @return -1 if no frame buffer has been bound yet */
|
||||
public int getActiveFramebufferId() { return this.activeFramebufferId; }
|
||||
|
||||
public void setActiveColorTextureId(int id)
|
||||
{
|
||||
this.activeColorTextureId = id;
|
||||
DhApiRenderProxy.activeOpenGlDhColorTextureId = id;
|
||||
}
|
||||
/** @return -1 if no texture has been bound yet */
|
||||
public int getActiveColorTextureId() { return this.activeColorTextureId; }
|
||||
|
||||
public void setActiveDepthTextureId(int id)
|
||||
{
|
||||
this.activeDepthTextureId = id;
|
||||
DhApiRenderProxy.activeOpenGlDhDepthTextureId = id;
|
||||
}
|
||||
/** @return -1 if no texture has been bound yet */
|
||||
public int getActiveDepthTextureId() { return this.activeDepthTextureId; }
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
//================//
|
||||
// helper methods //
|
||||
//================//
|
||||
//region
|
||||
|
||||
public void bindLightmap(ILightMapWrapper lightMapWrapper)
|
||||
{
|
||||
LightMapWrapper lightMap = (LightMapWrapper)lightMapWrapper;
|
||||
GLMC.glActiveTexture(GL32.GL_TEXTURE0 + LightMapWrapper.GL_BOUND_INDEX);
|
||||
GLMC.glBindTexture(lightMap.getOpenGlId());
|
||||
}
|
||||
|
||||
public void unbindLightmap()
|
||||
{
|
||||
// strange that we don't call "glActiveTexture" here but since it's working James isn't going to change it right now (2026-03-10)
|
||||
GLMC.glBindTexture(0);
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
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.terrain.GlDhTerrainShaderProgram;
|
||||
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 GlDhTerrainRenderer.INSTANCE; }
|
||||
@Override public IDhSsaoRenderer getSsaoRenderer() { return GlDhSSAORenderer.INSTANCE; }
|
||||
@Override public IDhFogRenderer getFogRenderer() { return GlDhFogRenderer.INSTANCE; }
|
||||
@Override public IDhFarFadeRenderer getFarFadeRenderer() { return GlDhFarFadeRenderer.INSTANCE; }
|
||||
@Override public AbstractDebugWireframeRenderer getDebugWireframeRenderer() { return GlDhDebugWireframeRenderer.INSTANCE; }
|
||||
|
||||
@Override public IDhVanillaFadeRenderer getVanillaFadeRenderer() { return GlVanillaFadeRenderer.INSTANCE; }
|
||||
@Override public IDhTestTriangleRenderer getTestTriangleRenderer() { return GlTestTriangleRenderer.INSTANCE; }
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//===========//
|
||||
// factories //
|
||||
//===========//
|
||||
//region
|
||||
|
||||
@Override public IDhGenericRenderer createGenericRenderer() { return new GlGenericObjectRenderer(); }
|
||||
|
||||
@Override public IVertexBufferWrapper createVboWrapper(String name) { return new GLVertexBuffer(); }
|
||||
@Override public ILodContainerUniformBufferWrapper createLodContainerUniformWrapper() { return new GlDummyUniformData(); }
|
||||
@Override public IDhGenericObjectVertexBufferContainer createGenericVboContainer() { return new GlGenericObjectVertexContainer(); }
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
package com.seibel.distanthorizons.common.render.openGl;
|
||||
|
||||
import com.seibel.distanthorizons.common.render.openGl.terrain.GlDhTerrainShaderProgram;
|
||||
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodBufferContainer;
|
||||
import com.seibel.distanthorizons.core.render.RenderParams;
|
||||
import com.seibel.distanthorizons.core.util.objects.SortedArraySet;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IProfilerWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhTerrainRenderer;
|
||||
|
||||
public class GlDhTerrainRenderer implements IDhTerrainRenderer
|
||||
{
|
||||
public static final GlDhTerrainRenderer INSTANCE = new GlDhTerrainRenderer();
|
||||
|
||||
private GlDhTerrainShaderProgram terrainShaderProgram = null;
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
//region
|
||||
|
||||
private GlDhTerrainRenderer() {}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
//=========//
|
||||
// getters //
|
||||
//=========//
|
||||
//region
|
||||
|
||||
/** must be called on the render thread the first time so GL can run it's setup */
|
||||
public GlDhTerrainShaderProgram getTerrainShaderProgram()
|
||||
{
|
||||
if (this.terrainShaderProgram == null)
|
||||
{
|
||||
this.terrainShaderProgram = new GlDhTerrainShaderProgram();
|
||||
}
|
||||
|
||||
return this.terrainShaderProgram;
|
||||
}
|
||||
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//========//
|
||||
// render //
|
||||
//========//
|
||||
//region
|
||||
|
||||
@Override
|
||||
public void render(RenderParams renderEventParam, boolean opaquePass, SortedArraySet<LodBufferContainer> bufferContainers, IProfilerWrapper profiler)
|
||||
{
|
||||
this.getTerrainShaderProgram();
|
||||
|
||||
this.terrainShaderProgram.tryInit();
|
||||
this.terrainShaderProgram.render(renderEventParam, opaquePass, bufferContainers, profiler);
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
}
|
||||
+774
@@ -0,0 +1,774 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.common.render.openGl.generic;
|
||||
|
||||
import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod;
|
||||
import com.seibel.distanthorizons.api.enums.rendering.EDhApiBlockMaterial;
|
||||
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiGenericObjectShaderProgram;
|
||||
import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderableBoxGroup;
|
||||
import com.seibel.distanthorizons.api.interfaces.render.IDhApiCustomRenderRegister;
|
||||
import com.seibel.distanthorizons.api.methods.events.abstractEvents.*;
|
||||
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
|
||||
import com.seibel.distanthorizons.api.objects.math.DhApiVec3d;
|
||||
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox;
|
||||
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBoxGroupShading;
|
||||
import com.seibel.distanthorizons.common.render.openGl.glObject.GLProxy;
|
||||
import com.seibel.distanthorizons.common.render.openGl.glObject.buffer.GLIndexBuffer;
|
||||
import com.seibel.distanthorizons.common.render.openGl.glObject.buffer.GLVertexBuffer;
|
||||
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.jar.EPlatform;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.logging.f3.F3Screen;
|
||||
import com.seibel.distanthorizons.core.render.RenderParams;
|
||||
import com.seibel.distanthorizons.core.render.renderer.GenericRenderObjectFactory;
|
||||
import com.seibel.distanthorizons.core.render.renderer.RenderableBoxGroup;
|
||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IProfilerWrapper;
|
||||
import com.seibel.distanthorizons.core.util.math.Vec3d;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhGenericRenderer;
|
||||
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
|
||||
import com.seibel.distanthorizons.coreapi.DependencyInjection.OverrideInjector;
|
||||
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||
import org.lwjgl.opengl.ARBInstancedArrays;
|
||||
import org.lwjgl.opengl.GL32;
|
||||
import org.lwjgl.opengl.GL33;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import java.awt.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Handles rendering generic groups of {@link DhApiRenderableBox}.
|
||||
*
|
||||
* @see IDhApiCustomRenderRegister
|
||||
* @see DhApiRenderableBox
|
||||
*/
|
||||
public class GlGenericObjectRenderer implements IDhGenericRenderer
|
||||
{
|
||||
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||
|
||||
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
|
||||
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
|
||||
|
||||
private static final DhApiRenderableBoxGroupShading DEFAULT_SHADING = DhApiRenderableBoxGroupShading.getUnshaded();
|
||||
|
||||
|
||||
/**
|
||||
* Can be used to troubleshoot the renderer.
|
||||
* If enabled several debug objects will render around (0,150,0).
|
||||
*/
|
||||
public static final boolean RENDER_DEBUG_OBJECTS = false;
|
||||
|
||||
|
||||
// rendering setup
|
||||
private boolean init = false;
|
||||
|
||||
private IDhApiGenericObjectShaderProgram instancedShaderProgram;
|
||||
private IDhApiGenericObjectShaderProgram directShaderProgram;
|
||||
private GLVertexBuffer boxVertexBuffer;
|
||||
private GLIndexBuffer boxIndexBuffer;
|
||||
|
||||
private boolean instancedRenderingAvailable;
|
||||
private boolean vertexAttribDivisorSupported;
|
||||
private boolean instancedArraysSupported;
|
||||
|
||||
|
||||
|
||||
private final ConcurrentHashMap<Long, RenderableBoxGroup> boxGroupById = new ConcurrentHashMap<>();
|
||||
|
||||
|
||||
|
||||
/** A box from 0,0,0 to 1,1,1 */
|
||||
private static final float[] BOX_VERTICES = {
|
||||
//region
|
||||
// Pos x y z
|
||||
|
||||
// min X, vertical face
|
||||
0, 0, 0,
|
||||
1, 0, 0,
|
||||
1, 1, 0,
|
||||
0, 1, 0,
|
||||
// max X, vertical face
|
||||
0, 1, 1,
|
||||
1, 1, 1,
|
||||
1, 0, 1,
|
||||
0, 0, 1,
|
||||
|
||||
// min Z, vertical face
|
||||
0, 0, 1,
|
||||
0, 0, 0,
|
||||
0, 1, 0,
|
||||
0, 1, 1,
|
||||
// max Z, vertical face
|
||||
1, 0, 1,
|
||||
1, 1, 1,
|
||||
1, 1, 0,
|
||||
1, 0, 0,
|
||||
|
||||
// min Y, horizontal face
|
||||
0, 0, 1,
|
||||
1, 0, 1,
|
||||
1, 0, 0,
|
||||
0, 0, 0,
|
||||
// max Y, horizontal face
|
||||
0, 1, 1,
|
||||
1, 1, 1,
|
||||
1, 1, 0,
|
||||
0, 1, 0,
|
||||
//endregion
|
||||
};
|
||||
|
||||
|
||||
private static final int[] BOX_INDICES = {
|
||||
//region
|
||||
// min X, vertical face
|
||||
2, 1, 0,
|
||||
0, 3, 2,
|
||||
// max X, vertical face
|
||||
6, 5, 4,
|
||||
4, 7, 6,
|
||||
|
||||
// min Z, vertical face
|
||||
10, 9, 8,
|
||||
8, 11, 10,
|
||||
// max Z, vertical face
|
||||
14, 13, 12,
|
||||
12, 15, 14,
|
||||
|
||||
// min Y, horizontal face
|
||||
18, 17, 16,
|
||||
16, 19, 18,
|
||||
// max Y, horizontal face
|
||||
20, 21, 22,
|
||||
22, 23, 20,
|
||||
//endregion
|
||||
};
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
//region
|
||||
|
||||
public GlGenericObjectRenderer() { }
|
||||
|
||||
public void init()
|
||||
{
|
||||
if (this.init)
|
||||
{
|
||||
return;
|
||||
}
|
||||
this.init = true;
|
||||
|
||||
|
||||
|
||||
//===================================//
|
||||
// is instanced rendering available? //
|
||||
//===================================//
|
||||
|
||||
this.vertexAttribDivisorSupported = GLProxy.getInstance().vertexAttribDivisorSupported;
|
||||
this.instancedArraysSupported = GLProxy.getInstance().instancedArraysSupported;
|
||||
boolean isMac = (EPlatform.get() == EPlatform.MACOS);
|
||||
if (isMac)
|
||||
{
|
||||
LOGGER.warn("Generic rendering not supported by Mac. Clouds, beacons, and some other effects will be disabled.");
|
||||
Config.Client.Advanced.Graphics.GenericRendering.enableGenericRendering.setApiValue(false);
|
||||
return;
|
||||
}
|
||||
|
||||
this.instancedRenderingAvailable = (this.vertexAttribDivisorSupported || this.instancedArraysSupported) && !isMac;
|
||||
if (!this.instancedRenderingAvailable)
|
||||
{
|
||||
LOGGER.warn("Instanced rendering not supported by this GPU, falling back to direct rendering. Generic object rendering will be slow and some effects may be disabled.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
//======================//
|
||||
// startup the renderer //
|
||||
//======================//
|
||||
|
||||
this.instancedShaderProgram = new GlGenericObjectShaderProgram(true);
|
||||
this.directShaderProgram = new GlGenericObjectShaderProgram(false);
|
||||
|
||||
this.createBuffers();
|
||||
|
||||
if (RENDER_DEBUG_OBJECTS)
|
||||
{
|
||||
this.addGenericDebugObjects();
|
||||
}
|
||||
}
|
||||
private void createBuffers()
|
||||
{
|
||||
// box vertices
|
||||
ByteBuffer boxVerticesBuffer = MemoryUtil.memAlloc(BOX_VERTICES.length * Float.BYTES);
|
||||
boxVerticesBuffer.asFloatBuffer().put(BOX_VERTICES);
|
||||
boxVerticesBuffer.rewind();
|
||||
this.boxVertexBuffer = new GLVertexBuffer(false);
|
||||
this.boxVertexBuffer.bind();
|
||||
this.boxVertexBuffer.uploadBuffer(boxVerticesBuffer, 8, EDhApiGpuUploadMethod.DATA, BOX_VERTICES.length * Float.BYTES);
|
||||
MemoryUtil.memFree(boxVerticesBuffer);
|
||||
|
||||
// box vertex indexes
|
||||
ByteBuffer solidIndexBuffer = MemoryUtil.memAlloc(BOX_INDICES.length * Integer.BYTES);
|
||||
solidIndexBuffer.asIntBuffer().put(BOX_INDICES);
|
||||
solidIndexBuffer.rewind();
|
||||
this.boxIndexBuffer = new GLIndexBuffer(false);
|
||||
this.boxIndexBuffer.uploadBuffer(solidIndexBuffer, EDhApiGpuUploadMethod.DATA, BOX_INDICES.length * Integer.BYTES, GL32.GL_STATIC_DRAW);
|
||||
this.boxIndexBuffer.bind();
|
||||
MemoryUtil.memFree(solidIndexBuffer);
|
||||
}
|
||||
private void addGenericDebugObjects()
|
||||
{
|
||||
GenericRenderObjectFactory factory = GenericRenderObjectFactory.INSTANCE;
|
||||
|
||||
|
||||
// single giant box
|
||||
IDhApiRenderableBoxGroup singleGiantBoxGroup = factory.createForSingleBox(
|
||||
ModInfo.NAME + ":CyanChunkBox",
|
||||
new DhApiRenderableBox(
|
||||
new DhApiVec3d(0,0,0), new DhApiVec3d(16,190,16),
|
||||
new Color(Color.CYAN.getRed(), Color.CYAN.getGreen(), Color.CYAN.getBlue(), 125),
|
||||
EDhApiBlockMaterial.WATER)
|
||||
);
|
||||
singleGiantBoxGroup.setSkyLight(LodUtil.MAX_MC_LIGHT);
|
||||
singleGiantBoxGroup.setBlockLight(LodUtil.MAX_MC_LIGHT);
|
||||
this.add(singleGiantBoxGroup);
|
||||
|
||||
|
||||
// single slender box
|
||||
IDhApiRenderableBoxGroup singleTallBoxGroup = factory.createForSingleBox(
|
||||
ModInfo.NAME + ":GreenBeacon",
|
||||
new DhApiRenderableBox(
|
||||
new DhApiVec3d(16,0,31), new DhApiVec3d(17,2000,32),
|
||||
new Color(Color.GREEN.getRed(), Color.GREEN.getGreen(), Color.GREEN.getBlue(), 125),
|
||||
EDhApiBlockMaterial.ILLUMINATED)
|
||||
);
|
||||
singleTallBoxGroup.setSkyLight(LodUtil.MAX_MC_LIGHT);
|
||||
singleTallBoxGroup.setBlockLight(LodUtil.MAX_MC_LIGHT);
|
||||
this.add(singleTallBoxGroup);
|
||||
|
||||
|
||||
// absolute box group
|
||||
ArrayList<DhApiRenderableBox> absBoxList = new ArrayList<>();
|
||||
for (int i = 0; i < 18; i++)
|
||||
{
|
||||
absBoxList.add(new DhApiRenderableBox(
|
||||
new DhApiVec3d(i,150+i,24), new DhApiVec3d(1+i,151+i,25),
|
||||
new Color(Color.ORANGE.getRed(), Color.ORANGE.getGreen(), Color.ORANGE.getBlue()),
|
||||
EDhApiBlockMaterial.LAVA
|
||||
)
|
||||
);
|
||||
}
|
||||
IDhApiRenderableBoxGroup absolutePosBoxGroup = factory.createAbsolutePositionedGroup(ModInfo.NAME + ":OrangeStairs", absBoxList);
|
||||
this.add(absolutePosBoxGroup);
|
||||
|
||||
|
||||
// relative box group
|
||||
ArrayList<DhApiRenderableBox> relBoxList = new ArrayList<>();
|
||||
for (int i = 0; i < 8; i+=2)
|
||||
{
|
||||
relBoxList.add(new DhApiRenderableBox(
|
||||
new DhApiVec3d(0,i,0), new DhApiVec3d(1,1+i,1),
|
||||
new Color(Color.MAGENTA.getRed(), Color.MAGENTA.getGreen(), Color.MAGENTA.getBlue()),
|
||||
EDhApiBlockMaterial.METAL
|
||||
)
|
||||
);
|
||||
}
|
||||
IDhApiRenderableBoxGroup relativePosBoxGroup = factory.createRelativePositionedGroup(
|
||||
ModInfo.NAME + ":MovingMagentaGroup",
|
||||
new DhApiVec3d(24, 140, 24),
|
||||
relBoxList);
|
||||
relativePosBoxGroup.setPreRenderFunc((event) ->
|
||||
{
|
||||
DhApiVec3d pos = relativePosBoxGroup.getOriginBlockPos();
|
||||
pos.x += event.partialTicks / 2;
|
||||
pos.x %= 32;
|
||||
relativePosBoxGroup.setOriginBlockPos(pos);
|
||||
});
|
||||
this.add(relativePosBoxGroup);
|
||||
|
||||
|
||||
// massive relative box group
|
||||
ArrayList<DhApiRenderableBox> massRelBoxList = new ArrayList<>();
|
||||
for (int x = 0; x < 50*2; x+=2)
|
||||
{
|
||||
for (int z = 0; z < 50*2; z+=2)
|
||||
{
|
||||
massRelBoxList.add(new DhApiRenderableBox(
|
||||
new DhApiVec3d(-x, 0, -z), new DhApiVec3d(1-x, 1, 1-z),
|
||||
new Color(Color.RED.getRed(), Color.RED.getGreen(), Color.RED.getBlue()),
|
||||
EDhApiBlockMaterial.TERRACOTTA
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
IDhApiRenderableBoxGroup massRelativePosBoxGroup = factory.createRelativePositionedGroup(
|
||||
ModInfo.NAME + ":MassRedGroup",
|
||||
new DhApiVec3d(-25, 140, 0),
|
||||
massRelBoxList);
|
||||
massRelativePosBoxGroup.setPreRenderFunc((event) ->
|
||||
{
|
||||
DhApiVec3d blockPos = massRelativePosBoxGroup.getOriginBlockPos();
|
||||
blockPos.y += event.partialTicks / 4;
|
||||
if (blockPos.y > 150f)
|
||||
{
|
||||
blockPos.y = 140f;
|
||||
|
||||
Color newColor = (massRelativePosBoxGroup.get(0).color == Color.RED) ? Color.RED.darker() : Color.RED;
|
||||
massRelativePosBoxGroup.forEach((box) -> { box.color = newColor; });
|
||||
massRelativePosBoxGroup.triggerBoxChange();
|
||||
}
|
||||
|
||||
massRelativePosBoxGroup.setOriginBlockPos(blockPos);
|
||||
});
|
||||
this.add(massRelativePosBoxGroup);
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// registration //
|
||||
//==============//
|
||||
//region
|
||||
|
||||
@Override
|
||||
public void add(IDhApiRenderableBoxGroup iBoxGroup) throws IllegalArgumentException
|
||||
{
|
||||
if (!(iBoxGroup instanceof RenderableBoxGroup))
|
||||
{
|
||||
throw new IllegalArgumentException("Box group must be of type ["+ RenderableBoxGroup.class.getSimpleName()+"], type received: ["+(iBoxGroup != null ? iBoxGroup.getClass() : "NULL")+"].");
|
||||
}
|
||||
RenderableBoxGroup boxGroup = (RenderableBoxGroup) iBoxGroup;
|
||||
if (boxGroup.size() != 0)
|
||||
{
|
||||
// trigger a box change to make sure the initial data is uploaded
|
||||
boxGroup.triggerBoxChange();
|
||||
}
|
||||
|
||||
|
||||
long id = boxGroup.getId();
|
||||
if (this.boxGroupById.containsKey(id))
|
||||
{
|
||||
throw new IllegalArgumentException("A box group with the ID [" + id + "] is already present.");
|
||||
}
|
||||
|
||||
this.boxGroupById.put(id, boxGroup);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IDhApiRenderableBoxGroup remove(long id) { return this.boxGroupById.remove(id); }
|
||||
|
||||
public void clear() { this.boxGroupById.clear(); }
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//===========//
|
||||
// rendering //
|
||||
//===========//
|
||||
//region
|
||||
|
||||
/**
|
||||
* @param renderingWithSsao
|
||||
* if true that means this render call is happening before the SSAO pass
|
||||
* and any objects rendered in this pass will have SSAO applied to them.
|
||||
*/
|
||||
@Override
|
||||
public void render(RenderParams renderEventParam, IProfilerWrapper profiler, boolean renderingWithSsao)
|
||||
{
|
||||
// generic rendering (both instanced and direct) is extremely unstable on Mac, so don't render anything
|
||||
if (EPlatform.get() == EPlatform.MACOS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// render setup //
|
||||
try (IProfilerWrapper.IProfileBlock setup_profile = profiler.push("setup"))
|
||||
{
|
||||
|
||||
this.init();
|
||||
|
||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericRenderSetupEvent.class, renderEventParam);
|
||||
|
||||
|
||||
boolean renderWireframe = Config.Client.Advanced.Debugging.renderWireframe.get();
|
||||
if (renderWireframe)
|
||||
{
|
||||
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_LINE);
|
||||
GLMC.disableFaceCulling();
|
||||
}
|
||||
else
|
||||
{
|
||||
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_FILL);
|
||||
GLMC.enableFaceCulling();
|
||||
}
|
||||
|
||||
GLMC.enableBlend();
|
||||
GL32.glBlendEquation(GL32.GL_FUNC_ADD);
|
||||
GLMC.glBlendFuncSeparate(GL32.GL_SRC_ALPHA, GL32.GL_ONE_MINUS_SRC_ALPHA, GL32.GL_ONE, GL32.GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
IDhApiGenericObjectShaderProgram shaderProgram = this.instancedRenderingAvailable ? this.instancedShaderProgram : this.directShaderProgram;
|
||||
IDhApiGenericObjectShaderProgram shaderProgramOverride = OverrideInjector.INSTANCE.get(IDhApiGenericObjectShaderProgram.class);
|
||||
if (shaderProgramOverride != null && shaderProgram.overrideThisFrame())
|
||||
{
|
||||
shaderProgram = shaderProgramOverride;
|
||||
}
|
||||
|
||||
shaderProgram.bind(renderEventParam);
|
||||
shaderProgram.bindVertexBuffer(this.boxVertexBuffer.getId());
|
||||
|
||||
this.boxIndexBuffer.bind();
|
||||
|
||||
Vec3d camPos = MC_RENDER.getCameraExactPosition();
|
||||
|
||||
|
||||
|
||||
// rendering //
|
||||
|
||||
Collection<RenderableBoxGroup> boxList = this.boxGroupById.values();
|
||||
for (RenderableBoxGroup boxGroup : boxList)
|
||||
{
|
||||
// validation //
|
||||
|
||||
// shouldn't happen, but just in case
|
||||
if (boxGroup == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// skip boxes that shouldn't render this pass
|
||||
if (boxGroup.ssaoEnabled != renderingWithSsao)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
profiler.popPush("render prep");
|
||||
boxGroup.preRender(renderEventParam); // called even if the group is inactive, so the group can be activate if desired
|
||||
|
||||
// ignore inactive groups
|
||||
if (!boxGroup.active)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// allow API users to cancel this object's rendering
|
||||
boolean cancelRendering = ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericObjectRenderEvent.class, new DhApiBeforeGenericObjectRenderEvent.EventParam(renderEventParam, boxGroup));
|
||||
if (cancelRendering)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// update instanced data if needed
|
||||
if (this.instancedRenderingAvailable)
|
||||
{
|
||||
boxGroup.tryUpdateInstancedDataAsync();
|
||||
|
||||
// skip groups that haven't been uploaded yet
|
||||
if (boxGroup.vertexBufferContainer.getState() != GlGenericObjectVertexContainer.EState.RENDER)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// render //
|
||||
|
||||
profiler.popPush("rendering");
|
||||
try (IProfilerWrapper.IProfileBlock namespace_profile = profiler.push(boxGroup.getResourceLocationNamespace());
|
||||
IProfilerWrapper.IProfileBlock location_profile = profiler.push(boxGroup.getResourceLocationPath()))
|
||||
{
|
||||
if (this.instancedRenderingAvailable)
|
||||
{
|
||||
this.renderBoxGroupInstanced(shaderProgram, renderEventParam, boxGroup, camPos, profiler);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.renderBoxGroupDirect(shaderProgram, renderEventParam, boxGroup, camPos, profiler);
|
||||
}
|
||||
}
|
||||
|
||||
boxGroup.postRender(renderEventParam);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//==========//
|
||||
// clean up //
|
||||
//==========//
|
||||
|
||||
profiler.popPush("cleanup");
|
||||
|
||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeGenericRenderCleanupEvent.class, renderEventParam);
|
||||
|
||||
if (renderWireframe)
|
||||
{
|
||||
// default back to GL_FILL since all other rendering uses it
|
||||
GL32.glPolygonMode(GL32.GL_FRONT_AND_BACK, GL32.GL_FILL);
|
||||
GLMC.enableFaceCulling();
|
||||
}
|
||||
|
||||
shaderProgram.unbind();
|
||||
}
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//=====================//
|
||||
// instanced rendering //
|
||||
//=====================//
|
||||
//region
|
||||
|
||||
private void renderBoxGroupInstanced(
|
||||
IDhApiGenericObjectShaderProgram shaderProgram, DhApiRenderParam renderEventParam,
|
||||
RenderableBoxGroup boxGroup, Vec3d camPos,
|
||||
IProfilerWrapper profiler)
|
||||
{
|
||||
try (IProfilerWrapper.IProfileBlock render_profile = profiler.push("vertex setup"))
|
||||
{
|
||||
|
||||
// update instance data //
|
||||
DhApiRenderableBoxGroupShading shading = boxGroup.shading;
|
||||
if (shading == null)
|
||||
{
|
||||
shading = DEFAULT_SHADING;
|
||||
}
|
||||
|
||||
shaderProgram.fillIndirectUniformData(
|
||||
renderEventParam,
|
||||
shading, boxGroup,
|
||||
camPos);
|
||||
|
||||
|
||||
|
||||
// Bind instance data //
|
||||
profiler.popPush("binding");
|
||||
|
||||
GlGenericObjectVertexContainer container = (GlGenericObjectVertexContainer) (boxGroup.vertexBufferContainer);
|
||||
|
||||
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, container.color);
|
||||
GL32.glEnableVertexAttribArray(1);
|
||||
GL32.glVertexAttribPointer(1, 4, GL32.GL_FLOAT, false, 4 * Float.BYTES, 0);
|
||||
this.vertexAttribDivisor(1, 1);
|
||||
|
||||
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, container.scale);
|
||||
GL32.glEnableVertexAttribArray(2);
|
||||
this.vertexAttribDivisor(2, 1);
|
||||
GL32.glVertexAttribPointer(2, 3, GL32.GL_FLOAT, false, 3 * Float.BYTES, 0);
|
||||
|
||||
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, container.chunkPos);
|
||||
GL32.glEnableVertexAttribArray(3);
|
||||
this.vertexAttribDivisor(3, 1);
|
||||
GL32.glVertexAttribIPointer(3, 3, GL32.GL_INT, 3 * Integer.BYTES, 0);
|
||||
|
||||
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, container.subChunkPos);
|
||||
GL32.glEnableVertexAttribArray(4);
|
||||
this.vertexAttribDivisor(4, 1);
|
||||
GL32.glVertexAttribPointer(4, 3, GL32.GL_FLOAT, false, 3 * Float.BYTES, 0);
|
||||
|
||||
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, container.material);
|
||||
GL32.glEnableVertexAttribArray(5);
|
||||
this.vertexAttribDivisor(5, 1);
|
||||
GL32.glVertexAttribIPointer(5, 1, GL32.GL_BYTE, Byte.BYTES, 0);
|
||||
|
||||
|
||||
// Draw instanced
|
||||
profiler.popPush("render");
|
||||
if (container.uploadedBoxCount > 0)
|
||||
{
|
||||
GL32.glDrawElementsInstanced(GL32.GL_TRIANGLES, BOX_INDICES.length, GL32.GL_UNSIGNED_INT, 0, container.uploadedBoxCount);
|
||||
}
|
||||
|
||||
|
||||
// Clean up
|
||||
profiler.popPush("cleanup");
|
||||
|
||||
GL32.glDisableVertexAttribArray(1);
|
||||
GL32.glDisableVertexAttribArray(2);
|
||||
GL32.glDisableVertexAttribArray(3);
|
||||
GL32.glDisableVertexAttribArray(4);
|
||||
GL32.glDisableVertexAttribArray(5);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Clean way to handle both {@link GL33#glVertexAttribDivisor} and {@link ARBInstancedArrays#glVertexAttribDivisorARB}
|
||||
* based on which one is supported.
|
||||
*/
|
||||
private void vertexAttribDivisor(int index, int divisor)
|
||||
{
|
||||
if (this.vertexAttribDivisorSupported)
|
||||
{
|
||||
GL33.glVertexAttribDivisor(index, divisor);
|
||||
}
|
||||
else if(this.instancedArraysSupported)
|
||||
{
|
||||
ARBInstancedArrays.glVertexAttribDivisorARB(index, divisor);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IllegalStateException("Instanced rendering isn't supported by this machine. Direct rendering should have been used instead.");
|
||||
}
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//==================//
|
||||
// direct rendering //
|
||||
//==================//
|
||||
//region
|
||||
|
||||
private void renderBoxGroupDirect(
|
||||
IDhApiGenericObjectShaderProgram shaderProgram,
|
||||
DhApiRenderParam renderEventParam,
|
||||
RenderableBoxGroup boxGroup, Vec3d camPos,
|
||||
IProfilerWrapper profiler)
|
||||
{
|
||||
profiler.popPush("shared uniforms");
|
||||
DhApiRenderableBoxGroupShading shading = boxGroup.shading;
|
||||
if (shading == null)
|
||||
{
|
||||
shading = DhApiRenderableBoxGroupShading.getUnshaded();
|
||||
}
|
||||
|
||||
shaderProgram.fillSharedDirectUniformData(renderEventParam, shading, boxGroup, camPos);
|
||||
|
||||
for (int i = 0; i < boxGroup.size(); i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
DhApiRenderableBox box = boxGroup.get(i);
|
||||
if (box != null)
|
||||
{
|
||||
profiler.popPush("direct uniforms");
|
||||
shaderProgram.fillDirectUniformData(renderEventParam, boxGroup, box, camPos);
|
||||
|
||||
profiler.popPush("render");
|
||||
GL32.glDrawElements(GL32.GL_TRIANGLES, BOX_INDICES.length, GL32.GL_UNSIGNED_INT, 0);
|
||||
}
|
||||
}
|
||||
catch (IndexOutOfBoundsException e)
|
||||
{
|
||||
// Concurrency issue, the list was modified while rendering
|
||||
// this can probably be ignored.
|
||||
// However, if it does become a problem we can add locks to the box group.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//=========//
|
||||
// getters //
|
||||
//=========//
|
||||
//region
|
||||
|
||||
/** @throws IllegalStateException if {@link #init()} function hasn't been called yet */
|
||||
public boolean getInstancedRenderingAvailable() throws IllegalStateException
|
||||
{
|
||||
if (!this.init)
|
||||
{
|
||||
throw new IllegalStateException("GL initialization hasn't been completed.");
|
||||
}
|
||||
|
||||
return this.instancedRenderingAvailable;
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//=========//
|
||||
// F3 menu //
|
||||
//=========//
|
||||
//region
|
||||
|
||||
public String getVboRenderDebugMenuString()
|
||||
{
|
||||
// get counts
|
||||
int totalGroupCount = this.boxGroupById.size();
|
||||
int totalBoxCount = 0;
|
||||
|
||||
int activeGroupCount = 0;
|
||||
int activeBoxCount = 0;
|
||||
|
||||
for (long key : this.boxGroupById.keySet())
|
||||
{
|
||||
RenderableBoxGroup renderGroup = this.boxGroupById.get(key);
|
||||
if (renderGroup.active)
|
||||
{
|
||||
activeGroupCount++;
|
||||
activeBoxCount += renderGroup.size();
|
||||
}
|
||||
totalBoxCount += renderGroup.size();
|
||||
}
|
||||
|
||||
|
||||
return "Generic Obj #: " + F3Screen.NUMBER_FORMAT.format(activeGroupCount) + "/" + F3Screen.NUMBER_FORMAT.format(totalGroupCount) + ", " +
|
||||
"Cube #: " + F3Screen.NUMBER_FORMAT.format(activeBoxCount) + "/" + F3Screen.NUMBER_FORMAT.format(totalBoxCount);
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// base overrides //
|
||||
//================//
|
||||
//region
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
if (this.boxVertexBuffer != null)
|
||||
{
|
||||
this.boxVertexBuffer.close();
|
||||
}
|
||||
|
||||
if (this.boxIndexBuffer != null)
|
||||
{
|
||||
this.boxIndexBuffer.close();
|
||||
}
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
}
|
||||
+231
@@ -0,0 +1,231 @@
|
||||
package com.seibel.distanthorizons.common.render.openGl.generic;
|
||||
|
||||
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiGenericObjectShaderProgram;
|
||||
import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderableBoxGroup;
|
||||
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
|
||||
import com.seibel.distanthorizons.api.objects.math.DhApiVec3d;
|
||||
import com.seibel.distanthorizons.api.objects.math.DhApiVec3i;
|
||||
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox;
|
||||
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBoxGroupShading;
|
||||
import com.seibel.distanthorizons.common.render.openGl.glObject.shader.GlShaderProgram;
|
||||
import com.seibel.distanthorizons.common.render.openGl.glObject.vertexAttribute.GlAbstractVertexAttribute;
|
||||
import com.seibel.distanthorizons.common.render.openGl.glObject.vertexAttribute.GlVertexPointer;
|
||||
import com.seibel.distanthorizons.common.wrappers.misc.LightMapWrapper;
|
||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
import com.seibel.distanthorizons.core.util.math.Mat4f;
|
||||
import com.seibel.distanthorizons.core.util.math.Vec3f;
|
||||
|
||||
public class GlGenericObjectShaderProgram extends GlShaderProgram implements IDhApiGenericObjectShaderProgram
|
||||
{
|
||||
public static final String VERTEX_SHADER_INSTANCED_PATH = "assets/distanthorizons/shaders/generic/gl/instanced/vert.vert";
|
||||
public static final String VERTEX_SHADER_DIRECT_PATH = "assets/distanthorizons/shaders/generic/gl/direct/vert.vert";
|
||||
public static final String FRAGMENT_SHADER_INSTANCED_PATH = "assets/distanthorizons/shaders/generic/gl/instanced/frag.frag";
|
||||
public static final String FRAGMENT_SHADER_DIRECT_PATH = "assets/distanthorizons/shaders/generic/gl/direct/frag.frag";
|
||||
|
||||
public final GlAbstractVertexAttribute va;
|
||||
|
||||
|
||||
// shader uniforms
|
||||
private final int directShaderTransformUniform;
|
||||
private final int directShaderColorUniform;
|
||||
|
||||
private final int instancedShaderOffsetChunkUniform;
|
||||
private final int instancedShaderOffsetSubChunkUniform;
|
||||
private final int instancedShaderCameraChunkPosUniform;
|
||||
private final int instancedShaderCameraSubChunkPosUniform;
|
||||
private final int instancedShaderProjectionModelViewMatrixUniform;
|
||||
|
||||
private final int lightMapUniform;
|
||||
private final int skyLightUniform;
|
||||
private final int blockLightUniform;
|
||||
|
||||
private final int northShadingUniform;
|
||||
private final int southShadingUniform;
|
||||
private final int eastShadingUniform;
|
||||
private final int westShadingUniform;
|
||||
private final int topShadingUniform;
|
||||
private final int bottomShadingUniform;
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
|
||||
public GlGenericObjectShaderProgram(boolean useInstancedRendering)
|
||||
{
|
||||
super(
|
||||
useInstancedRendering ? VERTEX_SHADER_INSTANCED_PATH : VERTEX_SHADER_DIRECT_PATH,
|
||||
useInstancedRendering ? FRAGMENT_SHADER_INSTANCED_PATH : FRAGMENT_SHADER_DIRECT_PATH,
|
||||
"vPosition"
|
||||
);
|
||||
|
||||
this.va = GlAbstractVertexAttribute.create();
|
||||
this.va.bind();
|
||||
// Pos
|
||||
this.va.setVertexAttribute(0, 0, GlVertexPointer.addVec3Pointer(false));
|
||||
this.va.completeAndCheck(Float.BYTES * 3);
|
||||
|
||||
this.directShaderTransformUniform = this.tryGetUniformLocation("uTransform");
|
||||
this.directShaderColorUniform = this.tryGetUniformLocation("uColor");
|
||||
|
||||
this.instancedShaderOffsetChunkUniform = this.tryGetUniformLocation("uOffsetChunk");
|
||||
this.instancedShaderOffsetSubChunkUniform = this.tryGetUniformLocation("uOffsetSubChunk");
|
||||
this.instancedShaderCameraChunkPosUniform = this.tryGetUniformLocation("uCameraPosChunk");
|
||||
this.instancedShaderCameraSubChunkPosUniform = this.tryGetUniformLocation("uCameraPosSubChunk");
|
||||
this.instancedShaderProjectionModelViewMatrixUniform = this.tryGetUniformLocation("uProjectionMvm");
|
||||
|
||||
this.lightMapUniform = this.getUniformLocation("uLightMap");
|
||||
this.skyLightUniform = this.getUniformLocation("uSkyLight");
|
||||
this.blockLightUniform = this.getUniformLocation("uBlockLight");
|
||||
this.northShadingUniform = this.getUniformLocation("uNorthShading");
|
||||
this.southShadingUniform = this.getUniformLocation("uSouthShading");
|
||||
this.eastShadingUniform = this.getUniformLocation("uEastShading");
|
||||
this.westShadingUniform = this.getUniformLocation("uWestShading");
|
||||
this.topShadingUniform = this.getUniformLocation("uTopShading");
|
||||
this.bottomShadingUniform = this.getUniformLocation("uBottomShading");
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=========//
|
||||
// methods //
|
||||
//=========//
|
||||
|
||||
@Override
|
||||
public void bind(DhApiRenderParam renderEventParam)
|
||||
{
|
||||
super.bind();
|
||||
this.va.bind();
|
||||
}
|
||||
@Override
|
||||
public void unbind()
|
||||
{
|
||||
super.unbind();
|
||||
this.va.unbind();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void free()
|
||||
{
|
||||
this.va.free();
|
||||
super.free();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindVertexBuffer(int vbo) { this.va.bindBufferToAllBindingPoints(vbo); }
|
||||
|
||||
@Override
|
||||
public void fillIndirectUniformData(
|
||||
DhApiRenderParam renderParameters,
|
||||
DhApiRenderableBoxGroupShading shading, IDhApiRenderableBoxGroup boxGroup,
|
||||
DhApiVec3d camPos
|
||||
)
|
||||
{
|
||||
Mat4f projectionMvmMatrix = new Mat4f(renderParameters.dhProjectionMatrix);
|
||||
projectionMvmMatrix.multiply(renderParameters.dhModelViewMatrix);
|
||||
|
||||
super.bind();
|
||||
|
||||
|
||||
|
||||
|
||||
this.setUniform(this.instancedShaderOffsetChunkUniform,
|
||||
new DhApiVec3i(
|
||||
LodUtil.getChunkPosFromDouble(boxGroup.getOriginBlockPos().x),
|
||||
LodUtil.getChunkPosFromDouble(boxGroup.getOriginBlockPos().y),
|
||||
LodUtil.getChunkPosFromDouble(boxGroup.getOriginBlockPos().z)
|
||||
));
|
||||
this.setUniform(this.instancedShaderOffsetSubChunkUniform,
|
||||
new Vec3f(
|
||||
LodUtil.getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().x),
|
||||
LodUtil.getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().y),
|
||||
LodUtil.getSubChunkPosFromDouble(boxGroup.getOriginBlockPos().z)
|
||||
));
|
||||
|
||||
this.setUniform(this.instancedShaderCameraChunkPosUniform,
|
||||
new DhApiVec3i(
|
||||
LodUtil.getChunkPosFromDouble(camPos.x),
|
||||
LodUtil.getChunkPosFromDouble(camPos.y),
|
||||
LodUtil.getChunkPosFromDouble(camPos.z)
|
||||
));
|
||||
this.setUniform(this.instancedShaderCameraSubChunkPosUniform,
|
||||
new Vec3f(
|
||||
LodUtil.getSubChunkPosFromDouble(camPos.x),
|
||||
LodUtil.getSubChunkPosFromDouble(camPos.y),
|
||||
LodUtil.getSubChunkPosFromDouble(camPos.z)
|
||||
));
|
||||
|
||||
this.setUniform(this.instancedShaderProjectionModelViewMatrixUniform, projectionMvmMatrix);
|
||||
|
||||
this.setUniform(this.lightMapUniform, LightMapWrapper.GL_BOUND_INDEX);
|
||||
this.setUniform(this.skyLightUniform, boxGroup.getSkyLight());
|
||||
this.setUniform(this.blockLightUniform, boxGroup.getBlockLight());
|
||||
|
||||
|
||||
this.setUniform(this.northShadingUniform, shading.north);
|
||||
this.setUniform(this.southShadingUniform, shading.south);
|
||||
this.setUniform(this.eastShadingUniform, shading.east);
|
||||
this.setUniform(this.westShadingUniform, shading.west);
|
||||
this.setUniform(this.topShadingUniform, shading.top);
|
||||
this.setUniform(this.bottomShadingUniform, shading.bottom);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void fillSharedDirectUniformData(
|
||||
DhApiRenderParam renderParameters,
|
||||
DhApiRenderableBoxGroupShading shading, IDhApiRenderableBoxGroup boxGroup,
|
||||
DhApiVec3d camPos)
|
||||
{
|
||||
|
||||
this.setUniform(this.lightMapUniform, LightMapWrapper.GL_BOUND_INDEX);
|
||||
this.setUniform(this.skyLightUniform, boxGroup.getSkyLight());
|
||||
this.setUniform(this.blockLightUniform, boxGroup.getBlockLight());
|
||||
|
||||
|
||||
this.setUniform(this.northShadingUniform, shading.north);
|
||||
this.setUniform(this.southShadingUniform, shading.south);
|
||||
this.setUniform(this.eastShadingUniform, shading.east);
|
||||
this.setUniform(this.westShadingUniform, shading.west);
|
||||
this.setUniform(this.topShadingUniform, shading.top);
|
||||
this.setUniform(this.bottomShadingUniform, shading.bottom);
|
||||
|
||||
}
|
||||
|
||||
public void fillDirectUniformData(
|
||||
DhApiRenderParam renderParameters,
|
||||
IDhApiRenderableBoxGroup boxGroup, DhApiRenderableBox box,
|
||||
DhApiVec3d camPos)
|
||||
{
|
||||
Mat4f projectionMvmMatrix = new Mat4f(renderParameters.dhProjectionMatrix);
|
||||
projectionMvmMatrix.multiply(renderParameters.dhModelViewMatrix);
|
||||
|
||||
Mat4f boxTransform = Mat4f.createTranslateMatrix(
|
||||
(float) (box.minPos.x + boxGroup.getOriginBlockPos().x - camPos.x),
|
||||
(float) (box.minPos.y + boxGroup.getOriginBlockPos().y - camPos.y),
|
||||
(float) (box.minPos.z + boxGroup.getOriginBlockPos().z - camPos.z));
|
||||
boxTransform.multiply(Mat4f.createScaleMatrix(
|
||||
(float) (box.maxPos.x - box.minPos.x),
|
||||
(float) (box.maxPos.y - box.minPos.y),
|
||||
(float) (box.maxPos.z - box.minPos.z)));
|
||||
projectionMvmMatrix.multiply(boxTransform);
|
||||
this.setUniform(this.directShaderTransformUniform, projectionMvmMatrix);
|
||||
|
||||
this.setUniform(this.directShaderColorUniform, box.color);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public int getId() { return this.id; }
|
||||
|
||||
/** The base DH render program should always render */
|
||||
@Override
|
||||
public boolean overrideThisFrame() { return true; }
|
||||
|
||||
}
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
package com.seibel.distanthorizons.common.render.openGl.generic;
|
||||
|
||||
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox;
|
||||
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.render.renderer.RenderableBoxGroup;
|
||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IDhGenericObjectVertexBufferContainer;
|
||||
import org.lwjgl.opengl.GL32;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* For use by {@link RenderableBoxGroup}
|
||||
*
|
||||
* @see RenderableBoxGroup
|
||||
*/
|
||||
public class GlGenericObjectVertexContainer implements IDhGenericObjectVertexBufferContainer
|
||||
{
|
||||
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||
|
||||
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
|
||||
|
||||
|
||||
|
||||
public int chunkPos = 0;
|
||||
public int subChunkPos = 0;
|
||||
public int scale = 0;
|
||||
public int color = 0;
|
||||
public int material = 0;
|
||||
|
||||
public int[] chunkPosData = new int[0];
|
||||
public float[] subChunkPosData = new float[0];
|
||||
public float[] scalingData = new float[0];
|
||||
public float[] colorData = new float[0];
|
||||
public int[] materialData = new int[0];
|
||||
|
||||
public int uploadedBoxCount = 0;
|
||||
|
||||
private EState state = EState.NEW;
|
||||
@Override
|
||||
public EState getState() { return this.state; }
|
||||
@Override
|
||||
public void setState(EState state) { this.state = state; }
|
||||
|
||||
|
||||
|
||||
//===========================//
|
||||
// render building/uploading //
|
||||
//===========================//
|
||||
//region
|
||||
|
||||
public void updateVertexData(List<DhApiRenderableBox> uploadBoxList)
|
||||
{
|
||||
int boxCount = uploadBoxList.size();
|
||||
|
||||
|
||||
// recreate the data arrays if their size is different
|
||||
if (this.uploadedBoxCount != boxCount)
|
||||
{
|
||||
this.uploadedBoxCount = boxCount;
|
||||
|
||||
this.chunkPosData = new int[boxCount * 3]; // 3 elements XYZ
|
||||
this.subChunkPosData = new float[boxCount * 3]; // 3 elements XYZ
|
||||
this.scalingData = new float[boxCount * 3]; // 3 elements XYZ
|
||||
|
||||
this.colorData = new float[boxCount * 4]; // 4 elements, RGBA
|
||||
this.materialData = new int[boxCount];
|
||||
}
|
||||
|
||||
|
||||
// transformation / scaling //
|
||||
for (int i = 0; i < boxCount; i++)
|
||||
{
|
||||
DhApiRenderableBox box = uploadBoxList.get(i);
|
||||
|
||||
int dataIndex = i * 3;
|
||||
|
||||
this.chunkPosData[dataIndex] = LodUtil.getChunkPosFromDouble(box.minPos.x);
|
||||
this.chunkPosData[dataIndex + 1] = LodUtil.getChunkPosFromDouble(box.minPos.y);
|
||||
this.chunkPosData[dataIndex + 2] = LodUtil.getChunkPosFromDouble(box.minPos.z);
|
||||
|
||||
this.subChunkPosData[dataIndex] = LodUtil.getSubChunkPosFromDouble(box.minPos.x);
|
||||
this.subChunkPosData[dataIndex + 1] = LodUtil.getSubChunkPosFromDouble(box.minPos.y);
|
||||
this.subChunkPosData[dataIndex + 2] = LodUtil.getSubChunkPosFromDouble(box.minPos.z);
|
||||
|
||||
this.scalingData[dataIndex] = (float) (box.maxPos.x - box.minPos.x);
|
||||
this.scalingData[dataIndex + 1] = (float) (box.maxPos.y - box.minPos.y);
|
||||
this.scalingData[dataIndex + 2] = (float) (box.maxPos.z - box.minPos.z);
|
||||
}
|
||||
|
||||
|
||||
// colors/materials //
|
||||
for (int i = 0; i < boxCount; i++)
|
||||
{
|
||||
DhApiRenderableBox box = uploadBoxList.get(i);
|
||||
Color color = box.color;
|
||||
int colorIndex = i * 4;
|
||||
this.colorData[colorIndex] = color.getRed() / 255.0f;
|
||||
this.colorData[colorIndex + 1] = color.getGreen() / 255.0f;
|
||||
this.colorData[colorIndex + 2] = color.getBlue() / 255.0f;
|
||||
this.colorData[colorIndex + 3] = color.getAlpha() / 255.0f;
|
||||
|
||||
this.materialData[i] = box.material;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uploadDataToGpu()
|
||||
{
|
||||
this.tryCreateBuffers();
|
||||
|
||||
// Upload transformation matrices
|
||||
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.chunkPos);
|
||||
GL32.glBufferData(GL32.GL_ARRAY_BUFFER, this.chunkPosData, GL32.GL_DYNAMIC_DRAW);
|
||||
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.subChunkPos);
|
||||
GL32.glBufferData(GL32.GL_ARRAY_BUFFER, this.subChunkPosData, GL32.GL_DYNAMIC_DRAW);
|
||||
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.scale);
|
||||
GL32.glBufferData(GL32.GL_ARRAY_BUFFER, this.scalingData, GL32.GL_DYNAMIC_DRAW);
|
||||
|
||||
// Upload colors
|
||||
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.color);
|
||||
GL32.glBufferData(GL32.GL_ARRAY_BUFFER, this.colorData, GL32.GL_DYNAMIC_DRAW);
|
||||
|
||||
// Upload materials
|
||||
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, this.material);
|
||||
GL32.glBufferData(GL32.GL_ARRAY_BUFFER, this.materialData, GL32.GL_DYNAMIC_DRAW);
|
||||
}
|
||||
/** needs to be done on the render thread */
|
||||
private void tryCreateBuffers()
|
||||
{
|
||||
if (this.chunkPos == 0)
|
||||
{
|
||||
this.chunkPos = GLMC.glGenBuffers();
|
||||
this.subChunkPos = GLMC.glGenBuffers();
|
||||
this.scale = GLMC.glGenBuffers();
|
||||
this.color = GLMC.glGenBuffers();
|
||||
this.material = GLMC.glGenBuffers();
|
||||
}
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// base overrides //
|
||||
//================//
|
||||
//region
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
tryDeleteBuffer(this.chunkPos);
|
||||
tryDeleteBuffer(this.subChunkPos);
|
||||
tryDeleteBuffer(this.scale);
|
||||
tryDeleteBuffer(this.color);
|
||||
tryDeleteBuffer(this.material);
|
||||
}
|
||||
private static void tryDeleteBuffer(int bufferId)
|
||||
{
|
||||
// usually unnecessary, but just in case
|
||||
if (bufferId != 0)
|
||||
{
|
||||
GLMC.glDeleteBuffers(bufferId);
|
||||
}
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
+371
@@ -0,0 +1,371 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.common.render.openGl.glObject;
|
||||
|
||||
import com.seibel.distanthorizons.api.enums.config.EDhApiGLErrorHandlingMode;
|
||||
import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod;
|
||||
import com.seibel.distanthorizons.api.enums.config.EDhApiLoggerLevel;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.config.types.ConfigEntry;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.jar.EPlatform;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.util.objects.GLMessages.*;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IIrisAccessor;
|
||||
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
import org.lwjgl.opengl.GL;
|
||||
import org.lwjgl.opengl.GL32;
|
||||
import org.lwjgl.opengl.GLCapabilities;
|
||||
import org.lwjgl.opengl.GLUtil;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* A singleton that holds references to different openGL contexts
|
||||
* and GPU capabilities.
|
||||
*/
|
||||
public class GLProxy
|
||||
{
|
||||
private static final IIrisAccessor IRIS_ACCESSOR = ModAccessorInjector.INSTANCE.get(IIrisAccessor.class);
|
||||
|
||||
public static final DhLogger LOGGER;
|
||||
static
|
||||
{
|
||||
DhLoggerBuilder loggerBuilder = new DhLoggerBuilder();
|
||||
loggerBuilder.fileLevelConfig(Config.Common.Logging.logRendererGLEventToFile);
|
||||
|
||||
// don't send chat messages if Iris is present since
|
||||
// Iris is known to cause (harmless) GL errors
|
||||
// and this can confuse users
|
||||
boolean irisPresent = (IRIS_ACCESSOR != null);
|
||||
if (!irisPresent)
|
||||
{
|
||||
loggerBuilder.chatLevelConfig(Config.Common.Logging.logRendererGLEventToChat);
|
||||
}
|
||||
|
||||
LOGGER = loggerBuilder.build();
|
||||
|
||||
if (irisPresent)
|
||||
{
|
||||
LOGGER.info("Iris detected, Distant Horizons OpenGL error logging won't be sent in the chat due to Iris throwing known (harmless) OpenGL errors. This is a bug with Iris, not Distant Horizons.");
|
||||
}
|
||||
}
|
||||
|
||||
public static final Set<String> LOGGED_GL_MESSAGES = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
|
||||
|
||||
|
||||
|
||||
private static GLProxy instance = null;
|
||||
|
||||
|
||||
/** Minecraft's GL capabilities */
|
||||
public final GLCapabilities glCapabilities;
|
||||
|
||||
public boolean namedObjectSupported = false; // ~OpenGL 4.5 (UNUSED CURRENTLY)
|
||||
public boolean bufferStorageSupported = false; // ~OpenGL 4.4
|
||||
public boolean vertexAttributeBufferBindingSupported = false; // ~OpenGL 4.3
|
||||
public boolean instancedArraysSupported = false;
|
||||
public boolean vertexAttribDivisorSupported = false; // OpenGL 3.3 or newer
|
||||
|
||||
private final EDhApiGpuUploadMethod preferredUploadMethod;
|
||||
|
||||
public final GLMessageBuilder vanillaDebugMessageBuilder =
|
||||
new GLMessageBuilder(
|
||||
(type) ->
|
||||
{
|
||||
if (type == EGLMessageType.POP_GROUP)
|
||||
return false;
|
||||
else if (type == EGLMessageType.PUSH_GROUP)
|
||||
return false;
|
||||
else if (type == EGLMessageType.MARKER)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
},
|
||||
(severity) ->
|
||||
{
|
||||
// notifications can generally be ignored (if they are logged at all)
|
||||
if (severity == EGLMessageSeverity.NOTIFICATION)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
},
|
||||
null
|
||||
);
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
//region
|
||||
|
||||
private GLProxy() throws IllegalStateException
|
||||
{
|
||||
// TODO vulkan complain if created when MC is running on vulkan
|
||||
|
||||
// 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() { return this.preferredUploadMethod; }
|
||||
|
||||
public static boolean runningOnRenderThread()
|
||||
{
|
||||
long currentContext = GLFW.glfwGetCurrentContext();
|
||||
return currentContext != 0L; // if the context isn't null, it's the MC context
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//=========//
|
||||
// logging //
|
||||
//=========//
|
||||
//region
|
||||
|
||||
/** this method is called on the render thread at the point of the GL Error */
|
||||
private static void logMessage(GLMessage glMessage)
|
||||
{
|
||||
EDhApiGLErrorHandlingMode errorHandlingMode = Config.Client.Advanced.Debugging.OpenGl.glErrorHandlingMode.get();
|
||||
if (errorHandlingMode == EDhApiGLErrorHandlingMode.IGNORE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
boolean onlyLogOnce = Config.Client.Advanced.Debugging.OpenGl.onlyLogGlErrorsOnce.get();
|
||||
if (onlyLogOnce
|
||||
&& !LOGGED_GL_MESSAGES.add(glMessage.message))
|
||||
{
|
||||
// this message has already been logged
|
||||
return;
|
||||
}
|
||||
|
||||
String errorMessage = "GL ERROR [" + glMessage.id + "] from [" + glMessage.source + "]: [" + glMessage.message + "].";
|
||||
if (onlyLogOnce)
|
||||
{
|
||||
errorMessage += " This message will only be logged once.";
|
||||
errorMessage += " Note: Distant Horizons will catch and log OpenGL errors from other mods, not just DH itself; if everything is rendering correctly these errors can probably be ignored.";
|
||||
}
|
||||
|
||||
|
||||
|
||||
// create an exception so we get a stacktrace of where the message was triggered from
|
||||
RuntimeException exception = new RuntimeException(errorMessage);
|
||||
|
||||
if (glMessage.type == EGLMessageType.ERROR || glMessage.type == EGLMessageType.UNDEFINED_BEHAVIOR)
|
||||
{
|
||||
// critical error
|
||||
|
||||
LOGGER.error(exception.getMessage(), exception);
|
||||
|
||||
if (errorHandlingMode == EDhApiGLErrorHandlingMode.LOG_THROW)
|
||||
{
|
||||
// will probably crash the game,
|
||||
// good for quickly checking if there's a problem while preventing log spam
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// non-critical log
|
||||
|
||||
EGLMessageSeverity severity = glMessage.severity;
|
||||
if (severity == null)
|
||||
{
|
||||
// just in case the message was malformed
|
||||
severity = EGLMessageSeverity.LOW;
|
||||
}
|
||||
|
||||
switch (severity)
|
||||
{
|
||||
case HIGH:
|
||||
LOGGER.error(exception.getMessage(), exception);
|
||||
break;
|
||||
case MEDIUM:
|
||||
LOGGER.warn(exception.getMessage(), exception);
|
||||
break;
|
||||
case LOW:
|
||||
LOGGER.info(exception.getMessage(), exception);
|
||||
break;
|
||||
case NOTIFICATION:
|
||||
LOGGER.debug(exception.getMessage(), exception);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// helper methods //
|
||||
//================//
|
||||
//region
|
||||
|
||||
private String getFailedVersionInfo(GLCapabilities c)
|
||||
{
|
||||
return "Your OpenGL support:\n" +
|
||||
"openGL version 3.2+: [" + c.OpenGL32 + "] <- REQUIRED\n" +
|
||||
"Vertex Attribute Buffer Binding: [" + (c.glVertexAttribBinding != 0) + "] <- optional improvement\n" +
|
||||
"Buffer Storage: [" + (c.glBufferStorage != 0) + "] <- optional improvement\n" +
|
||||
"If you noticed that your computer supports higher OpenGL versions"
|
||||
+ " but not the required version, try running the game in compatibility mode."
|
||||
+ " (How you turn that on, I have no clue~)";
|
||||
}
|
||||
|
||||
private String versionInfoToString(GLCapabilities c)
|
||||
{
|
||||
return "Your OpenGL support:\n" +
|
||||
"openGL version 3.2+: [" + c.OpenGL32 + "] <- REQUIRED\n" +
|
||||
"Vertex Attribute Buffer Binding: [" + (c.glVertexAttribBinding != 0) + "] <- optional improvement\n" +
|
||||
"Buffer Storage: [" + (c.glBufferStorage != 0) + "] <- optional improvement\n";
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
}
|
||||
+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() { }
|
||||
|
||||
}
|
||||
+629
@@ -0,0 +1,629 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.common.render.openGl.glObject.buffer;
|
||||
|
||||
import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod;
|
||||
import com.seibel.distanthorizons.common.render.openGl.glObject.GLProxy;
|
||||
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftGLWrapper;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.jar.EPlatform;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.logging.f3.F3Screen;
|
||||
import com.seibel.distanthorizons.core.render.RenderThreadTaskHandler;
|
||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
import com.seibel.distanthorizons.core.util.ThreadUtil;
|
||||
import com.seibel.distanthorizons.core.util.objects.Pair;
|
||||
import com.seibel.distanthorizons.core.util.objects.pooling.PhantomLoggingHelper;
|
||||
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||
import com.seibel.distanthorizons.coreapi.util.StringUtil;
|
||||
import org.lwjgl.opengl.GL32;
|
||||
import org.lwjgl.opengl.GL44;
|
||||
|
||||
import java.lang.ref.PhantomReference;
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.StampedLock;
|
||||
|
||||
public class GLBuffer implements AutoCloseable
|
||||
{
|
||||
private static final DhLogger LOGGER = new DhLoggerBuilder()
|
||||
.fileLevelConfig(Config.Common.Logging.logRendererGLEventToFile)
|
||||
.chatLevelConfig(Config.Common.Logging.logRendererGLEventToChat)
|
||||
.build();
|
||||
|
||||
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
|
||||
|
||||
|
||||
// TODO move to a shared location that can be handled by both GL and Blaze3D buffers
|
||||
/** if enabled the number of GC'ed buffers will be logged */
|
||||
private static final boolean LOG_PHANTOM_RECOVERY = ModInfo.IS_DEV_BUILD;
|
||||
/** If enabled buffers allocation/upload stacks will be logged when GC'ed. */
|
||||
private static final boolean LOG_PHANTOM_ALLOCATION_STACKS = false; // disabled by default due to the increased GC load
|
||||
|
||||
public static final double BUFFER_EXPANSION_MULTIPLIER = 1.3;
|
||||
public static final double BUFFER_SHRINK_TRIGGER = BUFFER_EXPANSION_MULTIPLIER * BUFFER_EXPANSION_MULTIPLIER;
|
||||
|
||||
/**
|
||||
* On macOS the legacy OpenGL -> Metal bridge crashes with SIGBUS in
|
||||
* {@code _platform_memmove} when {@code glBufferData} or {@code glBufferSubData}
|
||||
* are called with a large ByteBuffer in one shot. To work around it, we split
|
||||
* the upload into smaller sub-data calls that each fit comfortably inside the
|
||||
* driver's internal staging path. <br>
|
||||
* 256 KiB tuned empirically against macOS 26.5 — a 1 MiB chunk still
|
||||
* tripped the same {@code _platform_memmove} crash inside
|
||||
* {@code glBufferSubData_Exec}, but 256 KiB consistently survives.
|
||||
*/
|
||||
public static final int MAC_UPLOAD_CHUNK_BYTES = 256 * 1024;
|
||||
/** Threshold above which the chunked path kicks in on macOS. */
|
||||
public static final int MAC_UPLOAD_CHUNK_THRESHOLD = MAC_UPLOAD_CHUNK_BYTES;
|
||||
/** the number of active buffers, can be used for debugging */
|
||||
public static AtomicInteger bufferCount = new AtomicInteger(0);
|
||||
|
||||
private static final int PHANTOM_REF_CHECK_TIME_IN_MS = 5 * 1000;
|
||||
private static final ConcurrentHashMap<PhantomReference<? extends GLBuffer>, Integer> PHANTOM_TO_BUFFER_ID = new ConcurrentHashMap<>();
|
||||
private static final ConcurrentHashMap<Integer, PhantomReference<? extends GLBuffer>> BUFFER_ID_TO_PHANTOM = new ConcurrentHashMap<>();
|
||||
private static final ConcurrentHashMap<Integer, String> BUFFER_ID_TO_ALLOCATION_STRING = new ConcurrentHashMap<>();
|
||||
private static final ReferenceQueue<GLBuffer> PHANTOM_REFERENCE_QUEUE = new ReferenceQueue<>();
|
||||
private static final ThreadPoolExecutor CLEANUP_THREAD = ThreadUtil.makeSingleDaemonThreadPool("GLBuffer Cleanup");
|
||||
|
||||
|
||||
protected volatile int id = 0;
|
||||
public final int getId() { return this.id; }
|
||||
protected int size = 0;
|
||||
public int getSize() { return this.size; }
|
||||
protected boolean bufferStorage;
|
||||
protected boolean isMapped = false;
|
||||
|
||||
/**
|
||||
* Locking on the render thread isn't great, but is needed due to an inconsistent
|
||||
* race condition where VBOs can be marked as deleted outside the render thread. <br><br>
|
||||
*
|
||||
* But, due to being a read-write lock the chance of freezing
|
||||
* the render thread is very low
|
||||
* and since this is a stamped lock, the optimistic read time is basically zero.
|
||||
* (The optimistic lock time doesn't even appear in the profiler).
|
||||
*/
|
||||
public final StampedLock renderStampLock = new StampedLock();
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// constructors //
|
||||
//==============//
|
||||
//region
|
||||
|
||||
static { CLEANUP_THREAD.execute(() -> runPhantomReferenceCleanupLoop()); }
|
||||
|
||||
public GLBuffer(boolean isBufferStorage) { this.destroyOldAndCreate(isBufferStorage); }
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//=========//
|
||||
// methods //
|
||||
//=========//
|
||||
//region
|
||||
|
||||
// Should be override by subclasses
|
||||
public int getBufferBindingTarget() { return GL32.GL_COPY_READ_BUFFER; }
|
||||
|
||||
public void bind() { GL32.glBindBuffer(this.getBufferBindingTarget(), this.id); }
|
||||
public void unbind() { GL32.glBindBuffer(this.getBufferBindingTarget(), 0); }
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//====================//
|
||||
// create and destroy //
|
||||
//====================//
|
||||
//region
|
||||
|
||||
protected void destroyOldAndCreate(boolean asBufferStorage)
|
||||
{
|
||||
if (!GLProxy.runningOnRenderThread())
|
||||
{
|
||||
LodUtil.assertNotReach("Thread ["+Thread.currentThread()+"] tried to create a GLBuffer outside the MC render thread.");
|
||||
}
|
||||
|
||||
|
||||
// lock to prevent the render thread from accessing the buffer's ID
|
||||
// while we are removing it
|
||||
long writeStamp = renderStampLock.writeLock();
|
||||
try
|
||||
{
|
||||
final int oldId = this.id;
|
||||
this.id = GLMC.glGenBuffers();
|
||||
//LOGGER.info("created [" + newId + "].");
|
||||
|
||||
// destroy the old buffer
|
||||
// after the new one has been created
|
||||
// to hopefully prevent a rare race conditions where the old ID
|
||||
// is still used somewhere
|
||||
if (oldId != 0)
|
||||
{
|
||||
// this ID doesn't need to be tracked anymore
|
||||
tryRemoveBufferIdFromPhantom(oldId);
|
||||
destroyBufferIdNow(oldId, "destroyOldAndCreate");
|
||||
}
|
||||
|
||||
|
||||
this.bufferStorage = asBufferStorage;
|
||||
bufferCount.getAndIncrement();
|
||||
|
||||
PhantomReference<GLBuffer> phantom = new PhantomReference<>(this, PHANTOM_REFERENCE_QUEUE);
|
||||
PHANTOM_TO_BUFFER_ID.put(phantom, this.id);
|
||||
BUFFER_ID_TO_PHANTOM.put(this.id, phantom);
|
||||
|
||||
this.updateAllocationStackTrace();
|
||||
}
|
||||
finally
|
||||
{
|
||||
renderStampLock.unlock(writeStamp);
|
||||
}
|
||||
}
|
||||
|
||||
protected void destroyAsync()
|
||||
{
|
||||
// lock to prevent the render thread from accessing the buffer's ID
|
||||
// while we are removing it
|
||||
long writeStamp = renderStampLock.writeLock();
|
||||
try
|
||||
{
|
||||
if (this.id == 0)
|
||||
{
|
||||
// the buffer has already been closed
|
||||
return;
|
||||
}
|
||||
|
||||
final int idToDelete = this.id; // saving the ID to a separate variable is necessary so it can be captured by the lambda
|
||||
|
||||
// remove the phantom tracking now so the phantom doesn't have the chance to
|
||||
// get garbage collected before the render thread task runs
|
||||
// (this can happen if MC is running at extremely low framerates like 1 fps via mods)
|
||||
tryRemoveBufferIdFromPhantom(idToDelete);
|
||||
|
||||
// mark the old data is invalid before deleting to prevent a rare race condition
|
||||
// where the queued on render thread task runs before the ID is cleared
|
||||
this.id = 0;
|
||||
this.size = 0;
|
||||
|
||||
//LOGGER.info("async destroy [" + idToDelete + "].");
|
||||
RenderThreadTaskHandler.INSTANCE.queueRunningOnRenderThread("GLBuffer destroyAsync", () -> { destroyBufferIdNow(idToDelete, "destroyAsync"); });
|
||||
}
|
||||
finally
|
||||
{
|
||||
renderStampLock.unlock(writeStamp);
|
||||
}
|
||||
}
|
||||
|
||||
private static void destroyBufferIdNow(int id, String cause)
|
||||
{
|
||||
// only delete valid buffers
|
||||
if (id == 0)
|
||||
{
|
||||
LOGGER.warn("Attempted to destroy a buffer with ID 0, VRAM memory leaks may occur, cause: ["+cause+"].");
|
||||
return;
|
||||
}
|
||||
|
||||
bufferCount.decrementAndGet();
|
||||
GLMC.glDeleteBuffers(id);
|
||||
|
||||
if (Config.Client.Advanced.Debugging.logBufferGarbageCollection.get())
|
||||
{
|
||||
LOGGER.info("destroyed buffer [" + id + "], remaining: [" + BUFFER_ID_TO_PHANTOM.size() + "], cause: ["+cause+"].");
|
||||
}
|
||||
}
|
||||
|
||||
/** should be called before {@link GLBuffer#destroyBufferIdNow} */
|
||||
private static void tryRemoveBufferIdFromPhantom(int id)
|
||||
{
|
||||
// will contain nothing if stack tracking isn't enabled
|
||||
BUFFER_ID_TO_ALLOCATION_STRING.remove(id);
|
||||
|
||||
PhantomReference<? extends GLBuffer> phantom = BUFFER_ID_TO_PHANTOM.remove(id);
|
||||
if (phantom != null)
|
||||
{
|
||||
// if we are manually closing this buffer, we don't want the phantom reference to accidentally close it again
|
||||
// this can cause a race condition were we accidentally delete an in-use buffer and cause NVIDIA
|
||||
// to throw an EXCEPTION_ACCESS_VIOLATION when we attempt to render it
|
||||
phantom.clear();
|
||||
|
||||
Integer phantomId = PHANTOM_TO_BUFFER_ID.remove(phantom);
|
||||
if (phantomId == null)
|
||||
{
|
||||
LOGGER.warn("No Phantom->ID binding stored for ID ["+id+"]");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGGER.warn("Unable to remove phantom GLBuffer with ID ["+id+"], buffer may have already been deleted.");
|
||||
}
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//==================//
|
||||
// buffer uploading //
|
||||
//==================//
|
||||
//region
|
||||
|
||||
/**
|
||||
* Assumes the GL Context is already bound. <br>
|
||||
* Will create the VBO if one exist.
|
||||
*/
|
||||
public void uploadBuffer(ByteBuffer bb, EDhApiGpuUploadMethod uploadMethod, int maxExpansionSize, int bufferHint)
|
||||
{
|
||||
LodUtil.assertTrue(!uploadMethod.useEarlyMapping, "UploadMethod signal that this should use Mapping instead of uploadBuffer!");
|
||||
int bbSize = bb.limit() - bb.position();
|
||||
if (bbSize > maxExpansionSize)
|
||||
{
|
||||
LodUtil.assertNotReach("maxExpansionSize is [" + maxExpansionSize + "] but buffer size is [" + bbSize + "]!");
|
||||
}
|
||||
|
||||
// Don't upload an empty buffer
|
||||
if (bbSize == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// re-binding the old buffers is necessary for old MC versions for the following reasons:
|
||||
// for 16.5 and older the screen may be black when on the home menu
|
||||
// and for 1.19.2 - 1.21.4 the inventory/UI will render without a background
|
||||
int vao = GL32.glGetInteger(GL32.GL_VERTEX_ARRAY_BINDING);
|
||||
int vbo = GL32.glGetInteger(GL32.GL_ARRAY_BUFFER_BINDING);
|
||||
int ebo = GL32.glGetInteger(GL32.GL_ELEMENT_ARRAY_BUFFER_BINDING);
|
||||
|
||||
try
|
||||
{
|
||||
// make sure the buffer is ready for uploading
|
||||
this.createOrChangeBufferTypeForUpload(uploadMethod);
|
||||
|
||||
switch (uploadMethod)
|
||||
{
|
||||
case AUTO:
|
||||
LodUtil.assertNotReach("GpuUploadMethod AUTO must be resolved before call to uploadBuffer()!");
|
||||
case BUFFER_STORAGE:
|
||||
this.uploadBufferStorage(bb);
|
||||
break;
|
||||
case DATA:
|
||||
this.uploadBufferData(bb, bufferHint);
|
||||
break;
|
||||
case SUB_DATA:
|
||||
this.uploadSubData(bb, maxExpansionSize, bufferHint);
|
||||
break;
|
||||
default:
|
||||
LodUtil.assertNotReach("Unknown GpuUploadMethod!");
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
GL32.glBindVertexArray(GL32.glIsVertexArray(vao) ? vao : 0);
|
||||
GL32.glBindBuffer(GL32.GL_ARRAY_BUFFER, GL32.glIsBuffer(vbo) ? vbo : 0);
|
||||
GL32.glBindBuffer(GL32.GL_ELEMENT_ARRAY_BUFFER, GL32.glIsBuffer(ebo) ? ebo: 0);
|
||||
}
|
||||
}
|
||||
/** Requires the buffer to be bound */
|
||||
protected void uploadBufferStorage(ByteBuffer bb)
|
||||
{
|
||||
LodUtil.assertTrue(this.bufferStorage, "Buffer is not bufferStorage but its trying to use bufferStorage upload method!");
|
||||
|
||||
int bbSize = bb.limit() - bb.position();
|
||||
this.destroyOldAndCreate(true);
|
||||
this.bind();
|
||||
GL44.glBufferStorage(this.getBufferBindingTarget(), bb, 0);
|
||||
this.size = bbSize;
|
||||
}
|
||||
/** Requires the buffer to be bound */
|
||||
protected void uploadBufferData(ByteBuffer bb, int bufferDataHint)
|
||||
{
|
||||
LodUtil.assertTrue(!this.bufferStorage, "Buffer is bufferStorage but its trying to use bufferData upload method!");
|
||||
|
||||
int bbSize = bb.limit() - bb.position();
|
||||
int target = this.getBufferBindingTarget();
|
||||
|
||||
if (shouldUploadToGpuInChunks(bbSize))
|
||||
{
|
||||
// Two-step path used on macOS to dodge the Apple OpenGL -> Metal
|
||||
// memmove SIGBUS triggered by uploading a large ByteBuffer in one
|
||||
// glBufferData call:
|
||||
// 1) allocate-only with the size overload (no memcpy)
|
||||
// 2) fill the buffer through chunked glBufferSubData calls
|
||||
GL32.glBufferData(target, (long) bbSize, bufferDataHint);
|
||||
subDataUploadInChunks(target, 0, bb, MAC_UPLOAD_CHUNK_BYTES);
|
||||
}
|
||||
else
|
||||
{
|
||||
GL32.glBufferData(target, bb, bufferDataHint);
|
||||
}
|
||||
this.size = bbSize;
|
||||
|
||||
this.updateAllocationStackTrace();
|
||||
}
|
||||
/** Requires the buffer to be bound */
|
||||
protected void uploadSubData(ByteBuffer bb, int maxExpansionSize, int bufferDataHint)
|
||||
{
|
||||
LodUtil.assertTrue(!this.bufferStorage, "Buffer is bufferStorage but its trying to use subData upload method!");
|
||||
|
||||
int bbSize = bb.limit() - bb.position();
|
||||
int target = this.getBufferBindingTarget();
|
||||
if (this.size < bbSize || this.size > bbSize * BUFFER_SHRINK_TRIGGER)
|
||||
{
|
||||
int newSize = (int) (bbSize * BUFFER_EXPANSION_MULTIPLIER);
|
||||
if (newSize > maxExpansionSize)
|
||||
{
|
||||
newSize = maxExpansionSize;
|
||||
}
|
||||
|
||||
// allocate-only — no memcpy, safe on macOS regardless of size
|
||||
GL32.glBufferData(target, (long) newSize, bufferDataHint);
|
||||
this.size = newSize;
|
||||
}
|
||||
|
||||
if (shouldUploadToGpuInChunks(bbSize))
|
||||
{
|
||||
subDataUploadInChunks(target, 0, bb, MAC_UPLOAD_CHUNK_BYTES);
|
||||
}
|
||||
else
|
||||
{
|
||||
GL32.glBufferSubData(target, 0, bb);
|
||||
}
|
||||
|
||||
this.updateAllocationStackTrace();
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// base overrides //
|
||||
//================//
|
||||
//region
|
||||
|
||||
@Override
|
||||
public void close() { this.destroyAsync(); }
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return (this.bufferStorage ? "" : "Static-") + this.getClass().getSimpleName() +
|
||||
"[id:" + this.id + ",size:" + this.size + (this.isMapped ? ",MAPPED" : "") + "]";
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// helper methods //
|
||||
//================//
|
||||
//region
|
||||
|
||||
/**
|
||||
* Makes sure the buffer exists and is of the correct format
|
||||
* before uploading.
|
||||
*/
|
||||
private void createOrChangeBufferTypeForUpload(EDhApiGpuUploadMethod uploadMethod)
|
||||
{
|
||||
// create/change the buffer type if necessary
|
||||
if (uploadMethod.useBufferStorage != this.bufferStorage)
|
||||
{
|
||||
// recreate if the buffer storage type changed
|
||||
this.bind();
|
||||
this.destroyOldAndCreate(uploadMethod.useBufferStorage);
|
||||
this.bind();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Prevent uploading to the null buffer (ID 0).
|
||||
// This can happen if the buffer was deleted previously.
|
||||
if (this.id == 0)
|
||||
{
|
||||
this.destroyOldAndCreate(this.bufferStorage);
|
||||
}
|
||||
|
||||
this.bind();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* macOS-only mitigation for the SIGBUS in
|
||||
* {@code libsystem_platform.dylib _platform_memmove} that happens when the
|
||||
* Apple OpenGL -> Metal translation layer copies a single large ByteBuffer
|
||||
* out of LWJGL into driver memory. Splitting the copy into
|
||||
* {@link #MAC_UPLOAD_CHUNK_BYTES} slices keeps every memmove inside a size
|
||||
* the bridge handles reliably.
|
||||
*/
|
||||
private static boolean shouldUploadToGpuInChunks(int byteCount)
|
||||
{
|
||||
return EPlatform.get() == EPlatform.MACOS
|
||||
&& byteCount > MAC_UPLOAD_CHUNK_THRESHOLD;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uploads {@code bb} into the currently bound buffer at {@code baseOffset}
|
||||
* using a sequence of {@link GL32#glBufferSubData(int, long, ByteBuffer)}
|
||||
* calls of at most {@code chunkBytes} each. The buffer's position/limit are
|
||||
* restored before returning.
|
||||
*/
|
||||
private static void subDataUploadInChunks(int target, int baseOffset, ByteBuffer bb, int chunkBytes)
|
||||
{
|
||||
final int origPos = bb.position();
|
||||
final int origLimit = bb.limit();
|
||||
try
|
||||
{
|
||||
final int total = origLimit - origPos;
|
||||
int uploaded = 0;
|
||||
while (uploaded < total)
|
||||
{
|
||||
int chunk = Math.min(chunkBytes, total - uploaded);
|
||||
bb.position(origPos + uploaded);
|
||||
bb.limit(origPos + uploaded + chunk);
|
||||
GL32.glBufferSubData(target, (long) (baseOffset + uploaded), bb);
|
||||
uploaded += chunk;
|
||||
// Force the driver to drain its command queue between chunks
|
||||
// so the OpenGL -> Metal bridge processes (and frees) each
|
||||
// staging copy before the next sub-data call piles another
|
||||
// memmove on top of it.
|
||||
if (uploaded < total)
|
||||
{
|
||||
GL32.glFlush();
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
bb.limit(origLimit);
|
||||
bb.position(origPos);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* used to help track down leaks where the buffer isn't properly closed
|
||||
* Note: this probably needs extending to accept a stack trace from outside where it's being called
|
||||
* since it's often called on the render thread in an un-helpful location.
|
||||
*/
|
||||
public void updateAllocationStackTrace()
|
||||
{
|
||||
if (LOG_PHANTOM_ALLOCATION_STACKS)
|
||||
{
|
||||
String stack;
|
||||
|
||||
RenderThreadTaskHandler.QueuedRunnable parentQueuedRunnable;
|
||||
// if this is running on the render thread, try getting the render task's stack trace instead
|
||||
// since it's a lot more helpful than wherever the render thread tasks themselves are being run from
|
||||
if (RenderThreadTaskHandler.INSTANCE.isCurrentThread()
|
||||
&& (parentQueuedRunnable = RenderThreadTaskHandler.INSTANCE.getCurrentlyRunningTask()) != null
|
||||
&& parentQueuedRunnable.stackTrace != null)
|
||||
{
|
||||
// trim off the getStacktrace() and queueRunningOnRenderThread() methods
|
||||
StackTraceElement[] trimmedElements = Arrays.copyOfRange(parentQueuedRunnable.stackTrace, 2, parentQueuedRunnable.stackTrace.length);
|
||||
stack = StringUtil.join("\n", trimmedElements).intern();
|
||||
}
|
||||
else
|
||||
{
|
||||
// not running on the render thread, use the normal stack trace
|
||||
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
|
||||
stack = StringUtil.join("\n", stackTraceElements).intern();
|
||||
}
|
||||
|
||||
BUFFER_ID_TO_ALLOCATION_STRING.put(this.id, stack);
|
||||
}
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// static cleanup //
|
||||
//================//
|
||||
//region
|
||||
|
||||
private static void runPhantomReferenceCleanupLoop()
|
||||
{
|
||||
// these arrays are stored here so they don't have to be re-allocated each loop
|
||||
ArrayList<Pair<String, AtomicInteger>> allocationStackTraceCountPairList = new ArrayList<>();
|
||||
|
||||
while (true)
|
||||
{
|
||||
allocationStackTraceCountPairList.clear();
|
||||
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
Thread.sleep(PHANTOM_REF_CHECK_TIME_IN_MS);
|
||||
}
|
||||
catch (InterruptedException ignore) { }
|
||||
|
||||
int collectedCount = 0;
|
||||
|
||||
Reference<? extends GLBuffer> phantomRef = PHANTOM_REFERENCE_QUEUE.poll();
|
||||
while (phantomRef != null)
|
||||
{
|
||||
// destroy the buffer if it hasn't been cleared yet
|
||||
Integer idRef = PHANTOM_TO_BUFFER_ID.remove((PhantomReference<? extends GLBuffer>)phantomRef); // cast to make IntelliJ happy
|
||||
if (idRef != null)
|
||||
{
|
||||
BUFFER_ID_TO_PHANTOM.remove(idRef);
|
||||
final int id = idRef;
|
||||
RenderThreadTaskHandler.INSTANCE.queueRunningOnRenderThread("GLBuffer phantom destroy", () -> { destroyBufferIdNow(id, "runPhantomReferenceCleanupLoop"); });
|
||||
//LOGGER.info("Buffer Phantom collected, ID: ["+id+"]");
|
||||
|
||||
if (LOG_PHANTOM_ALLOCATION_STACKS) // stack trace shouldn't be null, but just in case
|
||||
{
|
||||
String stack = BUFFER_ID_TO_ALLOCATION_STRING.get(idRef);
|
||||
PhantomLoggingHelper.putAndIncrementTrackingString(stack, allocationStackTraceCountPairList);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGGER.warn("Failed to find Buffer ID for phantom reference: ["+phantomRef+"]");
|
||||
}
|
||||
|
||||
|
||||
collectedCount++;
|
||||
phantomRef = PHANTOM_REFERENCE_QUEUE.poll();
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (LOG_PHANTOM_RECOVERY)
|
||||
{
|
||||
// we only want to log when something has been returned
|
||||
if (collectedCount != 0)
|
||||
{
|
||||
LOGGER.warn("GLBuffer phantom recovered: ["+ F3Screen.NUMBER_FORMAT.format(collectedCount)+"].");
|
||||
|
||||
// log stack traces if present
|
||||
if (LOG_PHANTOM_ALLOCATION_STACKS)
|
||||
{
|
||||
PhantomLoggingHelper.LogAllocationStackTracePairCounts(LOGGER, allocationStackTraceCountPairList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOGGER.error("Unexpected error in buffer cleanup thread: [" + e.getMessage() + "].", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
}
|
||||
+31
-7
@@ -17,16 +17,40 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.common.util;
|
||||
package com.seibel.distanthorizons.common.render.openGl.glObject.buffer;
|
||||
|
||||
import org.lwjgl.opengl.GL32;
|
||||
|
||||
/**
|
||||
* Added to MC's dynamic textures via mixins
|
||||
* in order to denote whether a texture is a lightmap or not. <br><br>
|
||||
* AKA the GLElementBuffer
|
||||
*
|
||||
* If not done any dynamic texture could be used as the lightmap
|
||||
* which causes some weird rendering bugs.
|
||||
* @author James Seibel
|
||||
* @version 11-20-2021
|
||||
*/
|
||||
public interface ILightTextureMarker
|
||||
public class GLIndexBuffer extends GLBuffer
|
||||
{
|
||||
void markLightTexture();
|
||||
/**
|
||||
* When uploading to a buffer that is too small, recreate it this many times
|
||||
* bigger than the upload payload
|
||||
*/
|
||||
protected int indicesCount = 0;
|
||||
protected int glType = GL32.GL_UNSIGNED_INT;
|
||||
public int getGlType() { return this.glType; }
|
||||
|
||||
|
||||
|
||||
public GLIndexBuffer(boolean isBufferStorage) { super(isBufferStorage); }
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void destroyAsync()
|
||||
{
|
||||
super.destroyAsync();
|
||||
this.indicesCount = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBufferBindingTarget() { return GL32.GL_ELEMENT_ARRAY_BUFFER; }
|
||||
|
||||
}
|
||||
+194
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.common.render.openGl.glObject.buffer;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import com.seibel.distanthorizons.common.render.openGl.glObject.GLProxy;
|
||||
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.IndexBufferBuilder;
|
||||
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodQuadBuilder;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.render.RenderThreadTaskHandler;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.render.objects.IVertexBufferWrapper;
|
||||
import org.lwjgl.opengl.GL32;
|
||||
|
||||
import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
/**
|
||||
* This is a container for a OpenGL
|
||||
* VBO (Vertex Buffer Object).
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 11-20-2021
|
||||
*/
|
||||
public class GLVertexBuffer extends GLBuffer implements IVertexBufferWrapper
|
||||
{
|
||||
private static final AbstractDhRenderApiDefinition RENDER_DEF = SingletonInjector.INSTANCE.get(AbstractDhRenderApiDefinition.class);
|
||||
|
||||
/**
|
||||
* When uploading to a buffer that is too small, recreate it this many times
|
||||
* bigger than the upload payload
|
||||
*/
|
||||
protected int vertexCount = 0;
|
||||
public int getVertexCount() { return this.vertexCount; }
|
||||
|
||||
|
||||
private GlQuadIndexBuffer quadIBO = null;
|
||||
private static GlQuadIndexBuffer GLOBAL_QUAD_IBO = null;
|
||||
public GlQuadIndexBuffer getQuadIBO()
|
||||
{
|
||||
if (RENDER_DEF.useSingleIbo())
|
||||
{
|
||||
return GLOBAL_QUAD_IBO;
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.quadIBO;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
//region
|
||||
|
||||
static
|
||||
{
|
||||
if (RENDER_DEF.useSingleIbo())
|
||||
{
|
||||
RenderThreadTaskHandler.INSTANCE.queueRunningOnRenderThread("Global IBO Creation", () ->
|
||||
{
|
||||
GLOBAL_QUAD_IBO = new GlQuadIndexBuffer();
|
||||
|
||||
int maxSize = LodQuadBuilder.getMaxBufferByteSize();
|
||||
int maxVertexCount = maxSize / LodQuadBuilder.BYTES_PER_VERTEX;
|
||||
int maxQuadCount = (maxVertexCount / 4);
|
||||
|
||||
ByteBuffer buffer = IndexBufferBuilder.createBuffer(maxQuadCount);
|
||||
GLOBAL_QUAD_IBO.upload(buffer, maxQuadCount);
|
||||
MemoryUtil.memFree(buffer);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public GLVertexBuffer() { this(GLProxy.getInstance().getGpuUploadMethod() == EDhApiGpuUploadMethod.BUFFER_STORAGE); }
|
||||
public GLVertexBuffer(boolean isBufferStorage) { super(isBufferStorage); }
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//======================//
|
||||
// uploading/destroying //
|
||||
//======================//
|
||||
//region
|
||||
|
||||
@Override
|
||||
public int getBufferBindingTarget() { return GL32.GL_ARRAY_BUFFER; }
|
||||
|
||||
@Override
|
||||
public void uploadVertexBuffer(ByteBuffer buffer, int vertexCount)
|
||||
{
|
||||
EDhApiGpuUploadMethod uploadMethod = GLProxy.getInstance().getGpuUploadMethod();
|
||||
int maxBufferSize = LodQuadBuilder.getMaxBufferByteSize();
|
||||
this.uploadBuffer(buffer, vertexCount, uploadMethod, maxBufferSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* bufferSize is the number of shared verticies. <br>
|
||||
* This number will be higher when actually rendered since each box's face needs 2 triangles
|
||||
* with 2 shared verticies.
|
||||
*/
|
||||
public void uploadBuffer(ByteBuffer byteBuffer, int vertexCount, EDhApiGpuUploadMethod uploadMethod, int maxExpansionSize)
|
||||
{
|
||||
if (vertexCount < 0)
|
||||
{
|
||||
throw new IllegalArgumentException("vertexCount is negative!");
|
||||
}
|
||||
|
||||
// If size is zero, just ignore it.
|
||||
if (byteBuffer.limit() - byteBuffer.position() != 0)
|
||||
{
|
||||
super.uploadBuffer(byteBuffer, uploadMethod, maxExpansionSize, uploadMethod.useBufferStorage ? 0 : GL32.GL_STATIC_DRAW);
|
||||
}
|
||||
|
||||
this.vertexCount = vertexCount;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void uploadIndexBuffer(ByteBuffer buffer, int vertexCount)
|
||||
{
|
||||
if (RENDER_DEF.useSingleIbo())
|
||||
{
|
||||
// ignore index uploading when running a single IBO
|
||||
return;
|
||||
}
|
||||
|
||||
// If size is zero, just ignore it.
|
||||
if (vertexCount == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (this.quadIBO != null)
|
||||
{
|
||||
this.quadIBO.close();
|
||||
}
|
||||
|
||||
this.quadIBO = new GlQuadIndexBuffer();
|
||||
|
||||
int quadCount = (vertexCount / 4);
|
||||
this.quadIBO.upload(buffer, quadCount);
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// base overrides //
|
||||
//================//
|
||||
//region
|
||||
|
||||
@Override
|
||||
public void close() { this.destroyAsync(); }
|
||||
@Override
|
||||
public void destroyAsync()
|
||||
{
|
||||
super.destroyAsync();
|
||||
if (this.quadIBO != null)
|
||||
{
|
||||
this.quadIBO.destroyAsync();
|
||||
}
|
||||
this.vertexCount = 0;
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.common.render.openGl.glObject.buffer;
|
||||
|
||||
import com.seibel.distanthorizons.api.enums.config.EDhApiGpuUploadMethod;
|
||||
import com.seibel.distanthorizons.common.render.openGl.glObject.enums.GLEnums;
|
||||
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.IndexBufferBuilder;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import org.lwjgl.opengl.GL32;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/** aka GlQuadElementBuffer */
|
||||
public class GlQuadIndexBuffer extends GLIndexBuffer
|
||||
{
|
||||
private static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
//region
|
||||
|
||||
public GlQuadIndexBuffer() { super(false); }
|
||||
|
||||
public void upload(ByteBuffer buffer, int quadCount)
|
||||
{
|
||||
if (quadCount < 0)
|
||||
{
|
||||
throw new IllegalArgumentException("quadCount must be greater than 0");
|
||||
}
|
||||
if (quadCount == 0)
|
||||
{
|
||||
// shouldn't happen, but just in case
|
||||
return;
|
||||
}
|
||||
|
||||
this.indicesCount = quadCount * 6; // 2 triangles per quad
|
||||
if (this.indicesCount >= this.getCapacity()
|
||||
&& this.indicesCount < this.getCapacity() * BUFFER_SHRINK_TRIGGER)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.glType = GL32.GL_UNSIGNED_INT;
|
||||
super.uploadBuffer(buffer, EDhApiGpuUploadMethod.DATA,
|
||||
this.indicesCount * GLEnums.getTypeSize(this.glType), GL32.GL_STATIC_DRAW);
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//=========//
|
||||
// getters //
|
||||
//=========//
|
||||
//region
|
||||
|
||||
public int getCapacity() { return super.getSize() / GLEnums.getTypeSize(this.getGlType()); }
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package com.seibel.distanthorizons.common.render.openGl.glObject.enums;
|
||||
|
||||
public enum EGlVersion
|
||||
{
|
||||
GL_11,
|
||||
GL_12,
|
||||
GL_30,
|
||||
GL_31
|
||||
}
|
||||
+261
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.common.render.openGl.glObject.enums;
|
||||
|
||||
import static org.lwjgl.opengl.GL46.*;
|
||||
|
||||
// Turns GL int enums back to readable strings
|
||||
public class GLEnums
|
||||
{
|
||||
|
||||
public static String getString(int glEnum)
|
||||
{
|
||||
// blend stuff
|
||||
switch (glEnum)
|
||||
{
|
||||
case GL_ZERO:
|
||||
return "GL_ZERO";
|
||||
case GL_ONE:
|
||||
return "GL_ONE";
|
||||
case GL_SRC_COLOR:
|
||||
return "GL_SRC_COLOR";
|
||||
case GL_ONE_MINUS_SRC_COLOR:
|
||||
return "GL_ONE_MINUS_SRC_COLOR";
|
||||
case GL_DST_COLOR:
|
||||
return "GL_DST_COLOR";
|
||||
case GL_ONE_MINUS_DST_COLOR:
|
||||
return "GL_ONE_MINUS_DST_COLOR";
|
||||
case GL_SRC_ALPHA:
|
||||
return "GL_SRC_ALPHA";
|
||||
case GL_ONE_MINUS_SRC_ALPHA:
|
||||
return "GL_ONE_MINUS_SRC_ALPHA";
|
||||
case GL_DST_ALPHA:
|
||||
return "GL_DST_ALPHA";
|
||||
case GL_ONE_MINUS_DST_ALPHA:
|
||||
return "GL_ONE_MINUS_DST_ALPHA";
|
||||
case GL_CONSTANT_COLOR:
|
||||
return "GL_CONSTANT_COLOR";
|
||||
case GL_ONE_MINUS_CONSTANT_COLOR:
|
||||
return "GL_ONE_MINUS_CONSTANT_COLOR";
|
||||
case GL_CONSTANT_ALPHA:
|
||||
return "GL_CONSTANT_ALPHA";
|
||||
case GL_ONE_MINUS_CONSTANT_ALPHA:
|
||||
return "GL_ONE_MINUS_CONSTANT_ALPHA";
|
||||
default:
|
||||
}
|
||||
|
||||
// shader stuff
|
||||
switch (glEnum)
|
||||
{
|
||||
case GL_VERTEX_SHADER:
|
||||
return "GL_VERTEX_SHADER";
|
||||
case GL_GEOMETRY_SHADER:
|
||||
return "GL_GEOMETRY_SHADER";
|
||||
case GL_FRAGMENT_SHADER:
|
||||
return "GL_FRAGMENT_SHADER";
|
||||
default:
|
||||
}
|
||||
|
||||
// stencil stuff
|
||||
switch (glEnum)
|
||||
{
|
||||
case GL_KEEP:
|
||||
return "GL_KEEP";
|
||||
case GL_ZERO:
|
||||
return "GL_ZERO";
|
||||
case GL_REPLACE:
|
||||
return "GL_REPLACE";
|
||||
case GL_INCR:
|
||||
return "GL_INCR";
|
||||
case GL_DECR:
|
||||
return "GL_DECR";
|
||||
case GL_INVERT:
|
||||
return "GL_INVERT";
|
||||
case GL_INCR_WRAP:
|
||||
return "GL_INCR_WRAP";
|
||||
case GL_DECR_WRAP:
|
||||
return "GL_DECR_WRAP";
|
||||
default:
|
||||
}
|
||||
|
||||
// depth stuff
|
||||
switch (glEnum)
|
||||
{
|
||||
case GL_NEVER:
|
||||
return "GL_NEVER";
|
||||
case GL_LESS:
|
||||
return "GL_LESS";
|
||||
case GL_EQUAL:
|
||||
return "GL_EQUAL";
|
||||
case GL_LEQUAL:
|
||||
return "GL_LEQUAL";
|
||||
case GL_GREATER:
|
||||
return "GL_GREATER";
|
||||
case GL_NOTEQUAL:
|
||||
return "GL_NOTEQUAL";
|
||||
case GL_GEQUAL:
|
||||
return "GL_GEQUAL";
|
||||
case GL_ALWAYS:
|
||||
return "GL_ALWAYS";
|
||||
default:
|
||||
}
|
||||
|
||||
// Texture binding points
|
||||
switch (glEnum)
|
||||
{
|
||||
case GL_TEXTURE0:
|
||||
return "GL_TEXTURE0";
|
||||
case GL_TEXTURE1:
|
||||
return "GL_TEXTURE1";
|
||||
case GL_TEXTURE2:
|
||||
return "GL_TEXTURE2";
|
||||
case GL_TEXTURE3:
|
||||
return "GL_TEXTURE3";
|
||||
case GL_TEXTURE4:
|
||||
return "GL_TEXTURE4";
|
||||
case GL_TEXTURE5:
|
||||
return "GL_TEXTURE5";
|
||||
case GL_TEXTURE6:
|
||||
return "GL_TEXTURE6";
|
||||
case GL_TEXTURE7:
|
||||
return "GL_TEXTURE7";
|
||||
case GL_TEXTURE8:
|
||||
return "GL_TEXTURE8";
|
||||
case GL_TEXTURE9:
|
||||
return "GL_TEXTURE9";
|
||||
case GL_TEXTURE10:
|
||||
return "GL_TEXTURE10";
|
||||
case GL_TEXTURE11:
|
||||
return "GL_TEXTURE11";
|
||||
case GL_TEXTURE12:
|
||||
return "GL_TEXTURE12";
|
||||
case GL_TEXTURE13:
|
||||
return "GL_TEXTURE13";
|
||||
case GL_TEXTURE14:
|
||||
return "GL_TEXTURE14";
|
||||
case GL_TEXTURE15:
|
||||
return "GL_TEXTURE15";
|
||||
case GL_TEXTURE16:
|
||||
return "GL_TEXTURE16";
|
||||
case GL_TEXTURE17:
|
||||
return "GL_TEXTURE17";
|
||||
case GL_TEXTURE18:
|
||||
return "GL_TEXTURE18";
|
||||
case GL_TEXTURE19:
|
||||
return "GL_TEXTURE19";
|
||||
case GL_TEXTURE20:
|
||||
return "GL_TEXTURE20";
|
||||
case GL_TEXTURE21:
|
||||
return "GL_TEXTURE21";
|
||||
case GL_TEXTURE22:
|
||||
return "GL_TEXTURE22";
|
||||
case GL_TEXTURE23:
|
||||
return "GL_TEXTURE23";
|
||||
case GL_TEXTURE24:
|
||||
return "GL_TEXTURE24";
|
||||
case GL_TEXTURE25:
|
||||
return "GL_TEXTURE25";
|
||||
case GL_TEXTURE26:
|
||||
return "GL_TEXTURE26";
|
||||
case GL_TEXTURE27:
|
||||
return "GL_TEXTURE27";
|
||||
case GL_TEXTURE28:
|
||||
return "GL_TEXTURE28";
|
||||
case GL_TEXTURE29:
|
||||
return "GL_TEXTURE29";
|
||||
case GL_TEXTURE30:
|
||||
return "GL_TEXTURE30";
|
||||
case GL_TEXTURE31:
|
||||
return "GL_TEXTURE31";
|
||||
default:
|
||||
}
|
||||
|
||||
// Polygon modes
|
||||
switch (glEnum)
|
||||
{
|
||||
case GL_POINT:
|
||||
return "GL_POINT";
|
||||
case GL_LINE:
|
||||
return "GL_LINE";
|
||||
case GL_FILL:
|
||||
return "GL_FILL";
|
||||
default:
|
||||
}
|
||||
|
||||
// Culling modes
|
||||
switch (glEnum)
|
||||
{
|
||||
case GL_FRONT:
|
||||
return "GL_FRONT";
|
||||
case GL_BACK:
|
||||
return "GL_BACK";
|
||||
case GL_FRONT_AND_BACK:
|
||||
return "GL_FRONT_AND_BACK";
|
||||
default:
|
||||
}
|
||||
|
||||
// Types
|
||||
switch (glEnum)
|
||||
{
|
||||
case GL_BYTE:
|
||||
return "GL_BYTE";
|
||||
case GL_UNSIGNED_BYTE:
|
||||
return "GL_UNSIGNED_BYTE";
|
||||
case GL_SHORT:
|
||||
return "GL_SHORT";
|
||||
case GL_UNSIGNED_SHORT:
|
||||
return "GL_UNSIGNED_SHORT";
|
||||
case GL_INT:
|
||||
return "GL_INT";
|
||||
case GL_UNSIGNED_INT:
|
||||
return "GL_UNSIGNED_INT";
|
||||
case GL_FLOAT:
|
||||
return "GL_FLOAT";
|
||||
case GL_DOUBLE:
|
||||
return "GL_DOUBLE";
|
||||
default:
|
||||
}
|
||||
|
||||
return "GL_UNKNOWN(" + glEnum + ")";
|
||||
}
|
||||
|
||||
public static int getTypeSize(int glTypeEnum)
|
||||
{
|
||||
switch (glTypeEnum)
|
||||
{
|
||||
case GL_BYTE:
|
||||
case GL_UNSIGNED_BYTE:
|
||||
return 1;
|
||||
case GL_SHORT:
|
||||
case GL_UNSIGNED_SHORT:
|
||||
return 2;
|
||||
case GL_INT:
|
||||
case GL_UNSIGNED_INT:
|
||||
return 4;
|
||||
case GL_FLOAT:
|
||||
return 4;
|
||||
case GL_DOUBLE:
|
||||
return 8;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown type enum: " + getString(glTypeEnum));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+184
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.common.render.openGl.glObject.shader;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.logging.DhLogger;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import org.lwjgl.PointerBuffer;
|
||||
import org.lwjgl.opengl.GL32;
|
||||
import org.lwjgl.opengl.GL32C;
|
||||
import org.lwjgl.system.MemoryStack;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
import org.lwjgl.system.NativeType;
|
||||
|
||||
/**
|
||||
* This object holds a OpenGL reference to a shader
|
||||
* and allows for reading in and compiling a shader file.
|
||||
*/
|
||||
public class GlShader
|
||||
{
|
||||
private static final DhLogger LOGGER = new DhLoggerBuilder()
|
||||
.fileLevelConfig(Config.Common.Logging.logRendererGLEventToFile)
|
||||
.chatLevelConfig(Config.Common.Logging.logRendererGLEventToChat)
|
||||
.build();
|
||||
|
||||
|
||||
/** OpenGL shader ID */
|
||||
public final int id;
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// constructors //
|
||||
//==============//
|
||||
//region
|
||||
|
||||
/**
|
||||
* Creates a shader with specified type.
|
||||
*
|
||||
* @param type Either GL_VERTEX_SHADER or GL_FRAGMENT_SHADER.
|
||||
* @param sourceString File path of the shader
|
||||
* @throws RuntimeException if the shader fails to compile
|
||||
*/
|
||||
public GlShader(int type, String sourceString)
|
||||
{
|
||||
LOGGER.info("Loading shader with type: ["+type+"]");
|
||||
LOGGER.debug("Source: \n["+sourceString+"]");
|
||||
if (sourceString == null || sourceString.isEmpty())
|
||||
{
|
||||
throw new IllegalArgumentException("No shader source given.");
|
||||
}
|
||||
|
||||
// Create an empty shader object
|
||||
this.id = GL32.glCreateShader(type);
|
||||
if (this.id == 0)
|
||||
{
|
||||
throw new IllegalArgumentException("Failed to create shader with type ["+type+"] and Source: \n["+sourceString+"].");
|
||||
}
|
||||
|
||||
safeShaderSource(this.id, sourceString);
|
||||
GL32.glCompileShader(this.id);
|
||||
// check if the shader compiled
|
||||
int status = GL32.glGetShaderi(this.id, GL32.GL_COMPILE_STATUS);
|
||||
if (status != GL32.GL_TRUE)
|
||||
{
|
||||
|
||||
String message = "Shader compiler error. Details: [" + GL32.glGetShaderInfoLog(this.id) + "]\n";
|
||||
message += "Source: \n[" + sourceString + "]";
|
||||
this.free(); // important!
|
||||
throw new RuntimeException(message);
|
||||
}
|
||||
LOGGER.info("Shader loaded sucessfully.");
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//=========//
|
||||
// helpers //
|
||||
//=========//
|
||||
//region
|
||||
|
||||
/**
|
||||
* Identical in function to {@link GL32C#glShaderSource(int, CharSequence)} but
|
||||
* passes a null pointer for string length to force the driver to rely on the null
|
||||
* terminator for string length. This is a workaround for an apparent flaw with some
|
||||
* AMD drivers that don't receive or interpret the length correctly, resulting in
|
||||
* an access violation when the driver tries to read past the string memory.
|
||||
*
|
||||
* <p>Hat tip to fewizz for the find and the fix.
|
||||
*
|
||||
* <p>Source: https://github.com/vram-guild/canvas/commit/820bf754092ccaf8d0c169620c2ff575722d7d96
|
||||
*/
|
||||
private static void safeShaderSource(@NativeType("GLuint") int glId, @NativeType("GLchar const **") CharSequence source)
|
||||
{
|
||||
final MemoryStack stack = MemoryStack.stackGet();
|
||||
final int stackPointer = stack.getPointer();
|
||||
|
||||
try
|
||||
{
|
||||
final ByteBuffer sourceBuffer = MemoryUtil.memUTF8(source, true);
|
||||
final PointerBuffer pointers = stack.mallocPointer(1);
|
||||
pointers.put(sourceBuffer);
|
||||
|
||||
GL32.nglShaderSource(glId, 1, pointers.address0(), 0);
|
||||
org.lwjgl.system.APIUtil.apiArrayFree(pointers.address0(), 1);
|
||||
}
|
||||
finally
|
||||
{
|
||||
stack.setPointer(stackPointer);
|
||||
}
|
||||
}
|
||||
|
||||
public void free() { GL32.glDeleteShader(this.id); }
|
||||
|
||||
public static String loadFile(String path, boolean absoluteFilePath)
|
||||
{
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
|
||||
try
|
||||
{
|
||||
// open the file
|
||||
InputStream in;
|
||||
if (absoluteFilePath)
|
||||
{
|
||||
// Throws FileNotFoundException
|
||||
in = new FileInputStream(path); // Note: this should use OS path seperator
|
||||
}
|
||||
else
|
||||
{
|
||||
in = GlShader.class.getClassLoader().getResourceAsStream(path); // Note: path seperator should be '/'
|
||||
if (in == null)
|
||||
{
|
||||
throw new FileNotFoundException("Shader file not found in resource: " + path);
|
||||
}
|
||||
}
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
|
||||
|
||||
// read in the file
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null)
|
||||
{
|
||||
stringBuilder.append(line).append("\n");
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException("Unable to load shader from file [" + path + "]. Error: " + e.getMessage());
|
||||
}
|
||||
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
}
|
||||
+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/quad_apply.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/quad_apply.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();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
+157
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* 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
|
||||
{
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
//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/quad_apply.vert",
|
||||
"assets/distanthorizons/shaders/fade/gl/dh_fade.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/quad_apply.vert",
|
||||
"assets/distanthorizons/shaders/fade/gl/vanilla_fade.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
|
||||
|
||||
|
||||
|
||||
}
|
||||
+194
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.common.render.openGl.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();
|
||||
try (IProfilerWrapper.IProfileBlock fade_profile = profiler.push("DH-Vanilla Fade");
|
||||
GLState mcState = 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);
|
||||
}
|
||||
|
||||
|
||||
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())
|
||||
{
|
||||
GlDhFarFadeApplyShader.INSTANCE.fadeTexture = this.fadeTexture;
|
||||
GlDhFarFadeApplyShader.INSTANCE.readFramebuffer = GlDhVanillaFadeShader.INSTANCE.frameBuffer;
|
||||
GlDhFarFadeApplyShader.INSTANCE.drawFramebuffer = MC_RENDER.getTargetFramebuffer();
|
||||
GlDhFarFadeApplyShader.INSTANCE.render(renderParams);
|
||||
}
|
||||
}
|
||||
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/quad_apply.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/quad_apply.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/quad_apply.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/quad_apply.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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
+409
@@ -0,0 +1,409 @@
|
||||
package com.seibel.distanthorizons.common.render.openGl.terrain;
|
||||
|
||||
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.GlDhMetaRenderer;
|
||||
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.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.coreapi.DependencyInjection.ApiEventInjector;
|
||||
import org.lwjgl.opengl.GL32;
|
||||
|
||||
/**
|
||||
* Handles rendering the normal LOD terrain.
|
||||
* @see LodQuadBuilder
|
||||
*/
|
||||
public class GlDhTerrainShaderProgram extends GlShaderProgram implements IDhApiShaderProgram
|
||||
{
|
||||
public static final DhLogger LOGGER = new DhLoggerBuilder()
|
||||
.fileLevelConfig(Config.Common.Logging.logRendererEventToFile)
|
||||
.build();
|
||||
|
||||
private static final MinecraftGLWrapper GLMC = MinecraftGLWrapper.INSTANCE;
|
||||
private static final IIrisAccessor IRIS_ACCESSOR = ModAccessorInjector.INSTANCE.get(IIrisAccessor.class);
|
||||
|
||||
|
||||
private boolean init = false;
|
||||
|
||||
public 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
|
||||
|
||||
public GlDhTerrainShaderProgram()
|
||||
{
|
||||
super(
|
||||
"assets/distanthorizons/shaders/shared/gl/standard.vert",
|
||||
"assets/distanthorizons/shaders/shared/gl/flat_shaded.frag",
|
||||
new String[]{"vPosition", "color"}
|
||||
);
|
||||
}
|
||||
|
||||
public void tryInit()
|
||||
{
|
||||
if (this.init)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// unbinding here is necessary to fix an issue when running on Legacy GL
|
||||
this.vao.unbind();
|
||||
|
||||
this.init = true;
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// API methods //
|
||||
//=============//
|
||||
//region
|
||||
|
||||
@Override
|
||||
public void bind()
|
||||
{
|
||||
this.tryInit();
|
||||
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
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
// needs to be triggered after DH attempts to set the GL state so that Iris
|
||||
// can override it as needed
|
||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeRenderPassEvent.class, renderEventParam);
|
||||
|
||||
|
||||
|
||||
//===========//
|
||||
// rendering //
|
||||
//===========//
|
||||
|
||||
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);
|
||||
if (!bufferContainer.buffersUploaded)
|
||||
{
|
||||
// make sure we don't accidentally try
|
||||
// rendering a buffer that is (or is going to be) freed
|
||||
continue;
|
||||
}
|
||||
|
||||
// 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.vboOpaqueWrappers : bufferContainer.vboTransparentWrappers);
|
||||
for (int vboIndex = 0; vboIndex < vertexBuffers.length; vboIndex++)
|
||||
{
|
||||
GLVertexBuffer vbo = (GLVertexBuffer) vertexBuffers[vboIndex];
|
||||
if (vbo == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// for lock information please view the lock's javadocs
|
||||
long vboReadStamp = vbo.renderStampLock.readLock();
|
||||
long iboReadStamp = vbo.getQuadIBO().renderStampLock.readLock();
|
||||
try
|
||||
{
|
||||
// don't render empty sections
|
||||
if (vbo.getVertexCount() == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// don't render deleted VBOs (this will crash the driver/game)
|
||||
if (vbo.getId() == 0
|
||||
|| vbo.getQuadIBO().getId() == 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();
|
||||
vbo.getQuadIBO().bind();
|
||||
|
||||
GlDhMetaRenderer.INSTANCE.shaderProgramForThisFrame.bindVertexBuffer(vbo.getId());
|
||||
GL32.glDrawElements(
|
||||
GL32.GL_TRIANGLES,
|
||||
indexCount,
|
||||
vbo.getQuadIBO().getGlType(), 0);
|
||||
|
||||
vbo.unbind();
|
||||
vbo.getQuadIBO().unbind();
|
||||
}
|
||||
finally
|
||||
{
|
||||
vbo.renderStampLock.unlock(vboReadStamp);
|
||||
vbo.getQuadIBO().renderStampLock.unlock(iboReadStamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=========================//
|
||||
// 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
|
||||
|
||||
|
||||
|
||||
}
|
||||
+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());
|
||||
|
||||
}
|
||||
+79
-4
@@ -19,12 +19,19 @@
|
||||
|
||||
package com.seibel.distanthorizons.common.wrappers;
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.gui.ClassicConfigGUI;
|
||||
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.classicConfig.ClassicConfigGUI;
|
||||
import com.seibel.distanthorizons.common.wrappers.gui.LangWrapper;
|
||||
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.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.ILangWrapper;
|
||||
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.IWrapperFactory;
|
||||
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.IMinecraftSharedWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
|
||||
|
||||
/**
|
||||
* Binds all necessary dependencies, so we
|
||||
@@ -49,6 +56,9 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftSha
|
||||
*/
|
||||
public class DependencySetup
|
||||
{
|
||||
protected static final DhLogger LOGGER = new DhLoggerBuilder().build();
|
||||
|
||||
|
||||
|
||||
public static void createSharedBindings()
|
||||
{
|
||||
@@ -56,6 +66,7 @@ public class DependencySetup
|
||||
SingletonInjector.INSTANCE.bind(IVersionConstants.class, VersionConstants.INSTANCE);
|
||||
SingletonInjector.INSTANCE.bind(IWrapperFactory.class, WrapperFactory.INSTANCE);
|
||||
SingletonInjector.INSTANCE.bind(IKeyedClientLevelManager.class, KeyedClientLevelManager.INSTANCE);
|
||||
SingletonInjector.INSTANCE.bind(IDhApiCustomRenderObjectFactory.class, GenericRenderObjectFactory.INSTANCE);
|
||||
}
|
||||
|
||||
public static void createServerBindings()
|
||||
@@ -66,8 +77,72 @@ public class DependencySetup
|
||||
SingletonInjector.INSTANCE.bind(IMinecraftClientWrapper.class, MinecraftClientWrapper.INSTANCE);
|
||||
SingletonInjector.INSTANCE.bind(IMinecraftSharedWrapper.class, MinecraftClientWrapper.INSTANCE);
|
||||
SingletonInjector.INSTANCE.bind(IMinecraftRenderWrapper.class, MinecraftRenderWrapper.INSTANCE);
|
||||
SingletonInjector.INSTANCE.bind(IMinecraftGLWrapper.class, MinecraftGLWrapper.INSTANCE);
|
||||
SingletonInjector.INSTANCE.bind(IConfigGui.class, ClassicConfigGUI.CONFIG_CORE_INTERFACE);
|
||||
}
|
||||
|
||||
private static boolean renderingApiBindingsSet = false;
|
||||
/** will be called from a DH thread, not the render thread */
|
||||
public synchronized static void setRenderingApiBindings()
|
||||
{
|
||||
// shouldn't happen, but there was a single report that this method was triggered twice
|
||||
if (renderingApiBindingsSet)
|
||||
{
|
||||
LOGGER.warn("Rendering bindings already set, skipping. How did this happen?");
|
||||
return;
|
||||
}
|
||||
renderingApiBindingsSet = true;
|
||||
|
||||
|
||||
|
||||
EDhApiRenderApi renderingApiEnum = Config.Client.Advanced.Graphics.Experimental.renderingApi.get();
|
||||
if (renderingApiEnum == EDhApiRenderApi.AUTO)
|
||||
{
|
||||
IVersionConstants versionConstants = SingletonInjector.INSTANCE.get(IVersionConstants.class);
|
||||
renderingApiEnum = versionConstants.getDefaultRenderingApi();
|
||||
}
|
||||
|
||||
LOGGER.info("Setting DH Rendering API to: ["+renderingApiEnum+"].");
|
||||
|
||||
|
||||
|
||||
boolean validApi;
|
||||
AbstractDhRenderApiDefinition renderDefinition;
|
||||
if (renderingApiEnum == EDhApiRenderApi.OPEN_GL)
|
||||
{
|
||||
validApi = true;
|
||||
renderDefinition = new GlDhRenderApiDefinition();
|
||||
}
|
||||
else if (renderingApiEnum == EDhApiRenderApi.BLAZE_3D)
|
||||
{
|
||||
#if MC_VER <= MC_1_21_10
|
||||
validApi = false;
|
||||
renderDefinition = null;
|
||||
#else
|
||||
validApi = true;
|
||||
renderDefinition = new BlazeDhRenderApiDefinition();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
String message = "No ["+ AbstractDhRenderApiDefinition.class.getSimpleName()+"] concrete implementation found for the value: ["+renderingApiEnum+"].";
|
||||
LOGGER.fatal(message);
|
||||
throw new IllegalStateException(message);
|
||||
}
|
||||
|
||||
|
||||
// crash if an invalid API is set
|
||||
if (!validApi)
|
||||
{
|
||||
String message = "["+renderingApiEnum+"] is not supported on this version of Minecraft, reverting to ["+EDhApiRenderApi.AUTO+"].";
|
||||
LOGGER.fatal(message);
|
||||
Config.Client.Advanced.Graphics.Experimental.renderingApi.set(EDhApiRenderApi.AUTO);
|
||||
throw new IllegalStateException(message);
|
||||
}
|
||||
|
||||
|
||||
renderDefinition.bindRenderers();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
+9
-1
@@ -46,7 +46,6 @@ public class McObjectConverter
|
||||
|
||||
|
||||
/** 4x4 float matrix converter */
|
||||
@Deprecated
|
||||
public static Mat4f Convert(
|
||||
#if MC_VER < MC_1_19_4 com.mojang.math.Matrix4f
|
||||
#elif MC_VER < MC_1_21_6 org.joml.Matrix4f
|
||||
@@ -140,7 +139,16 @@ public class McObjectConverter
|
||||
}
|
||||
|
||||
public static BlockPos Convert(DhBlockPos wrappedPos) { return new BlockPos(wrappedPos.getX(), wrappedPos.getY(), wrappedPos.getZ()); }
|
||||
|
||||
public static ChunkPos Convert(DhChunkPos wrappedPos) { return new ChunkPos(wrappedPos.getX(), wrappedPos.getZ()); }
|
||||
public static DhChunkPos Convert(ChunkPos mcPos)
|
||||
{
|
||||
#if MC_VER <= MC_1_21_11
|
||||
return new DhChunkPos(mcPos.x, mcPos.z);
|
||||
#else
|
||||
return new DhChunkPos(mcPos.x(), mcPos.z());
|
||||
#endif
|
||||
}
|
||||
|
||||
public static Direction Convert(EDhDirection lodDirection) { return directions[lodDirection.ordinal()]; }
|
||||
public static EDhDirection Convert(Direction direction) { return lodDirections[direction.ordinal()]; }
|
||||
|
||||
+33
-7
@@ -19,22 +19,30 @@
|
||||
|
||||
package com.seibel.distanthorizons.common.wrappers;
|
||||
|
||||
import com.seibel.distanthorizons.api.enums.config.EDhApiRenderApi;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants;
|
||||
|
||||
/**
|
||||
* @author James Seibel
|
||||
* @version 12-11-2021
|
||||
*/
|
||||
public class VersionConstants implements IVersionConstants
|
||||
{
|
||||
public static final VersionConstants INSTANCE = new VersionConstants();
|
||||
|
||||
|
||||
private VersionConstants()
|
||||
{
|
||||
|
||||
}
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
//region
|
||||
|
||||
private VersionConstants() { }
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//=========//
|
||||
// methods //
|
||||
//=========//
|
||||
//region
|
||||
|
||||
@Override
|
||||
public String getMinecraftVersion()
|
||||
@@ -85,10 +93,28 @@ public class VersionConstants implements IVersionConstants
|
||||
return "1.21.10";
|
||||
#elif MC_VER == MC_1_21_11
|
||||
return "1.21.11";
|
||||
#elif MC_VER == MC_26_1_2
|
||||
return "26.1.2";
|
||||
#elif MC_VER == MC_26_2_0
|
||||
return "26.2.0";
|
||||
#else
|
||||
ERROR MC version constant missing
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public EDhApiRenderApi getDefaultRenderingApi()
|
||||
{
|
||||
#if MC_VER <= MC_1_21_11
|
||||
return EDhApiRenderApi.OPEN_GL;
|
||||
#else
|
||||
return EDhApiRenderApi.BLAZE_3D;
|
||||
#endif
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
}
|
||||
+58
-11
@@ -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.ServerLevelWrapper;
|
||||
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.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.wrapperInterfaces.IWrapperFactory;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
|
||||
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.ILevelWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.worldGeneration.IBatchGeneratorEnvironmentWrapper;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
#if MC_VER > MC_1_17_1
|
||||
import net.minecraft.core.Holder;
|
||||
#endif
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.LevelReader;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
|
||||
/**
|
||||
* This handles creating abstract wrapper objects.
|
||||
@@ -62,9 +67,32 @@ 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 //
|
||||
//==============//
|
||||
//region
|
||||
|
||||
@Override
|
||||
public IBatchGeneratorEnvironmentWrapper createBatchGenerator(IDhLevel targetLevel)
|
||||
@@ -103,7 +131,7 @@ public class WrapperFactory implements IWrapperFactory
|
||||
@Override
|
||||
public IBiomeWrapper deserializeBiomeWrapper(String str, ILevelWrapper levelWrapper) throws IOException { return BiomeWrapper.deserialize(str, levelWrapper); }
|
||||
@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
|
||||
{
|
||||
@@ -119,16 +147,19 @@ public class WrapperFactory implements IWrapperFactory
|
||||
public IBlockStateWrapper deserializeBlockStateWrapper(String str, ILevelWrapper levelWrapper) throws IOException { return BlockStateWrapper.deserialize(str, levelWrapper); }
|
||||
@Override
|
||||
public IBlockStateWrapper getAirBlockStateWrapper() { return BlockStateWrapper.AIR; }
|
||||
@Override
|
||||
public IBlockStateWrapper getWaterBlockStateWrapper(ILevelWrapper levelWrapper) { return BlockStateWrapper.getWaterBlockStateWrapper(levelWrapper); }
|
||||
@Override
|
||||
public ObjectOpenHashSet<IBlockStateWrapper> getRendererIgnoredBlocks(ILevelWrapper levelWrapper) { return BlockStateWrapper.getRendererIgnoredBlocks(levelWrapper); }
|
||||
@Override
|
||||
public ObjectOpenHashSet<IBlockStateWrapper> getRendererIgnoredCaveBlocks(ILevelWrapper levelWrapper) { return BlockStateWrapper.getRendererIgnoredCaveBlocks(levelWrapper); }
|
||||
@Override
|
||||
public ObjectOpenHashSet<IBlockStateWrapper> getWaterSubsurfaceReplacementBlocks(ILevelWrapper levelWrapper) { return BlockStateWrapper.getWaterSubsurfaceReplacementBlocks(levelWrapper); }
|
||||
@Override
|
||||
public ObjectOpenHashSet<IBlockStateWrapper> getWaterSurfaceReplacementBlocks(ILevelWrapper levelWrapper) { return BlockStateWrapper.getWaterSurfaceReplacementBlocks(levelWrapper); }
|
||||
|
||||
@Override
|
||||
public HashSet<IBlockStateWrapper> getRendererIgnoredBlocks(ILevelWrapper levelWrapper) { return BlockStateWrapper.getRendererIgnoredBlocks(levelWrapper); }
|
||||
@Override
|
||||
public HashSet<IBlockStateWrapper> getRendererIgnoredCaveBlocks(ILevelWrapper levelWrapper) { return BlockStateWrapper.getRendererIgnoredCaveBlocks(levelWrapper); }
|
||||
|
||||
@Override
|
||||
public void resetRendererIgnoredCaveBlocks() { BlockStateWrapper.clearRendererIgnoredCaveBlocks(); }
|
||||
@Override
|
||||
public void resetRendererIgnoredBlocksSet() { BlockStateWrapper.clearRendererIgnoredBlocks(); }
|
||||
public void resetCachedIgnoredBlocksSets() { BlockStateWrapper.clearCachedIgnoreBlocks(); }
|
||||
|
||||
|
||||
/**
|
||||
@@ -211,10 +242,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 //
|
||||
//=============//
|
||||
//region
|
||||
|
||||
// documentation should be in the API interface
|
||||
|
||||
@@ -313,12 +353,15 @@ public class WrapperFactory implements IWrapperFactory
|
||||
return createWrapperErrorMessage("BlockState wrapper", expectedClassNames, objectArray);
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// helper methods //
|
||||
//================//
|
||||
//region
|
||||
|
||||
private static String createWrapperErrorMessage(String wrapperName, String[] expectedClassNames, Object[] objectArray)
|
||||
{
|
||||
@@ -354,4 +397,8 @@ public class WrapperFactory implements IWrapperFactory
|
||||
return message.toString();
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
+36
-8
@@ -6,15 +6,13 @@ import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSour
|
||||
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.coreapi.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;
|
||||
|
||||
@@ -30,6 +28,11 @@ import org.jetbrains.annotations.Nullable;
|
||||
import net.minecraft.core.Holder;
|
||||
#endif
|
||||
|
||||
#if MC_VER <= MC_1_21_11
|
||||
import net.minecraft.world.level.BlockAndTintGetter;
|
||||
#else
|
||||
import net.minecraft.client.renderer.block.BlockAndTintGetter;
|
||||
#endif
|
||||
|
||||
public abstract class AbstractDhTintGetter implements BlockAndTintGetter
|
||||
{
|
||||
@@ -43,7 +46,7 @@ public abstract class AbstractDhTintGetter implements BlockAndTintGetter
|
||||
|
||||
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;
|
||||
public static final int INVALID_COLOR = -1;
|
||||
|
||||
|
||||
protected BiomeWrapper biomeWrapper;
|
||||
@@ -57,6 +60,7 @@ public abstract class AbstractDhTintGetter implements BlockAndTintGetter
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
//region
|
||||
|
||||
public AbstractDhTintGetter() { }
|
||||
|
||||
@@ -73,11 +77,14 @@ public abstract class AbstractDhTintGetter implements BlockAndTintGetter
|
||||
this.smoothingRadiusInBlocks = Config.Client.Advanced.Graphics.Quality.lodBiomeBlending.get();
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
//================//
|
||||
// shared methods //
|
||||
//================//
|
||||
|
||||
//===============//
|
||||
// color getters //
|
||||
//===============//
|
||||
//region
|
||||
|
||||
/** Called by MC's tint getter */
|
||||
@Override
|
||||
@@ -192,7 +199,7 @@ public abstract class AbstractDhTintGetter implements BlockAndTintGetter
|
||||
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
|
||||
Integer cachedColor = COLOR_BY_BLOCK_BIOME_PAIR.get(pair);
|
||||
if (cachedColor != null)
|
||||
{
|
||||
return cachedColor;
|
||||
@@ -332,6 +339,27 @@ public abstract class AbstractDhTintGetter implements BlockAndTintGetter
|
||||
});
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//===========//
|
||||
// set color //
|
||||
//===========//
|
||||
//region
|
||||
|
||||
/**
|
||||
* can be used in newer MC versions
|
||||
* where the color getting logic is a bit more manual
|
||||
*/
|
||||
public static void setStaticColor(BlockStateWrapper blockStateWrapper, BiomeWrapper biomeWrapper, Integer colorInt)
|
||||
{
|
||||
BlockBiomeWrapperPair pair = BlockBiomeWrapperPair.get(blockStateWrapper, biomeWrapper);
|
||||
COLOR_BY_BLOCK_BIOME_PAIR.put(pair, colorInt);
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
+25
-10
@@ -49,6 +49,7 @@ import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
#else
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.core.component.DataComponentMap;
|
||||
#endif
|
||||
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
@@ -221,26 +222,27 @@ public class BiomeWrapper implements IBiomeWrapper
|
||||
Level level = (Level)levelWrapper.getWrappedMcObject();
|
||||
net.minecraft.core.RegistryAccess registryAccess = level.registryAccess();
|
||||
|
||||
#if MC_VER < MC_1_21_11
|
||||
#if MC_VER <= MC_1_21_10
|
||||
ResourceLocation resourceLocation;
|
||||
#else
|
||||
Identifier resourceLocation;
|
||||
#endif
|
||||
|
||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
||||
#if MC_VER <= MC_1_17_1
|
||||
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_19_2
|
||||
resourceLocation = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).getKey(this.biome.value());
|
||||
#elif MC_VER < MC_1_21_3
|
||||
#elif MC_VER <= MC_1_21_1
|
||||
resourceLocation = registryAccess.registryOrThrow(Registries.BIOME).getKey(this.biome.value());
|
||||
#else
|
||||
resourceLocation = registryAccess.lookupOrThrow(Registries.BIOME).getKey(this.biome.value());
|
||||
#endif
|
||||
|
||||
|
||||
if (resourceLocation == null)
|
||||
{
|
||||
String biomeName;
|
||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
||||
#if MC_VER <= MC_1_17_1
|
||||
biomeName = this.biome.toString();
|
||||
#else
|
||||
biomeName = this.biome.value().toString();
|
||||
@@ -258,7 +260,6 @@ public class BiomeWrapper implements IBiomeWrapper
|
||||
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
|
||||
{
|
||||
// we need the final string for the concurrent hash map later
|
||||
@@ -355,18 +356,18 @@ public class BiomeWrapper implements IBiomeWrapper
|
||||
|
||||
|
||||
boolean success;
|
||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
||||
#if 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
|
||||
#elif 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
|
||||
#elif MC_VER <= MC_1_21_1
|
||||
Biome unwrappedBiome = registryAccess.registryOrThrow(Registries.BIOME).get(resourceLocation);
|
||||
success = (unwrappedBiome != null);
|
||||
Holder<Biome> biome = new Holder.Direct<>(unwrappedBiome);
|
||||
#else
|
||||
#elif MC_VER <= MC_1_21_11
|
||||
Holder<Biome> biome;
|
||||
Optional<Holder.Reference<Biome>> optionalBiomeHolder = registryAccess.lookupOrThrow(Registries.BIOME).get(resourceLocation);
|
||||
if (optionalBiomeHolder.isPresent())
|
||||
@@ -380,6 +381,20 @@ public class BiomeWrapper implements IBiomeWrapper
|
||||
success = false;
|
||||
biome = null;
|
||||
}
|
||||
#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, DataComponentMap.EMPTY);
|
||||
}
|
||||
else
|
||||
{
|
||||
success = false;
|
||||
biome = null;
|
||||
}
|
||||
#endif
|
||||
|
||||
return new BiomeDeserializeResult(success, biome);
|
||||
|
||||
+576
-395
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user