mirror of
https://github.com/GTNewHorizons/Angelica.git
synced 2026-10-25 20:22:22 +00:00
Add renderer selection to video settings - (#2215)
This commit is contained in:
1 parent
23e36f2b76
commit
2a8c8756d3
62 files changed
+1345
-1453
No files matched your search
@@ -0,0 +1,53 @@
|
||||
name: Build angelica-moltenvk
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "moltenvk-v*"
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
publish:
|
||||
description: Publish angelica-moltenvk.jar to the GTNH maven
|
||||
type: boolean
|
||||
required: false
|
||||
default: false
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/setup-java@v5
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: 21
|
||||
- uses: gradle/actions/setup-gradle@v4
|
||||
- name: Compute version
|
||||
shell: bash
|
||||
env:
|
||||
TAG: ${{ github.ref_type == 'tag' && github.ref_name || '' }}
|
||||
run: |
|
||||
version="$(bash .github/scripts/companion-version.sh moltenvk lwjgl3Release)"
|
||||
echo "MOLTENVK_VERSION=$version" >> "$GITHUB_ENV"
|
||||
- name: Build angelica-moltenvk.jar
|
||||
run: ./gradlew -PmoltenvkVersion="$MOLTENVK_VERSION" :moltenvk:distJar
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: angelica-moltenvk
|
||||
path: moltenvk/build/libs/angelica-moltenvk-*.jar
|
||||
if-no-files-found: error
|
||||
- name: Publish to GTNH maven
|
||||
if: github.ref_type == 'tag' || inputs.publish
|
||||
env:
|
||||
MAVEN_USER: ${{ secrets.MAVEN_USER }}
|
||||
MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }}
|
||||
run: ./gradlew -PpublishMoltenVK=true -PmoltenvkVersion="$MOLTENVK_VERSION" :moltenvk:publish
|
||||
- name: Create GitHub release
|
||||
if: github.ref_type == 'tag'
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
TAG: ${{ github.ref_name }}
|
||||
run: bash .github/scripts/release-companion-jar.sh moltenvk/build/libs/angelica-moltenvk-*.jar "MoltenVK for the SDL GPU Vulkan driver on macOS."
|
||||
@@ -12,6 +12,9 @@ on:
|
||||
required: false
|
||||
default: false
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
@@ -66,8 +69,15 @@ jobs:
|
||||
cp "$d"/* "$dest/"
|
||||
done
|
||||
find tracy-client/src/main/resources/natives -type f
|
||||
- name: Compute version
|
||||
shell: bash
|
||||
env:
|
||||
TAG: ${{ github.ref_type == 'tag' && github.ref_name || '' }}
|
||||
run: |
|
||||
version="$(bash .github/scripts/companion-version.sh tracy tracy)"
|
||||
echo "TRACY_JAR_VERSION=$version" >> "$GITHUB_ENV"
|
||||
- name: Build angelica-tracy.jar
|
||||
run: ./gradlew :tracy-client:distJar
|
||||
run: ./gradlew -PtracyJarVersion="$TRACY_JAR_VERSION" :tracy-client:distJar
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: angelica-tracy
|
||||
@@ -78,4 +88,10 @@ jobs:
|
||||
env:
|
||||
MAVEN_USER: ${{ secrets.MAVEN_USER }}
|
||||
MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }}
|
||||
run: ./gradlew -PpublishTracy=true :tracy-client:publish
|
||||
run: ./gradlew -PpublishTracy=true -PtracyJarVersion="$TRACY_JAR_VERSION" :tracy-client:publish
|
||||
- name: Create GitHub release
|
||||
if: github.ref_type == 'tag'
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
TAG: ${{ github.ref_name }}
|
||||
run: bash .github/scripts/release-companion-jar.sh tracy-client/build/libs/angelica-tracy-*.jar "Tracy profiler backend for Angelica."
|
||||
@@ -3,7 +3,7 @@ name: Release tagged build
|
||||
|
||||
on:
|
||||
push:
|
||||
tags: [ '*', '!tracy-v*' ]
|
||||
tags: [ '*', '!tracy-v*', '!moltenvk-v*' ]
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
@@ -93,6 +93,9 @@ DependencyHandlerScope.of(dependencies).apply {
|
||||
shadowImplementation(project(":lwjgl3-backend")) { isTransitive = false }
|
||||
shadowImplementation(project(":sdl-gpu")) { isTransitive = false }
|
||||
runtimeOnlyNonPublishable(project(":tracy-client")) { isTransitive = false }
|
||||
if (System.getProperty("os.name").lowercase().contains("mac")) {
|
||||
runtimeOnlyNonPublishable(project(":moltenvk")) { isTransitive = false }
|
||||
}
|
||||
devOnlyNonPublishable(libs.async.profiler)
|
||||
shadowImplementation(libs.eventbus)
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ public final class SystemProperties {
|
||||
|
||||
// Backend selection
|
||||
public static final String KEY_USE_SDL_GPU = "angelica.sdlgpu.enable";
|
||||
public static final boolean USE_SDL_GPU = Boolean.getBoolean(KEY_USE_SDL_GPU);
|
||||
public static final Boolean SDL_GPU_OVERRIDE = parseBooleanOverride(KEY_USE_SDL_GPU);
|
||||
public static final String GL_PROFILE = System.getProperty("angelica.glProfile", "");
|
||||
public static final boolean DISABLE_NVIDIA_WORKAROUND = Boolean.getBoolean("angelica.disableNvidiaWorkaround");
|
||||
public static final boolean DISABLE_LTW_WORKAROUND = Boolean.getBoolean("angelica.disableLtwWorkaround");
|
||||
@@ -28,7 +28,8 @@ public final class SystemProperties {
|
||||
|
||||
// SDL-GPU
|
||||
public static final String KEY_SDL_GPU_DRIVER = "angelica.sdlgpu.driver";
|
||||
public static final String SDL_GPU_DRIVER = System.getProperty(KEY_SDL_GPU_DRIVER, "");
|
||||
public static final String SDL_GPU_DRIVER_OVERRIDE = parseStringOverride(KEY_SDL_GPU_DRIVER);
|
||||
public static final String MOLTENVK_DIR = System.getProperty("angelica.moltenvk.dir", "angelica" + File.separator + "natives" + File.separator + "moltenvk");
|
||||
public static final boolean SDL_GPU_DEBUG = Boolean.getBoolean("angelica.sdlgpu.debug");
|
||||
private static final SdlAssertionMode ENCODER_ASSERTIONS = parseEnum("angelica.sdlgpu.encoderAssertions", SdlAssertionMode.OFF, SdlAssertionMode.WARN, SdlAssertionMode.class);
|
||||
public static final boolean SDL_ENCODER_ASSERTIONS = ENCODER_ASSERTIONS != SdlAssertionMode.OFF;
|
||||
@@ -165,7 +166,12 @@ public final class SystemProperties {
|
||||
|
||||
private static Boolean parseBooleanOverride(String key) {
|
||||
final String raw = System.getProperty(key);
|
||||
return raw == null ? null : Boolean.parseBoolean(raw);
|
||||
return raw == null || raw.isEmpty() ? null : Boolean.parseBoolean(raw);
|
||||
}
|
||||
|
||||
private static String parseStringOverride(String key) {
|
||||
final String raw = System.getProperty(key);
|
||||
return raw == null || raw.isEmpty() ? null : raw;
|
||||
}
|
||||
|
||||
private static double parseDouble(String key) {
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.gtnewhorizons.angelica.glsm.backend;
|
||||
|
||||
import com.gtnewhorizons.angelica.config.SystemProperties;
|
||||
|
||||
public final class BackendOptions {
|
||||
|
||||
private static boolean configSdlGpu;
|
||||
private static String configDriver = "";
|
||||
private static int configGlVersion;
|
||||
|
||||
private BackendOptions() {}
|
||||
|
||||
public static void latch(boolean sdlGpu, String driver, int glVersion) {
|
||||
configSdlGpu = sdlGpu;
|
||||
configDriver = driver;
|
||||
configGlVersion = glVersion;
|
||||
}
|
||||
|
||||
public static boolean sdlGpuRequested() {
|
||||
return SystemProperties.SDL_GPU_OVERRIDE != null ? SystemProperties.SDL_GPU_OVERRIDE : configSdlGpu;
|
||||
}
|
||||
|
||||
public static String sdlGpuDriver() {
|
||||
return SystemProperties.SDL_GPU_DRIVER_OVERRIDE != null ? SystemProperties.SDL_GPU_DRIVER_OVERRIDE : configDriver;
|
||||
}
|
||||
|
||||
public static boolean configSdlGpu() {
|
||||
return configSdlGpu;
|
||||
}
|
||||
|
||||
public static String configDriver() {
|
||||
return configDriver;
|
||||
}
|
||||
|
||||
public static int configGlVersion() {
|
||||
return configGlVersion;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.gtnewhorizons.angelica.glsm.backend;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public final class BackendStartGuard {
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger("Angelica/BackendStartGuard");
|
||||
|
||||
private static File pending;
|
||||
private static boolean tripped;
|
||||
|
||||
private BackendStartGuard() {}
|
||||
|
||||
public static boolean begin(File marker, boolean sdlGpuConfigured, boolean flagForced) {
|
||||
pending = null;
|
||||
tripped = false;
|
||||
if (!sdlGpuConfigured || flagForced) {
|
||||
delete(marker);
|
||||
return false;
|
||||
}
|
||||
if (marker.isFile()) {
|
||||
delete(marker);
|
||||
tripped = true;
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
final File dir = marker.getParentFile();
|
||||
if (dir != null && !dir.isDirectory() && !dir.mkdirs()) throw new IOException("cannot create " + dir);
|
||||
if (marker.createNewFile()) pending = marker;
|
||||
} catch (IOException e) {
|
||||
LOGGER.warn("Could not write {}: {}", marker, e.toString());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void finish() {
|
||||
if (pending == null) return;
|
||||
delete(pending);
|
||||
pending = null;
|
||||
}
|
||||
|
||||
public static boolean tripped() {
|
||||
return tripped;
|
||||
}
|
||||
|
||||
private static void delete(File marker) {
|
||||
if (marker.isFile() && !marker.delete()) {
|
||||
LOGGER.warn("Could not delete {}", marker);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package com.gtnewhorizons.angelica.glsm.backend;
|
||||
|
||||
import com.gtnewhorizons.angelica.config.SystemProperties;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.Arrays;
|
||||
|
||||
public final class MoltenVK {
|
||||
|
||||
public enum Source {
|
||||
ENV,
|
||||
JAR,
|
||||
SYSTEM,
|
||||
NONE
|
||||
}
|
||||
|
||||
public static final String ENV_VULKAN_LIBRARY = "SDL_VULKAN_LIBRARY";
|
||||
public static final String JAR_NAME = "angelica-moltenvk";
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger("Angelica/MoltenVK");
|
||||
private static final String LIB_NAME = "libMoltenVK.dylib";
|
||||
private static final String[] SYSTEM_PATHS = { "/opt/homebrew/lib/" + LIB_NAME, "/usr/local/lib/" + LIB_NAME };
|
||||
private static final String ARCH = archName(System.getProperty("os.arch", ""));
|
||||
|
||||
private static Source source;
|
||||
private static String path;
|
||||
private static boolean located;
|
||||
|
||||
private MoltenVK() {}
|
||||
|
||||
public static synchronized Source source() {
|
||||
if (source == null) {
|
||||
final boolean macos = System.getProperty("os.name", "").toLowerCase().contains("mac");
|
||||
source = detect(macos, System.getenv(ENV_VULKAN_LIBRARY), MoltenVK.class.getResource(bundledResource(ARCH)) != null, SYSTEM_PATHS);
|
||||
}
|
||||
return source;
|
||||
}
|
||||
|
||||
public static synchronized String locate() {
|
||||
if (!located) {
|
||||
path = resolve(source(), System.getenv(ENV_VULKAN_LIBRARY), bundledResource(ARCH), new File(SystemProperties.MOLTENVK_DIR), ARCH, SYSTEM_PATHS);
|
||||
located = true;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
static String archName(String osArch) {
|
||||
final String arch = osArch.toLowerCase();
|
||||
return arch.contains("aarch64") || arch.contains("arm64") ? "arm64" : "x64";
|
||||
}
|
||||
|
||||
static String bundledResource(String arch) {
|
||||
return "/macos/" + arch + "/org/lwjgl/vulkan/" + LIB_NAME;
|
||||
}
|
||||
|
||||
static Source detect(boolean macos, String env, boolean bundled, String[] systemPaths) {
|
||||
if (!macos) return Source.NONE;
|
||||
if (env != null && !env.isEmpty()) return Source.ENV;
|
||||
if (bundled) return Source.JAR;
|
||||
return systemPath(systemPaths) != null ? Source.SYSTEM : Source.NONE;
|
||||
}
|
||||
|
||||
static String resolve(Source source, String env, String resource, File dir, String arch, String[] systemPaths) {
|
||||
return switch (source) {
|
||||
case ENV -> env;
|
||||
case JAR -> {
|
||||
final String extracted = extract(resource, dir, arch);
|
||||
yield extracted != null ? extracted : systemPath(systemPaths);
|
||||
}
|
||||
case SYSTEM -> systemPath(systemPaths);
|
||||
case NONE -> null;
|
||||
};
|
||||
}
|
||||
|
||||
private static String systemPath(String[] systemPaths) {
|
||||
for (final String candidate : systemPaths) {
|
||||
if (new File(candidate).isFile()) return candidate;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String extract(String resource, File dir, String arch) {
|
||||
final byte[] lib;
|
||||
try (InputStream in = MoltenVK.class.getResourceAsStream(resource)) {
|
||||
if (in == null) return null;
|
||||
lib = readAll(in);
|
||||
} catch (IOException e) {
|
||||
LOGGER.warn("MoltenVK: failed reading {}: {}", resource, e.toString());
|
||||
return null;
|
||||
}
|
||||
|
||||
final File target = new File(dir, "libMoltenVK-" + arch + ".dylib");
|
||||
File tmp = null;
|
||||
try {
|
||||
if (!target.isFile() || target.length() != lib.length || !Arrays.equals(Files.readAllBytes(target.toPath()), lib)) {
|
||||
if (!dir.isDirectory() && !dir.mkdirs()) throw new IOException("cannot create " + dir);
|
||||
tmp = File.createTempFile("libMoltenVK", ".dylib", dir);
|
||||
Files.write(tmp.toPath(), lib);
|
||||
Files.move(tmp.toPath(), target.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOGGER.warn("MoltenVK: failed extracting to {}: {}", target, e.toString());
|
||||
if (tmp != null) tmp.delete();
|
||||
return null;
|
||||
}
|
||||
return target.getAbsolutePath();
|
||||
}
|
||||
|
||||
private static byte[] readAll(InputStream in) throws IOException {
|
||||
final ByteArrayOutputStream out = new ByteArrayOutputStream(1 << 20);
|
||||
final byte[] buf = new byte[16384];
|
||||
int n;
|
||||
while ((n = in.read(buf)) != -1) {
|
||||
out.write(buf, 0, n);
|
||||
}
|
||||
return out.toByteArray();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package com.gtnewhorizons.angelica.glsm.backend;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class BackendStartGuardTest {
|
||||
|
||||
private static File marker(Path dir) {
|
||||
return dir.resolve("angelica").resolve("sdlgpu-starting").toFile();
|
||||
}
|
||||
|
||||
@Test
|
||||
void firstStartCreatesTheMarkerAndFinishRemovesIt(@TempDir Path dir) {
|
||||
final File marker = marker(dir);
|
||||
assertFalse(BackendStartGuard.begin(marker, true, false));
|
||||
assertFalse(BackendStartGuard.tripped());
|
||||
assertTrue(marker.isFile());
|
||||
BackendStartGuard.finish();
|
||||
assertFalse(marker.exists());
|
||||
}
|
||||
|
||||
@Test
|
||||
void leftoverMarkerTripsOnceAndIsRemoved(@TempDir Path dir) {
|
||||
final File marker = marker(dir);
|
||||
assertFalse(BackendStartGuard.begin(marker, true, false));
|
||||
assertTrue(BackendStartGuard.begin(marker, true, false));
|
||||
assertTrue(BackendStartGuard.tripped());
|
||||
assertFalse(marker.exists());
|
||||
BackendStartGuard.finish();
|
||||
assertFalse(marker.exists());
|
||||
assertFalse(BackendStartGuard.begin(marker, true, false));
|
||||
assertFalse(BackendStartGuard.tripped());
|
||||
BackendStartGuard.finish();
|
||||
}
|
||||
|
||||
@Test
|
||||
void openGlConfigWritesNoMarkerAndClearsAStaleOne(@TempDir Path dir) throws IOException {
|
||||
final File marker = marker(dir);
|
||||
assertFalse(BackendStartGuard.begin(marker, false, false));
|
||||
assertFalse(marker.exists());
|
||||
assertTrue(marker.getParentFile().mkdirs());
|
||||
assertTrue(marker.createNewFile());
|
||||
assertFalse(BackendStartGuard.begin(marker, false, false));
|
||||
assertFalse(BackendStartGuard.tripped());
|
||||
assertFalse(marker.exists());
|
||||
}
|
||||
|
||||
@Test
|
||||
void forcedFlagNeverTripsOrWrites(@TempDir Path dir) throws IOException {
|
||||
final File marker = marker(dir);
|
||||
assertFalse(BackendStartGuard.begin(marker, true, true));
|
||||
assertFalse(marker.exists());
|
||||
assertTrue(marker.getParentFile().mkdirs());
|
||||
assertTrue(marker.createNewFile());
|
||||
assertFalse(BackendStartGuard.begin(marker, true, true));
|
||||
assertFalse(BackendStartGuard.tripped());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.gtnewhorizons.angelica.glsm.backend;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class MoltenVKTest {
|
||||
|
||||
private static final String PRESENT_RESOURCE = "/com/gtnewhorizons/angelica/glsm/backend/MoltenVK.class";
|
||||
private static final String ABSENT_RESOURCE = "/macos/arm64/org/lwjgl/vulkan/absent.dylib";
|
||||
|
||||
@Test
|
||||
void detectOrderIsEnvThenJarThenSystem(@TempDir Path dir) throws IOException {
|
||||
final String[] system = { Files.createFile(dir.resolve("system.dylib")).toString() };
|
||||
final String[] none = { dir.resolve("missing.dylib").toString() };
|
||||
assertEquals(MoltenVK.Source.NONE, MoltenVK.detect(false, "/env/lib.dylib", true, system));
|
||||
assertEquals(MoltenVK.Source.ENV, MoltenVK.detect(true, "/env/lib.dylib", true, system));
|
||||
assertEquals(MoltenVK.Source.JAR, MoltenVK.detect(true, "", true, system));
|
||||
assertEquals(MoltenVK.Source.SYSTEM, MoltenVK.detect(true, null, false, system));
|
||||
assertEquals(MoltenVK.Source.NONE, MoltenVK.detect(true, null, false, none));
|
||||
assertEquals(1, dir.toFile().list().length);
|
||||
}
|
||||
|
||||
@Test
|
||||
void jarIsExtractedOnceAndNotRewritten(@TempDir Path dir) throws IOException {
|
||||
final File out = dir.resolve("natives").toFile();
|
||||
final String first = MoltenVK.resolve(MoltenVK.Source.JAR, null, PRESENT_RESOURCE, out, "arm64", new String[0]);
|
||||
final File extracted = new File(out, "libMoltenVK-arm64.dylib");
|
||||
assertEquals(extracted.getAbsolutePath(), first);
|
||||
assertTrue(extracted.length() > 0);
|
||||
assertTrue(extracted.setLastModified(1_000_000L));
|
||||
assertEquals(first, MoltenVK.resolve(MoltenVK.Source.JAR, null, PRESENT_RESOURCE, out, "arm64", new String[0]));
|
||||
assertEquals(1_000_000L, extracted.lastModified());
|
||||
assertEquals(1, out.list().length);
|
||||
}
|
||||
|
||||
@Test
|
||||
void changedFileIsRewritten(@TempDir Path dir) throws IOException {
|
||||
final File extracted = new File(dir.toFile(), "libMoltenVK-arm64.dylib");
|
||||
Files.write(extracted.toPath(), new byte[] { 1, 2, 3 });
|
||||
MoltenVK.resolve(MoltenVK.Source.JAR, null, PRESENT_RESOURCE, dir.toFile(), "arm64", new String[0]);
|
||||
assertTrue(extracted.length() > 3);
|
||||
}
|
||||
|
||||
@Test
|
||||
void failedExtractionFallsBackToTheSystemInstall(@TempDir Path dir) throws IOException {
|
||||
final Path system = Files.createFile(dir.resolve("system.dylib"));
|
||||
final File notADirectory = Files.createFile(dir.resolve("blocker")).toFile();
|
||||
assertEquals(system.toString(), MoltenVK.resolve(MoltenVK.Source.JAR, null, PRESENT_RESOURCE, notADirectory, "arm64", new String[] { system.toString() }));
|
||||
assertNull(MoltenVK.resolve(MoltenVK.Source.JAR, null, ABSENT_RESOURCE, dir.toFile(), "arm64", new String[0]));
|
||||
}
|
||||
|
||||
@Test
|
||||
void envAndSystemAndNoneResolveWithoutExtracting(@TempDir Path dir) throws IOException {
|
||||
final Path system = Files.createFile(dir.resolve("system.dylib"));
|
||||
final File out = dir.resolve("natives").toFile();
|
||||
assertEquals("/env/lib.dylib", MoltenVK.resolve(MoltenVK.Source.ENV, "/env/lib.dylib", PRESENT_RESOURCE, out, "arm64", new String[0]));
|
||||
assertEquals(system.toString(), MoltenVK.resolve(MoltenVK.Source.SYSTEM, null, PRESENT_RESOURCE, out, "arm64", new String[] { system.toString() }));
|
||||
assertNull(MoltenVK.resolve(MoltenVK.Source.NONE, null, PRESENT_RESOURCE, out, "arm64", new String[] { system.toString() }));
|
||||
assertFalse(out.exists());
|
||||
}
|
||||
|
||||
@Test
|
||||
void archNames() {
|
||||
assertEquals("arm64", MoltenVK.archName("aarch64"));
|
||||
assertEquals("x64", MoltenVK.archName("x86_64"));
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,8 @@ launchwrapper = "1.12"
|
||||
# End Frozen
|
||||
|
||||
lwjgl3 = "3.4.2-SNAPSHOT"
|
||||
# Must equal the LWJGL release shipped by lwjgl3ify. Do not bump without bumping lwjgl3ify.
|
||||
lwjgl3Release = "3.4.2"
|
||||
lwjgl3ify = "3.0.31"
|
||||
|
||||
celeritas = "2.5.12-GTNH"
|
||||
@@ -75,6 +77,7 @@ lwjgl3-opengl = { module = "org.lwjgl:lwjgl-opengl", version.ref = "lwjgl3" }
|
||||
lwjgl3-sdl = { module = "org.lwjgl:lwjgl-sdl", version.ref = "lwjgl3" }
|
||||
lwjgl3-spvc = { module = "org.lwjgl:lwjgl-spvc", version.ref = "lwjgl3" }
|
||||
lwjgl3-shaderc = { module = "org.lwjgl:lwjgl-shaderc", version.ref = "lwjgl3" }
|
||||
lwjgl3-vulkan = { module = "org.lwjgl:lwjgl-vulkan", version.ref = "lwjgl3Release" }
|
||||
|
||||
# Consumed with an explicit :dev / :universal / :downgraded-8 classifier at the call site.
|
||||
gtnhlib = { module = "com.github.GTNewHorizons:GTNHLib", version.ref = "gtnhlib" }
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
plugins {
|
||||
`java-library`
|
||||
`maven-publish`
|
||||
}
|
||||
|
||||
version = rootProject.version
|
||||
|
||||
java {
|
||||
toolchain.languageVersion.set(JavaLanguageVersion.of(21))
|
||||
}
|
||||
|
||||
tasks.withType<JavaCompile>().configureEach {
|
||||
options.release.set(8)
|
||||
}
|
||||
|
||||
val rfgObfAttr = Attribute.of("com.gtnewhorizons.retrofuturagradle.obfuscation", String::class.java)
|
||||
val rfgTransformedAttr = Attribute.of("rfgDeobfuscatorTransformed", Boolean::class.javaObjectType)
|
||||
|
||||
configurations {
|
||||
listOf("apiElements", "runtimeElements").forEach { name ->
|
||||
named(name) {
|
||||
attributes {
|
||||
attribute(rfgObfAttr, "mcp")
|
||||
attribute(rfgTransformedAttr, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val moltenvkVersion = (findProperty("moltenvkVersion") as String?) ?: libs.versions.lwjgl3Release.get()
|
||||
|
||||
repositories {
|
||||
maven {
|
||||
name = "Forge"
|
||||
url = uri("https://maven.minecraftforge.net/")
|
||||
}
|
||||
maven {
|
||||
name = "Forge artifact-only"
|
||||
url = uri("https://maven.minecraftforge.net/")
|
||||
metadataSources { artifact() }
|
||||
content { includeModule("net.minecraftforge", "forge") }
|
||||
}
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
val moltenvkNatives by configurations.creating {
|
||||
isCanBeConsumed = false
|
||||
isCanBeResolved = true
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly("net.minecraftforge:forge:1.7.10-10.13.4.1614-1.7.10:universal") { isTransitive = false }
|
||||
|
||||
listOf("natives-macos", "natives-macos-arm64").forEach { nativesClassifier ->
|
||||
moltenvkNatives(libs.lwjgl3.vulkan) {
|
||||
artifact { classifier = nativesClassifier }
|
||||
isTransitive = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val extractMoltenVK = tasks.register<Sync>("extractMoltenVK") {
|
||||
val outDir = layout.buildDirectory.dir("generated/resources/moltenvk")
|
||||
from(provider { moltenvkNatives.files.map { zipTree(it) } }) {
|
||||
include("macos/**/libMoltenVK.dylib")
|
||||
}
|
||||
includeEmptyDirs = false
|
||||
into(outDir)
|
||||
doLast {
|
||||
listOf("macos/x64", "macos/arm64").forEach { dir ->
|
||||
val rel = "$dir/org/lwjgl/vulkan/libMoltenVK.dylib"
|
||||
if (!outDir.get().file(rel).asFile.isFile) {
|
||||
throw GradleException("MoltenVK dylib missing after extraction: $rel")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sourceSets["main"].resources.srcDir(extractMoltenVK)
|
||||
|
||||
val distJar = tasks.register<Jar>("distJar") {
|
||||
archiveBaseName.set("angelica-moltenvk")
|
||||
archiveVersion.set(moltenvkVersion)
|
||||
from(sourceSets["main"].output)
|
||||
manifest {
|
||||
attributes(
|
||||
"FMLCorePlugin" to "com.gtnewhorizons.angelica.moltenvk.loading.MoltenVKCorePlugin"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
create<MavenPublication>("mavenJava") {
|
||||
groupId = "com.gtnewhorizons.angelica"
|
||||
artifactId = "angelica-moltenvk"
|
||||
version = moltenvkVersion
|
||||
artifact(distJar)
|
||||
}
|
||||
}
|
||||
repositories {
|
||||
if (hasProperty("publishMoltenVK") && System.getenv("MAVEN_USER") != null) {
|
||||
maven {
|
||||
name = "GTNHMaven"
|
||||
url = uri(rootProject.findProperty("mavenPublishUrl")?.toString() ?: "https://nexus.gtnewhorizons.com/repository/releases/")
|
||||
credentials {
|
||||
username = System.getenv("MAVEN_USER")
|
||||
password = System.getenv("MAVEN_PASSWORD")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
package com.gtnewhorizons.angelica.moltenvk.loading;
|
||||
|
||||
import cpw.mods.fml.relauncher.IFMLLoadingPlugin;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@IFMLLoadingPlugin.MCVersion("1.7.10")
|
||||
public class MoltenVKCorePlugin implements IFMLLoadingPlugin {
|
||||
|
||||
@Override
|
||||
public String[] getASMTransformerClass() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModContainerClass() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSetupClass() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectData(Map<String, Object> data) {}
|
||||
|
||||
@Override
|
||||
public String getAccessTransformerClass() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -2,7 +2,7 @@ package com.gtnewhorizons.angelica.sdlgpu;
|
||||
|
||||
import static org.lwjgl.sdl.SDLVideo.SDL_PROP_WINDOW_CREATE_METAL_BOOLEAN;
|
||||
|
||||
import com.gtnewhorizons.angelica.config.SystemProperties;
|
||||
import com.gtnewhorizons.angelica.glsm.backend.BackendOptions;
|
||||
import com.gtnewhorizons.angelica.glsm.backend.BackendManager;
|
||||
import com.gtnewhorizons.angelica.glsm.backend.RenderBackend;
|
||||
import com.gtnewhorizons.angelica.glsm.loading.DependencyVerifier;
|
||||
@@ -83,7 +83,7 @@ public final class SDLGPUGate {
|
||||
|
||||
private static synchronized boolean probe() {
|
||||
if (deviceReady != null) return deviceReady;
|
||||
if (!SystemProperties.USE_SDL_GPU || !isSDLGPUAvailable()) {
|
||||
if (!BackendOptions.sdlGpuRequested() || !isSDLGPUAvailable()) {
|
||||
deviceReady = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.gtnewhorizons.angelica.glsm.CaptureGate;
|
||||
import com.gtnewhorizons.angelica.glsm.GLContextState;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.profiling.Tracy;
|
||||
import com.gtnewhorizons.angelica.glsm.backend.BackendOptions;
|
||||
import com.gtnewhorizons.angelica.glsm.backend.GLDebugMessageListener;
|
||||
import com.gtnewhorizons.angelica.glsm.backend.MainThreadPump;
|
||||
import me.eigenraven.lwjgl3ify.client.MainThreadExec;
|
||||
@@ -532,7 +533,7 @@ public class SDLGPURenderBackend extends RenderBackend {
|
||||
}
|
||||
|
||||
@Override public boolean isAvailable() {
|
||||
return SystemProperties.USE_SDL_GPU && SDLGPUGate.isSDLGPUAvailable() && SDLGPUGate.isEngaged();
|
||||
return BackendOptions.sdlGpuRequested() && SDLGPUGate.isSDLGPUAvailable() && SDLGPUGate.isEngaged();
|
||||
}
|
||||
|
||||
@Override public String getName() {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.gtnewhorizons.angelica.sdlgpu.device;
|
||||
|
||||
import com.gtnewhorizons.angelica.config.SystemProperties;
|
||||
import com.gtnewhorizons.angelica.glsm.backend.BackendOptions;
|
||||
import com.gtnewhorizons.angelica.glsm.backend.MoltenVK;
|
||||
import com.gtnewhorizons.angelica.glsm.backend.VSyncMode;
|
||||
import com.gtnewhorizons.angelica.glsm.backend.RenderBackend;
|
||||
import com.gtnewhorizons.angelica.sdlgpu.util.DebugMessageRelay;
|
||||
@@ -20,11 +22,12 @@ import org.lwjgl.system.Platform;
|
||||
import org.lwjglx.opengl.Display;
|
||||
|
||||
import java.nio.IntBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static org.lwjgl.sdl.SDLGPU.*;
|
||||
import static org.lwjgl.sdl.SDLHints.SDL_HINT_GPU_DRIVER;
|
||||
import static org.lwjgl.sdl.SDLHints.SDL_HINT_VULKAN_LIBRARY;
|
||||
import static org.lwjgl.sdl.SDLHints.SDL_SetHint;
|
||||
import static org.lwjgl.sdl.SDLVideo.*;
|
||||
import static org.lwjgl.system.MemoryUtil.memUTF8;
|
||||
@@ -82,9 +85,23 @@ public final class Device {
|
||||
throw new GpuDeviceLostException(operation, err);
|
||||
}
|
||||
|
||||
// Default to vulkan for now until D3D is more tested
|
||||
static String resolveDriverName(String userHint, boolean windows) {
|
||||
return userHint.isEmpty() && windows ? "vulkan" : null;
|
||||
static String[] driverCandidates(String requested, Platform platform) {
|
||||
final String[] platformOrder = switch (platform) {
|
||||
case MACOSX -> new String[] { "metal", "vulkan" };
|
||||
case WINDOWS -> new String[] { "vulkan", "direct3d12" };
|
||||
default -> new String[] { "vulkan" };
|
||||
};
|
||||
if (requested.isEmpty()) return platformOrder;
|
||||
final List<String> candidates = new ArrayList<>(platformOrder.length + 1);
|
||||
candidates.add(requested);
|
||||
for (final String driver : platformOrder) {
|
||||
if (!driver.equalsIgnoreCase(requested)) candidates.add(driver);
|
||||
}
|
||||
return candidates.toArray(new String[0]);
|
||||
}
|
||||
|
||||
static boolean isVulkan(String driverName) {
|
||||
return "vulkan".equalsIgnoreCase(driverName);
|
||||
}
|
||||
|
||||
static boolean isMetal(String driverName) {
|
||||
@@ -103,17 +120,16 @@ public final class Device {
|
||||
final int ver = SDLVersion.SDL_GetVersion();
|
||||
LOG.info("SDL runtime version {}.{}.{} (raw {})", SDLVersion.SDL_VERSIONNUM_MAJOR(ver), SDLVersion.SDL_VERSIONNUM_MINOR(ver), SDLVersion.SDL_VERSIONNUM_MICRO(ver), ver);
|
||||
|
||||
final String driverHint = SystemProperties.SDL_GPU_DRIVER;
|
||||
if (!driverHint.isEmpty()) {
|
||||
SDL_SetHint(SDL_HINT_GPU_DRIVER, driverHint);
|
||||
LOG.info("SDL GPU driver hint set to '{}'", driverHint);
|
||||
final String requestedDriver = BackendOptions.sdlGpuDriver();
|
||||
final String[] candidates = driverCandidates(requestedDriver, Platform.get());
|
||||
if (!requestedDriver.isEmpty()) {
|
||||
LOG.info("SDL GPU driver requested: '{}'", requestedDriver);
|
||||
}
|
||||
|
||||
final boolean gpuDebug = SystemProperties.LWJGL_DEBUG || SystemProperties.SDL_GPU_DEBUG;
|
||||
final String forcedDriver = resolveDriverName(driverHint, Platform.get() == Platform.WINDOWS);
|
||||
device = createGPUDevice(gpuDebug, forcedDriver);
|
||||
device = createGPUDevice(gpuDebug, candidates);
|
||||
if (device == 0 && VideoDriverRecovery.shouldRetryOnX11(SDL_GetCurrentVideoDriver(), vulkanLoaderAvailable(), System.getenv("DISPLAY"))) {
|
||||
device = VideoDriverRecovery.retryUnderX11(() -> createGPUDevice(gpuDebug, forcedDriver));
|
||||
device = VideoDriverRecovery.retryUnderX11(() -> createGPUDevice(gpuDebug, candidates));
|
||||
}
|
||||
if (device == 0) {
|
||||
logDeviceCreationFailure(REQUESTED_SHADER_FORMATS);
|
||||
@@ -128,7 +144,7 @@ public final class Device {
|
||||
driverVersion = SDLProperties.SDL_GetStringProperty(props, SDL_PROP_GPU_DEVICE_DRIVER_VERSION_STRING, "");
|
||||
driverInfo = SDLProperties.SDL_GetStringProperty(props, SDL_PROP_GPU_DEVICE_DRIVER_INFO_STRING, "");
|
||||
|
||||
LOG.info("SDL GPU device created: gpu={}, driver={} {}, video={}, formats=0x{}, debug={}, forcedDriver={}", deviceName, driverName, driverVersion, SDL_GetCurrentVideoDriver(), Integer.toHexString(supportedShaderFormats), gpuDebug, forcedDriver);
|
||||
LOG.info("SDL GPU device created: gpu={}, driver={} {}, video={}, formats=0x{}, debug={}, requestedDriver={}", deviceName, driverName, driverVersion, SDL_GetCurrentVideoDriver(), Integer.toHexString(supportedShaderFormats), gpuDebug, requestedDriver);
|
||||
|
||||
if (metalNeedsNewerSdl(driverName, ver)) {
|
||||
LOG.error("SDL GPU on Metal requires SDL 3.4.6 or newer (have {}.{}.{}); falling back to OpenGL", SDLVersion.SDL_VERSIONNUM_MAJOR(ver), SDLVersion.SDL_VERSIONNUM_MINOR(ver), SDLVersion.SDL_VERSIONNUM_MICRO(ver));
|
||||
@@ -151,13 +167,29 @@ public final class Device {
|
||||
}
|
||||
}
|
||||
|
||||
private long createGPUDevice(boolean gpuDebug, String forcedDriver) {
|
||||
long dev = SDL_CreateGPUDevice(REQUESTED_SHADER_FORMATS, gpuDebug, forcedDriver);
|
||||
if (dev == 0 && forcedDriver != null) {
|
||||
LOG.warn("Failed to create a '{}' SDL GPU device ({}); falling back to SDL's default backend. Set -D{} to pin one.", forcedDriver, SDLError.SDL_GetError(), SystemProperties.KEY_SDL_GPU_DRIVER);
|
||||
dev = SDL_CreateGPUDevice(REQUESTED_SHADER_FORMATS, gpuDebug, (CharSequence) null);
|
||||
private static void useMoltenVk() {
|
||||
final String path = MoltenVK.locate();
|
||||
if (path == null || MoltenVK.source() == MoltenVK.Source.ENV) return;
|
||||
if (SDL_SetHint(SDL_HINT_VULKAN_LIBRARY, path)) {
|
||||
LOG.info("MoltenVK: {}", path);
|
||||
} else {
|
||||
LOG.warn("Could not point SDL at MoltenVK {}: {}", path, SDLError.SDL_GetError());
|
||||
}
|
||||
return dev;
|
||||
}
|
||||
|
||||
private long createGPUDevice(boolean gpuDebug, String[] candidates) {
|
||||
final boolean macos = Platform.get() == Platform.MACOSX;
|
||||
for (final String driver : candidates) {
|
||||
final boolean macVulkan = macos && isVulkan(driver);
|
||||
if (macVulkan) useMoltenVk();
|
||||
final long dev = SDL_CreateGPUDevice(REQUESTED_SHADER_FORMATS, gpuDebug, driver);
|
||||
if (dev != 0) return dev;
|
||||
LOG.warn("Failed to create a '{}' SDL GPU device: {}", driver, SDLError.SDL_GetError());
|
||||
if (macVulkan && MoltenVK.locate() == null) {
|
||||
LOG.warn("Vulkan on macOS needs MoltenVK. Add {} to the mods folder or install MoltenVK.", MoltenVK.JAR_NAME);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void claimWindow(long window) {
|
||||
@@ -213,7 +245,7 @@ public final class Device {
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG.error("Continuing on OpenGL. Set -D{}=false to skip this probe entirely.", SystemProperties.KEY_USE_SDL_GPU);
|
||||
LOG.error("Continuing on OpenGL. Set Video Settings > Renderer > Backend to OpenGL, or -D{}=false, to skip this probe entirely.", SystemProperties.KEY_USE_SDL_GPU);
|
||||
}
|
||||
|
||||
public void destroyDevice() {
|
||||
|
||||
+15
-11
@@ -1,32 +1,36 @@
|
||||
package com.gtnewhorizons.angelica.sdlgpu.device;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.lwjgl.system.Platform;
|
||||
|
||||
import static com.gtnewhorizons.angelica.sdlgpu.device.Device.driverCandidates;
|
||||
import static com.gtnewhorizons.angelica.sdlgpu.device.Device.metalNeedsNewerSdl;
|
||||
import static com.gtnewhorizons.angelica.sdlgpu.device.Device.resolveDriverName;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.lwjgl.sdl.SDLVersion.SDL_VERSIONNUM;
|
||||
|
||||
class DriverSelectionTest {
|
||||
|
||||
@Test
|
||||
void windowsWithoutUserHintForcesVulkan() {
|
||||
assertEquals("vulkan", resolveDriverName("", true));
|
||||
void autoUsesThePlatformOrder() {
|
||||
assertArrayEquals(new String[] { "metal", "vulkan" }, driverCandidates("", Platform.MACOSX));
|
||||
assertArrayEquals(new String[] { "vulkan", "direct3d12" }, driverCandidates("", Platform.WINDOWS));
|
||||
assertArrayEquals(new String[] { "vulkan" }, driverCandidates("", Platform.LINUX));
|
||||
}
|
||||
|
||||
@Test
|
||||
void userHintWinsOnWindows() {
|
||||
assertNull(resolveDriverName("direct3d12", true));
|
||||
assertNull(resolveDriverName("vulkan", true));
|
||||
void requestedDriverGoesFirstWithoutDuplicates() {
|
||||
assertArrayEquals(new String[] { "vulkan", "metal" }, driverCandidates("vulkan", Platform.MACOSX));
|
||||
assertArrayEquals(new String[] { "direct3d12", "vulkan" }, driverCandidates("direct3d12", Platform.WINDOWS));
|
||||
assertArrayEquals(new String[] { "vulkan" }, driverCandidates("vulkan", Platform.LINUX));
|
||||
assertArrayEquals(new String[] { "Vulkan", "direct3d12" }, driverCandidates("Vulkan", Platform.WINDOWS));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nonWindowsIsUntouched() {
|
||||
assertNull(resolveDriverName("", false));
|
||||
assertNull(resolveDriverName("direct3d12", false));
|
||||
void unsupportedDriverStillFallsBack() {
|
||||
assertArrayEquals(new String[] { "metal", "vulkan", "direct3d12" }, driverCandidates("metal", Platform.WINDOWS));
|
||||
assertArrayEquals(new String[] { "bogus", "vulkan" }, driverCandidates("bogus", Platform.LINUX));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -25,4 +25,5 @@ apply(from = file("experimental-surround/surround.settings.gradle.kts"))
|
||||
include("glsm")
|
||||
include("lwjgl3-backend")
|
||||
include("tracy-client")
|
||||
include("moltenvk")
|
||||
include("sdl-gpu")
|
||||
@@ -0,0 +1,174 @@
|
||||
package com.gtnewhorizons.angelica.client.gui;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.gtnewhorizons.angelica.config.AngelicaConfig;
|
||||
import com.gtnewhorizons.angelica.config.GLVersionChoice;
|
||||
import com.gtnewhorizons.angelica.config.RenderBackendChoice;
|
||||
import com.gtnewhorizons.angelica.config.SdlGpuDriver;
|
||||
import com.gtnewhorizons.angelica.config.SystemProperties;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.RenderSystem;
|
||||
import com.gtnewhorizons.angelica.glsm.backend.BackendManager;
|
||||
import com.gtnewhorizons.angelica.glsm.backend.BackendOptions;
|
||||
import com.gtnewhorizons.angelica.glsm.backend.BackendStartGuard;
|
||||
import com.gtnewhorizons.angelica.glsm.backend.MoltenVK;
|
||||
import com.gtnewhorizons.angelica.sdlgpu.SDLGPUGate;
|
||||
import me.flashyreese.mods.reeses_sodium_options.client.gui.ReeseSodiumVideoOptionsScreen;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.ActionOption;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.OptionFlag;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.OptionGroup;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.OptionImpl;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.OptionPage;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.control.CyclingControl;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.storage.AngelicaOptionsStorage;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
import net.minecraft.util.Util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class RendererOptionPages {
|
||||
|
||||
private static final AngelicaOptionsStorage angelicaOpts = new AngelicaOptionsStorage();
|
||||
|
||||
public static OptionPage renderer() {
|
||||
final Util.EnumOS os = Util.getOSType();
|
||||
final boolean sdlAvailable = SDLGPUGate.isSDLGPUAvailable();
|
||||
final RenderBackendChoice[] backends = sdlAvailable ? RenderBackendChoice.values() : new RenderBackendChoice[] { RenderBackendChoice.OPENGL };
|
||||
final SdlGpuDriver[] drivers = allowedDrivers(os);
|
||||
final GLVersionChoice[] glVersions = allowedGlVersions(glVersionCeiling(os));
|
||||
final String active = activeLabel();
|
||||
|
||||
final OptionGroup.Builder status = OptionGroup.createBuilder()
|
||||
.add(ActionOption.label(I18n.format("options.angelica.renderer.status"), I18n.format("options.angelica.renderer.status.tooltip"), statusLabel()))
|
||||
.add(ActionOption.label(I18n.format("options.angelica.renderer.active"), I18n.format("options.angelica.renderer.active.tooltip"), () -> active));
|
||||
if (os == Util.EnumOS.OSX) {
|
||||
final String moltenVk = I18n.format("options.angelica.renderer.moltenvk." + MoltenVK.source().name().toLowerCase());
|
||||
status.add(ActionOption.label(I18n.format("options.angelica.renderer.moltenvk"), I18n.format("options.angelica.renderer.moltenvk.tooltip"), () -> moltenVk));
|
||||
}
|
||||
|
||||
return new OptionPage(I18n.format("options.angelica.renderer.page"), ImmutableList.of(
|
||||
OptionGroup.createBuilder()
|
||||
.add(OptionImpl.createBuilder(RenderBackendChoice.class, angelicaOpts)
|
||||
.setName(I18n.format("options.angelica.renderer.backend"))
|
||||
.setTooltip(overrideTooltip(backendTooltip(sdlAvailable), SystemProperties.KEY_USE_SDL_GPU, SystemProperties.SDL_GPU_OVERRIDE != null))
|
||||
.setControl(o -> new CyclingControl<>(o, RenderBackendChoice.class, backends))
|
||||
.setBinding((opts, value) -> AngelicaConfig.renderBackend = value, opts -> backendOf(SystemProperties.SDL_GPU_OVERRIDE != null ? SystemProperties.SDL_GPU_OVERRIDE : AngelicaConfig.sdlGpuConfigured()))
|
||||
.setEnabled(SystemProperties.SDL_GPU_OVERRIDE == null)
|
||||
.setFlags(OptionFlag.REQUIRES_GAME_RESTART)
|
||||
.build())
|
||||
.add(OptionImpl.createBuilder(SdlGpuDriver.class, angelicaOpts)
|
||||
.setName(I18n.format("options.angelica.renderer.driver"))
|
||||
.setTooltip(overrideTooltip(driverTooltip(os), SystemProperties.KEY_SDL_GPU_DRIVER, SystemProperties.SDL_GPU_DRIVER_OVERRIDE != null))
|
||||
.setControl(o -> new CyclingControl<>(o, SdlGpuDriver.class, drivers))
|
||||
.setBinding((opts, value) -> AngelicaConfig.sdlGpuDriver = value, opts -> shownDriver())
|
||||
.setEnabled(SystemProperties.SDL_GPU_DRIVER_OVERRIDE == null)
|
||||
.setFlags(OptionFlag.REQUIRES_GAME_RESTART)
|
||||
.build())
|
||||
.add(OptionImpl.createBuilder(GLVersionChoice.class, angelicaOpts)
|
||||
.setName(I18n.format("options.angelica.renderer.glVersion"))
|
||||
.setTooltip(I18n.format("options.angelica.renderer.glVersion.tooltip"))
|
||||
.setControl(o -> new CyclingControl<>(o, GLVersionChoice.class, glVersions, glVersionNames()))
|
||||
.setBinding((opts, value) -> AngelicaConfig.glVersion = value.version(), opts -> GLVersionChoice.of(AngelicaConfig.glVersion, GLVersionChoice.GL46.version()))
|
||||
.setFlags(OptionFlag.REQUIRES_GAME_RESTART)
|
||||
.build())
|
||||
.build(),
|
||||
status.build()));
|
||||
}
|
||||
|
||||
public static OptionPage withLink(OptionPage general, ReeseSodiumVideoOptionsScreen gui) {
|
||||
final String rendererPage = I18n.format("options.angelica.renderer.page");
|
||||
final String active = activeLabel();
|
||||
return new OptionPage(general.getName(), ImmutableList.<OptionGroup>builder()
|
||||
.add(OptionGroup.createBuilder()
|
||||
.add(new ActionOption(I18n.format("options.angelica.renderer.link"), I18n.format("options.angelica.renderer.link.tooltip"),
|
||||
() -> active, () -> gui.showPage(rendererPage), () -> true))
|
||||
.build())
|
||||
.addAll(general.getGroups())
|
||||
.build());
|
||||
}
|
||||
|
||||
private static RenderBackendChoice backendOf(boolean sdlGpu) {
|
||||
return sdlGpu ? RenderBackendChoice.SDL_GPU : RenderBackendChoice.OPENGL;
|
||||
}
|
||||
|
||||
private static SdlGpuDriver shownDriver() {
|
||||
final SdlGpuDriver forced = SystemProperties.SDL_GPU_DRIVER_OVERRIDE != null ? SdlGpuDriver.fromSdlName(SystemProperties.SDL_GPU_DRIVER_OVERRIDE) : null;
|
||||
if (forced != null) return forced;
|
||||
return AngelicaConfig.sdlGpuDriver != null ? AngelicaConfig.sdlGpuDriver : SdlGpuDriver.AUTO;
|
||||
}
|
||||
|
||||
static SdlGpuDriver[] allowedDrivers(Util.EnumOS os) {
|
||||
return switch (os) {
|
||||
case OSX -> new SdlGpuDriver[] { SdlGpuDriver.AUTO, SdlGpuDriver.METAL, SdlGpuDriver.VULKAN };
|
||||
case WINDOWS -> new SdlGpuDriver[] { SdlGpuDriver.AUTO, SdlGpuDriver.VULKAN, SdlGpuDriver.D3D12 };
|
||||
default -> new SdlGpuDriver[] { SdlGpuDriver.AUTO, SdlGpuDriver.VULKAN };
|
||||
};
|
||||
}
|
||||
|
||||
private static int glVersionCeiling(Util.EnumOS os) {
|
||||
final int platformMax = os == Util.EnumOS.OSX ? 41 : 46;
|
||||
final int pinned = AngelicaConfig.pinnedGLVersion;
|
||||
return pinned >= 33 && pinned < platformMax ? pinned : platformMax;
|
||||
}
|
||||
|
||||
static GLVersionChoice[] allowedGlVersions(int ceiling) {
|
||||
final List<GLVersionChoice> allowed = new ArrayList<>();
|
||||
for (final GLVersionChoice choice : GLVersionChoice.values()) {
|
||||
if (choice.version() <= ceiling) allowed.add(choice);
|
||||
}
|
||||
return allowed.toArray(new GLVersionChoice[0]);
|
||||
}
|
||||
|
||||
private static String[] glVersionNames() {
|
||||
final GLVersionChoice[] universe = GLVersionChoice.values();
|
||||
final String[] names = new String[universe.length];
|
||||
for (int i = 0; i < universe.length; i++) {
|
||||
names[i] = universe[i] == GLVersionChoice.AUTO ? I18n.format("options.angelica.renderer.glVersion.auto") : universe[i].label();
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
private static String backendTooltip(boolean sdlAvailable) {
|
||||
final String base = EnumChatFormatting.RED + I18n.format("options.angelica.renderer.backend.experimental") + EnumChatFormatting.RESET + " " + I18n.format("options.angelica.renderer.backend.tooltip");
|
||||
return sdlAvailable ? base : base + " " + I18n.format("options.angelica.renderer.backend.unavailable", SDLGPUGate.missingRequirement());
|
||||
}
|
||||
|
||||
private static String driverTooltip(Util.EnumOS os) {
|
||||
final String base = I18n.format("options.angelica.renderer.driver.tooltip");
|
||||
return switch (os) {
|
||||
case OSX -> base + " " + I18n.format("options.angelica.renderer.driver.tooltip.macos");
|
||||
case WINDOWS -> base + " " + I18n.format("options.angelica.renderer.driver.tooltip.windows") + " " + EnumChatFormatting.RED + I18n.format("options.angelica.renderer.driver.tooltip.d3d12") + EnumChatFormatting.RESET;
|
||||
default -> base + " " + I18n.format("options.angelica.renderer.driver.tooltip.other");
|
||||
};
|
||||
}
|
||||
|
||||
private static Supplier<String> statusLabel() {
|
||||
final String restartLabel = I18n.format("options.angelica.status.restart");
|
||||
final String forcedLabel = I18n.format("options.angelica.renderer.status.forced");
|
||||
final String failedLabel = I18n.format("options.angelica.renderer.status.failed");
|
||||
final String activeLabel = I18n.format("options.angelica.renderer.status.active");
|
||||
final String resetLabel = I18n.format("options.angelica.renderer.status.reset");
|
||||
return () -> {
|
||||
if (AngelicaConfig.sdlGpuConfigured() != BackendOptions.configSdlGpu()
|
||||
|| !AngelicaConfig.sdlGpuDriverName().equals(BackendOptions.configDriver())
|
||||
|| AngelicaConfig.glVersion != BackendOptions.configGlVersion()) {
|
||||
return restartLabel;
|
||||
}
|
||||
if (BackendStartGuard.tripped() && !AngelicaConfig.sdlGpuConfigured()) return resetLabel;
|
||||
if (BackendOptions.sdlGpuRequested() && !BackendManager.RENDER_BACKEND.isSDLGPU()) return failedLabel;
|
||||
return SystemProperties.SDL_GPU_OVERRIDE != null || SystemProperties.SDL_GPU_DRIVER_OVERRIDE != null ? forcedLabel : activeLabel;
|
||||
};
|
||||
}
|
||||
|
||||
private static String activeLabel() {
|
||||
final String name = GLStateManager.getRenderBackendName();
|
||||
return BackendManager.RENDER_BACKEND.isSDLGPU() ? name : name + " " + RenderSystem.getGlMajor() + "." + RenderSystem.getGlMinor();
|
||||
}
|
||||
|
||||
static String overrideTooltip(String base, String flag, boolean overridden) {
|
||||
return overridden ? base + " " + I18n.format("options.angelica.overriddenBy", flag) : base;
|
||||
}
|
||||
}
|
||||
@@ -34,7 +34,7 @@ public class TracyOptionPages {
|
||||
default -> startLabel;
|
||||
};
|
||||
|
||||
final String restartLabel = I18n.format("options.angelica.tracy.status.restart");
|
||||
final String restartLabel = I18n.format("options.angelica.status.restart");
|
||||
final String runningLabel = I18n.format("options.angelica.tracy.status.running");
|
||||
final String runningForcedLabel = I18n.format("options.angelica.tracy.status.runningForced");
|
||||
final String failedLabel = I18n.format("options.angelica.tracy.status.failed");
|
||||
@@ -87,8 +87,7 @@ public class TracyOptionPages {
|
||||
.build())
|
||||
.build(),
|
||||
OptionGroup.createBuilder()
|
||||
.add(new ActionOption(I18n.format("options.angelica.tracy.status"), I18n.format("options.angelica.tracy.status.tooltip"),
|
||||
statusLabel, () -> {}, () -> false))
|
||||
.add(ActionOption.label(I18n.format("options.angelica.tracy.status"), I18n.format("options.angelica.tracy.status.tooltip"), statusLabel))
|
||||
.build(),
|
||||
OptionGroup.createBuilder()
|
||||
.add(OptionImpl.createBuilder(int.class, angelicaOpts)
|
||||
@@ -104,7 +103,6 @@ public class TracyOptionPages {
|
||||
}
|
||||
|
||||
private static String overrideTooltip(String baseKey, String flag, boolean overridden) {
|
||||
final String base = I18n.format(baseKey);
|
||||
return overridden ? base + " " + I18n.format("options.angelica.tracy.overriddenBy", flag) : base;
|
||||
return RendererOptionPages.overrideTooltip(I18n.format(baseKey), flag, overridden);
|
||||
}
|
||||
}
|
||||
@@ -55,14 +55,6 @@ public class AngelicaConfig {
|
||||
@Config.RequiresMcRestart
|
||||
public static int workerThreadCount;
|
||||
|
||||
@Config.Comment("Enable NotFine Options")
|
||||
@Config.DefaultBoolean(false)
|
||||
public static boolean enableNotFineOptions;
|
||||
|
||||
@Config.Comment("Enable Reese's Sodium Options")
|
||||
@Config.DefaultBoolean(true)
|
||||
public static boolean enableReesesSodiumOptions;
|
||||
|
||||
@Config.Comment("Inject BakedModel rendering into some vanilla blocks")
|
||||
@Config.DefaultBoolean(false)
|
||||
@Config.RequiresMcRestart
|
||||
@@ -468,6 +460,22 @@ public class AngelicaConfig {
|
||||
@Config.RequiresMcRestart
|
||||
public static boolean disableGLVersionPinning;
|
||||
|
||||
@Config.Comment("Requested OpenGL context version as an integer (e.g. 46, 41, 33). 0 = highest available. Falls back to probing when the version cannot be created.")
|
||||
@Config.DefaultInt(0)
|
||||
@Config.RangeInt(min = 0, max = 46)
|
||||
@Config.RequiresMcRestart
|
||||
public static int glVersion;
|
||||
|
||||
@Config.Comment("Render backend: OPENGL, or SDL_GPU (experimental; Vulkan/Metal/Direct3D 12 through SDL3, falls back to OpenGL when no device can be created). -Dangelica.sdlgpu.enable=true|false overrides this.")
|
||||
@Config.DefaultEnum("OPENGL")
|
||||
@Config.RequiresMcRestart
|
||||
public static RenderBackendChoice renderBackend;
|
||||
|
||||
@Config.Comment("SDL GPU driver: AUTO, VULKAN, METAL (macOS), D3D12 (Windows). Vulkan on macOS needs MoltenVK and uses Metal without it. -Dangelica.sdlgpu.driver overrides this.")
|
||||
@Config.DefaultEnum("AUTO")
|
||||
@Config.RequiresMcRestart
|
||||
public static SdlGpuDriver sdlGpuDriver;
|
||||
|
||||
@Config.Comment("Disables GL Error checks. Always set to false in dev env or if LWJGL debug is on. Improves performance.")
|
||||
@Config.DefaultBoolean(true)
|
||||
@Config.RequiresMcRestart
|
||||
@@ -536,6 +544,14 @@ public class AngelicaConfig {
|
||||
return enableEntityBatching && enableCubeInstancing;
|
||||
}
|
||||
|
||||
public static boolean sdlGpuConfigured() {
|
||||
return renderBackend == RenderBackendChoice.SDL_GPU;
|
||||
}
|
||||
|
||||
public static String sdlGpuDriverName() {
|
||||
return sdlGpuDriver == null ? "" : sdlGpuDriver.sdlName();
|
||||
}
|
||||
|
||||
public static GLProfile getEffectiveGlProfile() {
|
||||
final String sys = SystemProperties.GL_PROFILE.trim().toUpperCase();
|
||||
if ("GLES".equals(sys)) return GLProfile.ES;
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.gtnewhorizons.angelica.config;
|
||||
|
||||
public enum GLVersionChoice {
|
||||
AUTO(0),
|
||||
GL33(33),
|
||||
GL40(40),
|
||||
GL41(41),
|
||||
GL42(42),
|
||||
GL43(43),
|
||||
GL44(44),
|
||||
GL45(45),
|
||||
GL46(46);
|
||||
|
||||
private final int version;
|
||||
|
||||
GLVersionChoice(int version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public int version() { return version; }
|
||||
|
||||
public String label() {
|
||||
return version / 10 + "." + version % 10;
|
||||
}
|
||||
|
||||
public static GLVersionChoice of(int version, int ceiling) {
|
||||
GLVersionChoice best = AUTO;
|
||||
for (final GLVersionChoice choice : values()) {
|
||||
if (choice.version != 0 && choice.version <= version && choice.version <= ceiling) best = choice;
|
||||
}
|
||||
return best;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.gtnewhorizons.angelica.config;
|
||||
|
||||
import me.jellysquid.mods.sodium.client.gui.options.named.NamedState;
|
||||
|
||||
public enum RenderBackendChoice implements NamedState {
|
||||
OPENGL ("options.angelica.renderer.backend.opengl"),
|
||||
SDL_GPU("options.angelica.renderer.backend.sdl_gpu");
|
||||
|
||||
private final String key;
|
||||
|
||||
RenderBackendChoice(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.gtnewhorizons.angelica.config;
|
||||
|
||||
import me.jellysquid.mods.sodium.client.gui.options.named.NamedState;
|
||||
|
||||
public enum SdlGpuDriver implements NamedState {
|
||||
AUTO ("", "options.angelica.renderer.driver.auto"),
|
||||
VULKAN("vulkan", "options.angelica.renderer.driver.vulkan"),
|
||||
METAL ("metal", "options.angelica.renderer.driver.metal"),
|
||||
D3D12 ("direct3d12", "options.angelica.renderer.driver.d3d12");
|
||||
|
||||
private final String sdlName;
|
||||
private final String key;
|
||||
|
||||
SdlGpuDriver(String sdlName, String key) {
|
||||
this.sdlName = sdlName;
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public String sdlName() { return sdlName; }
|
||||
|
||||
public static SdlGpuDriver fromSdlName(String sdlName) {
|
||||
for (final SdlGpuDriver driver : values()) {
|
||||
if (driver.sdlName.equalsIgnoreCase(sdlName)) return driver;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,10 @@ import com.gtnewhorizon.gtnhmixins.builders.ITransformers;
|
||||
import com.gtnewhorizons.angelica.config.AngelicaConfig;
|
||||
import com.gtnewhorizons.angelica.config.CompatConfig;
|
||||
import com.gtnewhorizons.angelica.config.FontConfig;
|
||||
import com.gtnewhorizons.angelica.config.RenderBackendChoice;
|
||||
import com.gtnewhorizons.angelica.config.SystemProperties;
|
||||
import com.gtnewhorizons.angelica.glsm.backend.BackendOptions;
|
||||
import com.gtnewhorizons.angelica.glsm.backend.BackendStartGuard;
|
||||
import com.gtnewhorizons.angelica.glsm.loading.DependencyVerifier;
|
||||
import com.gtnewhorizons.angelica.glsm.loading.Lwjgl3ifyExclusions;
|
||||
import com.gtnewhorizons.angelica.glsm.profiling.TracyOptions;
|
||||
@@ -33,6 +36,7 @@ import org.apache.logging.log4j.core.config.LoggerConfig;
|
||||
import org.spongepowered.asm.launch.GlobalProperties;
|
||||
import org.spongepowered.asm.service.mojang.MixinServiceLaunchWrapper;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@@ -68,6 +72,12 @@ public final class AngelicaClientTweaker implements IFMLLoadingPlugin, IEarlyMix
|
||||
// Angelica Config
|
||||
ConfigurationManager.registerConfig(AngelicaConfig.class);
|
||||
TracyOptions.latch(AngelicaConfig.enableTracy, AngelicaConfig.tracyAllowRemote, AngelicaConfig.tracyFineZones, AngelicaConfig.tracyMaxSrcLocs);
|
||||
if (BackendStartGuard.begin(new File(Launch.minecraftHome, "angelica" + File.separator + "sdlgpu-starting"), AngelicaConfig.sdlGpuConfigured(), SystemProperties.SDL_GPU_OVERRIDE != null)) {
|
||||
LOGGER.warn("The last start with SDL GPU did not reach the main menu; resetting the render backend to OpenGL");
|
||||
AngelicaConfig.renderBackend = RenderBackendChoice.OPENGL;
|
||||
ConfigurationManager.save(AngelicaConfig.class);
|
||||
}
|
||||
BackendOptions.latch(AngelicaConfig.sdlGpuConfigured(), AngelicaConfig.sdlGpuDriverName(), AngelicaConfig.glVersion);
|
||||
ConfigurationManager.registerConfig(CompatConfig.class);
|
||||
ConfigurationManager.registerConfig(FontConfig.class);
|
||||
MCPatcherForgeConfig.registerConfig();
|
||||
@@ -89,7 +99,7 @@ public final class AngelicaClientTweaker implements IFMLLoadingPlugin, IEarlyMix
|
||||
DependencyVerifier.gtnhLibChecks("Angelica"), LOGGER,
|
||||
(title, message) -> MissingDependencySdl.showFatal(title, message));
|
||||
|
||||
if (SystemProperties.USE_SDL_GPU) {
|
||||
if (BackendOptions.sdlGpuRequested()) {
|
||||
if (SDLGPUGate.isSDLGPUAvailable()) {
|
||||
LOGGER.info("SDL GPU window mode enabled");
|
||||
} else {
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.gtnewhorizons.angelica.config.AngelicaConfig;
|
||||
import com.gtnewhorizons.angelica.config.CompatConfig;
|
||||
import com.gtnewhorizons.angelica.config.SystemProperties;
|
||||
import com.gtnewhorizons.angelica.glsm.CaptureGate;
|
||||
import com.gtnewhorizons.angelica.glsm.backend.BackendOptions;
|
||||
import com.gtnewhorizons.angelica.glsm.profiling.TracyOptions;
|
||||
import com.gtnewhorizons.angelica.sdlgpu.SDLGPUGate;
|
||||
import jss.notfine.config.MCPatcherForgeConfig;
|
||||
@@ -104,7 +105,7 @@ public enum Mixins implements IMixins {
|
||||
|
||||
ANGELICA_SDL_GPU_DISPLAY(new MixinBuilder("SDL-GPU-aware Display.create path")
|
||||
.setPhase(Phase.EARLY)
|
||||
.setApplyIf(() -> SystemProperties.USE_SDL_GPU && SDLGPUGate.isSDLGPUAvailable())
|
||||
.setApplyIf(() -> BackendOptions.sdlGpuRequested() && SDLGPUGate.isSDLGPUAvailable())
|
||||
.addClientMixins(
|
||||
"sdlgpu.MixinForgeHooksClient_SDLGPUDisplay",
|
||||
"sdlgpu.MixinMinecraft_SDLGPUIcons"
|
||||
|
||||
@@ -62,6 +62,7 @@ import com.gtnewhorizons.angelica.debug.TPSGraph;
|
||||
import com.gtnewhorizons.angelica.dynamiclights.DynamicLights;
|
||||
import com.gtnewhorizons.angelica.dynamiclights.config.EntityLightConfig;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.backend.BackendStartGuard;
|
||||
import com.gtnewhorizons.angelica.glsm.backend.VSyncMode;
|
||||
import com.gtnewhorizons.angelica.glsm.profiling.Tracy;
|
||||
import com.gtnewhorizons.angelica.glsm.shader.ShaderDiskCache;
|
||||
@@ -97,13 +98,10 @@ import cpw.mods.fml.common.gameevent.TickEvent;
|
||||
import cpw.mods.fml.common.registry.GameData;
|
||||
import cpw.mods.fml.relauncher.ReflectionHelper;
|
||||
import jss.notfine.core.Settings;
|
||||
import jss.notfine.gui.GuiCustomMenu;
|
||||
import jss.notfine.gui.NotFineGameOptionPages;
|
||||
import jss.notfine.gui.options.named.FOVMode;
|
||||
import me.flashyreese.mods.reeses_sodium_options.client.gui.ReeseSodiumVideoOptionsScreen;
|
||||
import me.jellysquid.mods.sodium.client.gui.FrameRateOptions;
|
||||
import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions;
|
||||
import me.jellysquid.mods.sodium.client.gui.SodiumOptionsGUI;
|
||||
import net.coderbot.iris.Iris;
|
||||
import net.coderbot.iris.client.IrisDebugScreenHandler;
|
||||
|
||||
@@ -388,6 +386,7 @@ public final class ClientProxy extends CommonProxy {
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.LOWEST)
|
||||
public void onGuiOpen(GuiOpenEvent event) {
|
||||
BackendStartGuard.finish();
|
||||
if (!event.isCanceled()) {
|
||||
if (event.gui instanceof GuiMainMenu && gameStartTime == -1) {
|
||||
gameStartTime = ManagementFactory.getRuntimeMXBean().getUptime() / 1000f;
|
||||
@@ -403,19 +402,7 @@ public final class ClientProxy extends CommonProxy {
|
||||
public void onGuiInit(GuiScreenEvent.InitGuiEvent.Pre event) {
|
||||
if (event.gui instanceof GuiVideoSettings eventGui) {
|
||||
event.setCanceled(true);
|
||||
if (AngelicaConfig.enableNotFineOptions || GuiScreen.isShiftKeyDown()) {
|
||||
Minecraft.getMinecraft().displayGuiScreen(new GuiCustomMenu(
|
||||
eventGui.parentGuiScreen,
|
||||
NotFineGameOptionPages.general(),
|
||||
NotFineGameOptionPages.detail(),
|
||||
NotFineGameOptionPages.atmosphere(),
|
||||
NotFineGameOptionPages.particles(),
|
||||
NotFineGameOptionPages.other()));
|
||||
} else if (!AngelicaConfig.enableReesesSodiumOptions || GuiScreen.isCtrlKeyDown()) {
|
||||
Minecraft.getMinecraft().displayGuiScreen(new SodiumOptionsGUI(eventGui.parentGuiScreen));
|
||||
} else {
|
||||
Minecraft.getMinecraft().displayGuiScreen(new ReeseSodiumVideoOptionsScreen(eventGui.parentGuiScreen));
|
||||
}
|
||||
Minecraft.getMinecraft().displayGuiScreen(new ReeseSodiumVideoOptionsScreen(eventGui.parentGuiScreen));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
package jss.notfine.gui;
|
||||
|
||||
import me.jellysquid.mods.sodium.client.gui.options.OptionPage;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.storage.OptionStorage;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.client.gui.ScaledResolution;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import org.lwjgl.input.Keyboard;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
public class GuiCustomMenu extends GuiScreen {
|
||||
public static GuiCustomMenu instance;
|
||||
public static HashSet<OptionStorage<?>> dirtyStorages = new HashSet<>();
|
||||
private final GuiScreen parentGuiScreen;
|
||||
private final OptionPage optionPage;
|
||||
private final OptionPage[] subPages;
|
||||
protected String screenTitle;
|
||||
|
||||
private GuiCustomOptionsRowList optionsRowList;
|
||||
|
||||
public GuiCustomMenu(GuiScreen parentGuiScreen, OptionPage optionPage, OptionPage... subPages) {
|
||||
this.parentGuiScreen = parentGuiScreen;
|
||||
this.screenTitle = optionPage.getName();
|
||||
this.optionPage = optionPage;
|
||||
this.subPages = subPages;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initGui() {
|
||||
Keyboard.enableRepeatEvents(true);
|
||||
buttonList.clear();
|
||||
buttonList.add(new GuiButton(200, width / 2 - 110, height - 27, I18n.format("gui.done")));
|
||||
optionsRowList = new GuiCustomOptionsRowList(mc, width, height, 32, height - 32, 25, optionPage, subPages);
|
||||
instance = this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void actionPerformed(GuiButton button) {
|
||||
if(button.enabled && button.id == 200) {
|
||||
if(!(parentGuiScreen instanceof GuiCustomMenu)) {
|
||||
saveChanges();
|
||||
}
|
||||
mc.displayGuiScreen(parentGuiScreen);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void mouseClicked(int mouseX, int mouseY, int mouseButton) {
|
||||
int originalScale = mc.gameSettings.guiScale;
|
||||
|
||||
super.mouseClicked(mouseX, mouseY, mouseButton);
|
||||
optionsRowList.func_148179_a(mouseX, mouseY, mouseButton);
|
||||
|
||||
if(mc.gameSettings.guiScale != originalScale) {
|
||||
ScaledResolution scaledresolution = new ScaledResolution(mc, mc.displayWidth, mc.displayHeight);
|
||||
setWorldAndResolution(mc, scaledresolution.getScaledWidth(), scaledresolution.getScaledHeight());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void mouseMovedOrUp(int mouseX, int mouseY, int state) {
|
||||
int originalScale = mc.gameSettings.guiScale;
|
||||
|
||||
super.mouseMovedOrUp(mouseX, mouseY, state);
|
||||
optionsRowList.func_148181_b(mouseX, mouseY, state);
|
||||
|
||||
if(mc.gameSettings.guiScale != originalScale) {
|
||||
ScaledResolution scaledresolution = new ScaledResolution(mc, mc.displayWidth, mc.displayHeight);
|
||||
setWorldAndResolution(mc, scaledresolution.getScaledWidth(), scaledresolution.getScaledHeight());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawScreen(int mouseX, int mouseY, float partialTicks) {
|
||||
if(mc.theWorld != null && Keyboard.isKeyDown(Keyboard.KEY_F1)) {
|
||||
return;
|
||||
}
|
||||
drawDefaultBackground();
|
||||
optionsRowList.drawScreen(mouseX, mouseY, partialTicks);
|
||||
drawCenteredString(fontRendererObj, screenTitle, width / 2, 5, 16777215);
|
||||
super.drawScreen(mouseX, mouseY, partialTicks);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void keyTyped(char typedChar, int keyCode) {
|
||||
if(keyCode == Keyboard.KEY_ESCAPE && !(parentGuiScreen instanceof GuiCustomMenu)) {
|
||||
saveChanges();
|
||||
}
|
||||
optionsRowList.keyTyped(keyCode);
|
||||
super.keyTyped(typedChar, keyCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGuiClosed() {
|
||||
Keyboard.enableRepeatEvents(false);
|
||||
}
|
||||
|
||||
private void saveChanges() {
|
||||
for(OptionStorage<?> storage : dirtyStorages) {
|
||||
storage.save();
|
||||
}
|
||||
dirtyStorages = new HashSet<>();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package jss.notfine.gui;
|
||||
|
||||
import me.jellysquid.mods.sodium.client.gui.options.OptionPage;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
|
||||
public class GuiCustomMenuButton extends GuiButton {
|
||||
|
||||
private final OptionPage optionPage;
|
||||
private final OptionPage[] subPages;
|
||||
|
||||
public GuiCustomMenuButton(int xPosition, int yPosition, int width, int height, OptionPage optionPage, OptionPage... subPages) {
|
||||
super(-10, xPosition, yPosition, width, height, optionPage.getName());
|
||||
this.optionPage = optionPage;
|
||||
this.subPages = subPages;
|
||||
}
|
||||
|
||||
public GuiCustomMenuButton(int xPosition, int yPosition, OptionPage optionPage, OptionPage... subPages) {
|
||||
this(xPosition, yPosition, 150, 20, optionPage, subPages);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mousePressed(Minecraft mc, int mouseX, int mouseY) {
|
||||
boolean load = super.mousePressed(mc, mouseX, mouseY);
|
||||
if(load) {
|
||||
mc.displayGuiScreen(new GuiCustomMenu(mc.currentScreen, optionPage, subPages));
|
||||
}
|
||||
return load;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
package jss.notfine.gui;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import jss.notfine.gui.options.control.element.NotFineControlElementFactory;
|
||||
import jss.notfine.gui.options.control.element.SliderControlElement;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.Option;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.OptionGroup;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.OptionPage;
|
||||
import me.jellysquid.mods.sodium.client.util.Dim2i;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import net.minecraft.client.gui.GuiListExtended;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class GuiCustomOptionsRowList extends GuiListExtended {
|
||||
private static final NotFineControlElementFactory factory = new NotFineControlElementFactory();
|
||||
private final List<Row> settingsList = Lists.newArrayList();
|
||||
private GuiButton focusedButton;
|
||||
|
||||
public GuiCustomOptionsRowList(Minecraft mc, int width, int height, int top, int bottom, int slotHeight, OptionPage optionPage, OptionPage... subPages) {
|
||||
super(mc, width, height, top, bottom, slotHeight);
|
||||
field_148163_i = false;
|
||||
|
||||
for(OptionGroup optionGroup : optionPage.getGroups()) {
|
||||
Iterator<Option<?>> settings = optionGroup.getOptions().stream().iterator();
|
||||
while(settings.hasNext()) {
|
||||
Option<?> optionOne = settings.next();
|
||||
Option<?> optionTwo = settings.hasNext() ? settings.next() : null;
|
||||
GuiButton buttonOne = (GuiButton)optionOne.getControl().createElement(new Dim2i(width / 2 - 155,0,150,20), factory);
|
||||
GuiButton buttonTwo = optionTwo == null ? null : (GuiButton)optionTwo.getControl().createElement(new Dim2i(width / 2 - 155 + 160,0,150,20), factory);
|
||||
settingsList.add(new GuiCustomOptionsRowList.Row(buttonOne, buttonTwo));
|
||||
}
|
||||
}
|
||||
for(int i = 0; i < subPages.length; i += 2) {
|
||||
OptionPage pageOne = subPages[i];
|
||||
OptionPage pageTwo = i < subPages.length - 1 ? subPages[i + 1] : null;
|
||||
GuiButton buttonOne = new GuiCustomMenuButton(width / 2 - 155, 0, pageOne);
|
||||
GuiButton buttonTwo = pageTwo == null ? null : new GuiCustomMenuButton(width / 2 - 155 + 160, 0, pageTwo);
|
||||
settingsList.add(new Row(buttonOne, buttonTwo));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public GuiCustomOptionsRowList.Row getListEntry(int index) {
|
||||
return settingsList.get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getSize() {
|
||||
return settingsList.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getListWidth() {
|
||||
return 400;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getScrollBarX() {
|
||||
return super.getScrollBarX() + 32;
|
||||
}
|
||||
|
||||
public void keyTyped(int keyCode) {
|
||||
if(focusedButton instanceof SliderControlElement slider) {
|
||||
slider.keyTyped(keyCode);
|
||||
}
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class Row implements GuiListExtended.IGuiListEntry {
|
||||
private final Minecraft mc = Minecraft.getMinecraft();
|
||||
private final GuiButton buttonOne, buttonTwo;
|
||||
|
||||
public Row(GuiButton one, GuiButton two) {
|
||||
buttonOne = one;
|
||||
buttonTwo = two;
|
||||
|
||||
if(one != null && two == null) {
|
||||
one.width += 160;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawEntry(int varU1, int x, int y, int varU2, int varU3, Tessellator tessellator, int mouseX, int mouseY, boolean varU4) {
|
||||
buttonOne.yPosition = y;
|
||||
buttonOne.drawButton(mc, mouseX, mouseY);
|
||||
|
||||
|
||||
if(buttonTwo != null) {
|
||||
buttonTwo.yPosition = y;
|
||||
buttonTwo.drawButton(mc, mouseX, mouseY);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mousePressed(int index, int x, int y, int mouseEvent, int relativeX, int relativeY) {
|
||||
if(buttonOne.mousePressed(mc, x, y)) {
|
||||
focusedButton = buttonOne;
|
||||
return true;
|
||||
}
|
||||
if(buttonTwo != null && buttonTwo.mousePressed(mc, x, y)) {
|
||||
focusedButton = buttonTwo;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased(int index, int x, int y, int mouseEvent, int relativeX, int relativeY) {
|
||||
if(buttonOne != null) {
|
||||
buttonOne.mouseReleased(x, y);
|
||||
}
|
||||
|
||||
if(buttonTwo != null) {
|
||||
buttonTwo.mouseReleased(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,389 +0,0 @@
|
||||
package jss.notfine.gui;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.gtnewhorizons.angelica.config.AngelicaConfig;
|
||||
import jss.notfine.config.NotFineConfig;
|
||||
import jss.notfine.core.Settings;
|
||||
import jss.notfine.core.SettingsManager;
|
||||
import me.jellysquid.mods.sodium.client.gui.FrameRateOptions;
|
||||
import me.jellysquid.mods.sodium.client.gui.SodiumGameOptionPages;
|
||||
import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.OptionFlag;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.OptionGroup;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.OptionImpact;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.OptionImpl;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.OptionPage;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.control.ControlValueFormatter;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.control.CyclingControl;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.control.SliderControl;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.control.TickBoxControl;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.named.GraphicsMode;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.named.GraphicsQuality;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.named.LightingQuality;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.named.ParticleMode;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.named.TextureFilterMode;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.storage.MinecraftOptionsStorage;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.storage.SodiumOptionsStorage;
|
||||
import net.coderbot.iris.Iris;
|
||||
import net.coderbot.iris.gui.option.IrisVideoSettings;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraft.client.settings.GameSettings;
|
||||
import org.lwjgl.opengl.Display;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class NotFineGameOptionPages {
|
||||
private static final MinecraftOptionsStorage vanillaOpts = new MinecraftOptionsStorage();
|
||||
private static final SodiumOptionsStorage sodiumOpts = new SodiumOptionsStorage();
|
||||
|
||||
public static OptionPage general() {
|
||||
List<OptionGroup> groups = new ArrayList<>();
|
||||
|
||||
final FrameRateOptions frameRate = FrameRateOptions.create(vanillaOpts, sodiumOpts);
|
||||
groups.add(OptionGroup.createBuilder()
|
||||
.add(OptionImpl.createBuilder(GraphicsMode.class, vanillaOpts)
|
||||
.setName(I18n.format("options.graphics"))
|
||||
.setTooltip(I18n.format("sodium.options.graphics_quality.tooltip"))
|
||||
.setControl(option -> new CyclingControl<>(option, GraphicsMode.class))
|
||||
.setBinding((opts, value) -> {
|
||||
opts.fancyGraphics = value.isFancy();
|
||||
SettingsManager.graphicsUpdated();
|
||||
}, opts -> GraphicsMode.fromBoolean(opts.fancyGraphics))
|
||||
.setImpact(OptionImpact.HIGH)
|
||||
.setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD)
|
||||
.build())
|
||||
.add(OptionImpl.createBuilder(int.class, vanillaOpts)
|
||||
.setName(I18n.format("options.renderDistance"))
|
||||
.setTooltip(I18n.format("sodium.options.view_distance.tooltip"))
|
||||
.setControl(option -> new SliderControl(option, 2, (int) GameSettings.Options.RENDER_DISTANCE.getValueMax(), 1, ControlValueFormatter.quantity("options.chunks")))
|
||||
.setBinding((options, value) -> options.renderDistanceChunks = value, options -> options.renderDistanceChunks)
|
||||
.setImpact(OptionImpact.HIGH)
|
||||
.setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD)
|
||||
.build())
|
||||
.add(frameRate.vsync())
|
||||
.add(OptionImpl.createBuilder(boolean.class, vanillaOpts)
|
||||
.setName(I18n.format("options.fullscreen"))
|
||||
.setTooltip(I18n.format("sodium.options.fullscreen.tooltip"))
|
||||
.setControl(TickBoxControl::new)
|
||||
.setBinding((opts, value) -> {
|
||||
opts.fullScreen = value;
|
||||
Minecraft client = Minecraft.getMinecraft();
|
||||
if (client.isFullScreen() != opts.fullScreen) {
|
||||
client.toggleFullscreen();
|
||||
//The client might not be able to enter full-screen mode
|
||||
opts.fullScreen = client.isFullScreen();
|
||||
}
|
||||
}, (opts) -> opts.fullScreen)
|
||||
.build())
|
||||
.build());
|
||||
|
||||
groups.add(OptionGroup.createBuilder()
|
||||
.add(frameRate.maxFramerate())
|
||||
.build());
|
||||
|
||||
final OptionImpl<GameSettings, Integer> mipmapLevels = OptionImpl.createBuilder(int.class, vanillaOpts)
|
||||
.setName(I18n.format("options.mipmapLevels"))
|
||||
.setTooltip(I18n.format("sodium.options.mipmap_levels.tooltip"))
|
||||
.setControl(option -> new SliderControl(option, 0, 4, 1, ControlValueFormatter.multiplier()))
|
||||
.setBinding((opts, value) -> opts.mipmapLevels = value, opts -> opts.mipmapLevels)
|
||||
.setImpact(OptionImpact.MEDIUM)
|
||||
.setFlags(OptionFlag.REQUIRES_ASSET_RELOAD)
|
||||
.build();
|
||||
|
||||
final OptionImpl<SodiumGameOptions, TextureFilterMode> textureFilterMode =
|
||||
OptionImpl.createBuilder(TextureFilterMode.class, sodiumOpts)
|
||||
.setName(I18n.format("sodium.options.texture_filtering.name"))
|
||||
.setTooltip(I18n.format("sodium.options.texture_filtering.tooltip"))
|
||||
.setControl(option -> new CyclingControl<>(option, TextureFilterMode.class,
|
||||
TextureFilterMode.selectableValues(SodiumGameOptions.anisotropySupported())))
|
||||
.setBinding((opts, value) -> opts.quality.textureFilterMode = value,
|
||||
opts -> SodiumGameOptions.resolveFilterMode(opts.quality.textureFilterMode))
|
||||
.setImpact(OptionImpact.MEDIUM)
|
||||
.setFlags(OptionFlag.REQUIRES_ASSET_RELOAD, OptionFlag.REQUIRES_RENDERER_RELOAD)
|
||||
.build();
|
||||
|
||||
int maxGuiScale = Math.max(3, Math.min(Minecraft.getMinecraft().displayWidth / 320, Minecraft.getMinecraft().displayHeight / 240));
|
||||
groups.add(OptionGroup.createBuilder()
|
||||
.add(OptionImpl.createBuilder(int.class, vanillaOpts)
|
||||
.setName(I18n.format("options.guiScale"))
|
||||
.setTooltip(I18n.format("sodium.options.gui_scale.tooltip"))
|
||||
.setControl(option -> new SliderControl(option, 0, maxGuiScale, 1, ControlValueFormatter.guiScale()))
|
||||
.setBinding((opts, value) -> opts.guiScale = value, opts -> opts.guiScale)
|
||||
.build())
|
||||
.add(OptionImpl.createBuilder(boolean.class, vanillaOpts)
|
||||
.setName(I18n.format("options.viewBobbing"))
|
||||
.setTooltip(I18n.format("sodium.options.view_bobbing.tooltip"))
|
||||
.setControl(TickBoxControl::new)
|
||||
.setBinding((opts, value) -> opts.viewBobbing = value, opts -> opts.viewBobbing)
|
||||
.build())
|
||||
.add(OptionImpl.createBuilder(LightingQuality.class, vanillaOpts)
|
||||
.setName(I18n.format("options.ao"))
|
||||
.setTooltip(I18n.format("sodium.options.smooth_lighting.tooltip"))
|
||||
.setControl(option -> new CyclingControl<>(option, LightingQuality.class))
|
||||
.setBinding((opts, value) -> opts.ambientOcclusion = value.getVanilla(), opts -> LightingQuality.fromOrdinal(opts.ambientOcclusion))
|
||||
.setImpact(OptionImpact.MEDIUM)
|
||||
.setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD)
|
||||
.build())
|
||||
.add(OptionImpl.createBuilder(int.class, vanillaOpts)
|
||||
.setName(I18n.format("options.gamma"))
|
||||
.setTooltip(I18n.format("sodium.options.brightness.tooltip"))
|
||||
.setControl(opt -> new SliderControl(opt, 0, 100, 1, ControlValueFormatter.brightness()))
|
||||
.setBinding((opts, value) -> opts.gammaSetting = value * 0.01F, (opts) -> (int) (opts.gammaSetting / 0.01F))
|
||||
.build())
|
||||
.add(Settings.MODE_LIGHT_FLICKER.option)
|
||||
.add(Settings.DYNAMIC_FOV.option)
|
||||
.add(mipmapLevels)
|
||||
.add(textureFilterMode)
|
||||
.add(SodiumGameOptionPages.anisotropicFilteringSlider(vanillaOpts, textureFilterMode::getValue),
|
||||
SodiumGameOptions.anisotropySupported())
|
||||
.build());
|
||||
|
||||
if (Iris.enabled) {
|
||||
final OptionImpl<GameSettings, Integer> maxShadowDistanceSlider = OptionImpl.createBuilder(int.class, vanillaOpts)
|
||||
.setName(I18n.format("options.iris.shadowDistance"))
|
||||
.setTooltip(I18n.format("options.iris.shadowDistance.sodium_tooltip"))
|
||||
.setControl(option -> new SliderControl(option, 0, 32, 1, ControlValueFormatter.quantity("options.chunks")))
|
||||
.setBinding((options, value) -> {
|
||||
IrisVideoSettings.shadowDistance = value;
|
||||
try {
|
||||
Iris.getIrisConfig().save();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
},
|
||||
options -> IrisVideoSettings.getOverriddenShadowDistance(IrisVideoSettings.shadowDistance))
|
||||
.setImpact(OptionImpact.HIGH)
|
||||
.setEnabled(true)
|
||||
.build();
|
||||
maxShadowDistanceSlider.iris$dynamicallyEnable(IrisVideoSettings::isShadowDistanceSliderEnabled);
|
||||
groups.add(OptionGroup.createBuilder()
|
||||
.add(maxShadowDistanceSlider)
|
||||
.build());
|
||||
}
|
||||
|
||||
if (AngelicaConfig.enableZoom) {
|
||||
groups.add(OptionGroup.createBuilder()
|
||||
.add(Settings.ZOOM_SMOOTH.option)
|
||||
.add(Settings.ZOOM_SMOOTH_SPEED.option)
|
||||
.add(Settings.ZOOM_CINEMATIC.option)
|
||||
.build());
|
||||
}
|
||||
|
||||
return new OptionPage(I18n.format("options.video"), ImmutableList.copyOf(groups));
|
||||
}
|
||||
|
||||
public static OptionPage detail() {
|
||||
List<OptionGroup> groups = new ArrayList<>();
|
||||
groups.add(OptionGroup.createBuilder()
|
||||
.add(Settings.MODE_LEAVES.option)
|
||||
.add(OptionImpl.createBuilder(GraphicsQuality.class, sodiumOpts)
|
||||
.setName(I18n.format("sodium.options.grass_quality.name"))
|
||||
.setTooltip(I18n.format("sodium.options.grass_quality.tooltip"))
|
||||
.setControl(option -> new CyclingControl<>(option, GraphicsQuality.class))
|
||||
.setBinding((opts, value) -> opts.quality.grassQuality = value, opts -> opts.quality.grassQuality)
|
||||
.setImpact(OptionImpact.MEDIUM)
|
||||
.setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD)
|
||||
.build())
|
||||
.add(Settings.MODE_WATER.option)
|
||||
.add(Settings.DOWNFALL_DISTANCE.option)
|
||||
.add(Settings.MODE_VIGNETTE.option)
|
||||
.add(Settings.MODE_SHADOWS.option)
|
||||
.add(Settings.VOID_FOG.option)
|
||||
.add(Settings.MODE_DROPPED_ITEMS.option)
|
||||
.add(Settings.MODE_GLINT_WORLD.option)
|
||||
.add(Settings.MODE_GLINT_INV.option)
|
||||
.build());
|
||||
return new OptionPage(I18n.format("options.button.detail"), ImmutableList.copyOf(groups));
|
||||
}
|
||||
|
||||
public static OptionPage atmosphere() {
|
||||
List<OptionGroup> groups = new ArrayList<>();
|
||||
groups.add(OptionGroup.createBuilder()
|
||||
.add(Settings.MODE_SKY.option)
|
||||
.add(Settings.MODE_SUN_MOON.option)
|
||||
.add(Settings.MODE_CLOUDS.option)
|
||||
.add(Settings.RENDER_DISTANCE_CLOUDS.option)
|
||||
.add(Settings.CLOUD_HEIGHT.option)
|
||||
.add(Settings.CLOUD_SCALE.option)
|
||||
.add(Settings.MODE_CLOUD_TRANSLUCENCY.option)
|
||||
.add(Settings.MODE_STARS.option)
|
||||
.add(Settings.TOTAL_STARS.option)
|
||||
.add(Settings.HORIZON.option)
|
||||
.add(Settings.TERRAIN_FOG.option)
|
||||
.add(Settings.FOG_NEAR_DISTANCE.option)
|
||||
.build());
|
||||
return new OptionPage(I18n.format("options.button.sky"), ImmutableList.copyOf(groups));
|
||||
}
|
||||
|
||||
public static OptionPage particles() {
|
||||
List<OptionGroup> groups = new ArrayList<>();
|
||||
groups.add(OptionGroup.createBuilder()
|
||||
.add(OptionImpl.createBuilder(ParticleMode.class, vanillaOpts)
|
||||
.setName(I18n.format("options.particles"))
|
||||
.setTooltip(I18n.format("sodium.options.particle_quality.tooltip"))
|
||||
.setControl(opt -> new CyclingControl<>(opt, ParticleMode.class))
|
||||
.setBinding((opts, value) -> opts.particleSetting = value.ordinal(), (opts) -> ParticleMode.fromOrdinal(opts.particleSetting))
|
||||
.setImpact(OptionImpact.LOW)
|
||||
.build())
|
||||
.add(Settings.PARTICLES_VOID.option)
|
||||
.add(Settings.PARTICLES_ENC_TABLE.option)
|
||||
.build());
|
||||
return new OptionPage(I18n.format("options.button.particle"), ImmutableList.copyOf(groups));
|
||||
}
|
||||
|
||||
public static OptionPage other() {
|
||||
List<OptionGroup> groups = new ArrayList<>();
|
||||
|
||||
groups.add(OptionGroup.createBuilder()
|
||||
.add(OptionImpl.createBuilder(boolean.class, vanillaOpts)
|
||||
.setName(I18n.format("options.anaglyph"))
|
||||
.setTooltip(I18n.format("sodium.options.anaglyph.tooltip"))
|
||||
.setControl(TickBoxControl::new)
|
||||
.setBinding((opts, value) -> opts.anaglyph = value, opts -> opts.anaglyph)
|
||||
.setImpact(OptionImpact.HIGH)
|
||||
.setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD)
|
||||
.setEnabled(NotFineConfig.allowToggle3DAnaglyph)
|
||||
.build())
|
||||
.add(OptionImpl.createBuilder(boolean.class, vanillaOpts)
|
||||
.setName(I18n.format("options.showCape"))
|
||||
.setTooltip(I18n.format("sodium.options.show_cape.tooltip"))
|
||||
.setControl(TickBoxControl::new)
|
||||
.setBinding((opts, value) -> opts.showCape = value, opts -> opts.showCape)
|
||||
.build())
|
||||
.add(Settings.MODE_GUI_BACKGROUND.option)
|
||||
.build());
|
||||
|
||||
groups.add(OptionGroup.createBuilder()
|
||||
.add(Settings.GUI_BACKGROUND.option)
|
||||
.build());
|
||||
|
||||
groups.add(OptionGroup.createBuilder()
|
||||
.add(OptionImpl.createBuilder(boolean.class, sodiumOpts)
|
||||
.setName(I18n.format("sodium.options.use_chunk_multidraw.name"))
|
||||
.setTooltip(I18n.format("sodium.options.use_chunk_multidraw.tooltip"))
|
||||
.setControl(TickBoxControl::new)
|
||||
.setBinding((opts, value) -> opts.advanced.useChunkMultidraw = value, opts -> opts.advanced.useChunkMultidraw)
|
||||
.setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD)
|
||||
.setImpact(OptionImpact.EXTREME)
|
||||
.setEnabled(true)
|
||||
.build())
|
||||
.add(OptionImpl.createBuilder(boolean.class, sodiumOpts)
|
||||
.setName(I18n.format("sodium.options.use_vertex_objects.name"))
|
||||
.setTooltip(I18n.format("sodium.options.use_vertex_objects.tooltip"))
|
||||
.setControl(TickBoxControl::new)
|
||||
.setBinding((opts, value) -> opts.advanced.useVertexArrayObjects = value, opts -> opts.advanced.useVertexArrayObjects)
|
||||
.setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD)
|
||||
.setImpact(OptionImpact.LOW)
|
||||
.build())
|
||||
.add(OptionImpl.createBuilder(boolean.class, sodiumOpts)
|
||||
.setName(I18n.format("sodium.options.use_block_face_culling.name"))
|
||||
.setTooltip(I18n.format("sodium.options.use_block_face_culling.tooltip"))
|
||||
.setControl(TickBoxControl::new)
|
||||
.setImpact(OptionImpact.MEDIUM)
|
||||
.setBinding((opts, value) -> opts.performance.useBlockFaceCulling = value, opts -> opts.performance.useBlockFaceCulling)
|
||||
.setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD)
|
||||
.build())
|
||||
.add(OptionImpl.createBuilder(boolean.class, sodiumOpts)
|
||||
.setName(I18n.format("sodium.options.use_compact_vertex_format.name"))
|
||||
.setTooltip(I18n.format("sodium.options.use_compact_vertex_format.tooltip"))
|
||||
.setControl(TickBoxControl::new)
|
||||
.setImpact(OptionImpact.MEDIUM)
|
||||
.setBinding((opts, value) -> opts.performance.useCompactVertexFormat = value, opts -> opts.performance.useCompactVertexFormat)
|
||||
.setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD)
|
||||
.build())
|
||||
.add(OptionImpl.createBuilder(boolean.class, sodiumOpts)
|
||||
.setName(I18n.format("sodium.options.use_fog_occlusion.name"))
|
||||
.setTooltip(I18n.format("sodium.options.use_fog_occlusion.tooltip"))
|
||||
.setControl(TickBoxControl::new)
|
||||
.setBinding((opts, value) -> opts.performance.useFogOcclusion = value, opts -> opts.performance.useFogOcclusion)
|
||||
.setImpact(OptionImpact.MEDIUM)
|
||||
.setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD)
|
||||
.build())
|
||||
.add(OptionImpl.createBuilder(boolean.class, sodiumOpts)
|
||||
.setName(I18n.format("sodium.options.translucency_sorting.name"))
|
||||
.setTooltip(I18n.format("sodium.options.translucency_sorting.tooltip"))
|
||||
.setControl(TickBoxControl::new)
|
||||
.setBinding((opts, value) -> opts.performance.translucencySorting = value, opts -> opts.performance.translucencySorting)
|
||||
.setImpact(OptionImpact.MEDIUM)
|
||||
.setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD)
|
||||
.build())
|
||||
.add(OptionImpl.createBuilder(boolean.class, sodiumOpts)
|
||||
.setName(I18n.format("sodium.options.use_entity_culling.name"))
|
||||
.setTooltip(I18n.format("sodium.options.use_entity_culling.tooltip"))
|
||||
.setControl(TickBoxControl::new)
|
||||
.setImpact(OptionImpact.MEDIUM)
|
||||
.setBinding((opts, value) -> opts.performance.useEntityCulling = value, opts -> opts.performance.useEntityCulling)
|
||||
.build())
|
||||
.add(OptionImpl.createBuilder(boolean.class, sodiumOpts)
|
||||
.setName(I18n.format("sodium.options.use_particle_culling.name"))
|
||||
.setTooltip(I18n.format("sodium.options.use_particle_culling.tooltip"))
|
||||
.setControl(TickBoxControl::new)
|
||||
.setImpact(OptionImpact.MEDIUM)
|
||||
.setBinding((opts, value) -> opts.advanced.useParticleCulling = value, opts -> opts.advanced.useParticleCulling)
|
||||
.build())
|
||||
.build());
|
||||
groups.add(OptionGroup.createBuilder()
|
||||
.add(OptionImpl.createBuilder(boolean.class, sodiumOpts)
|
||||
.setName(I18n.format("sodium.options.animate_only_visible_textures.name"))
|
||||
.setTooltip(I18n.format("sodium.options.animate_only_visible_textures.tooltip"))
|
||||
.setControl(TickBoxControl::new)
|
||||
.setImpact(OptionImpact.MEDIUM)
|
||||
.setBinding((opts, value) -> opts.performance.animateOnlyVisibleTextures = value, opts -> opts.performance.animateOnlyVisibleTextures)
|
||||
.build())
|
||||
.build());
|
||||
groups.add(OptionGroup.createBuilder()
|
||||
.add(OptionImpl.createBuilder(boolean.class, sodiumOpts)
|
||||
.setName(I18n.format("sodium.options.allow_direct_memory_access.name"))
|
||||
.setTooltip(I18n.format("sodium.options.allow_direct_memory_access.tooltip"))
|
||||
.setControl(TickBoxControl::new)
|
||||
.setImpact(OptionImpact.HIGH)
|
||||
.setBinding((opts, value) -> opts.advanced.allowDirectMemoryAccess = value, opts -> opts.advanced.allowDirectMemoryAccess)
|
||||
.build())
|
||||
.build());
|
||||
groups.add(OptionGroup.createBuilder()
|
||||
.add(OptionImpl.createBuilder(boolean.class, sodiumOpts)
|
||||
.setName(I18n.format("sodium.options.ignore_driver_blacklist.name"))
|
||||
.setTooltip(I18n.format("sodium.options.ignore_driver_blacklist.tooltip"))
|
||||
.setControl(TickBoxControl::new)
|
||||
.setBinding((opts, value) -> opts.advanced.ignoreDriverBlacklist = value, opts -> opts.advanced.ignoreDriverBlacklist)
|
||||
.build())
|
||||
.build());
|
||||
groups.add(OptionGroup.createBuilder()
|
||||
.add(OptionImpl.createBuilder(int.class, sodiumOpts)
|
||||
.setName(I18n.format("sodium.options.chunk_update_threads.name"))
|
||||
.setTooltip(I18n.format("sodium.options.chunk_update_threads.tooltip"))
|
||||
.setControl(o -> new SliderControl(o, 0, Runtime.getRuntime().availableProcessors(), 1, ControlValueFormatter.quantityOrDisabled("sodium.options.threads.value", "sodium.options.default")))
|
||||
.setImpact(OptionImpact.HIGH)
|
||||
.setBinding((opts, value) -> opts.performance.chunkBuilderThreads = value, opts -> opts.performance.chunkBuilderThreads)
|
||||
.setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD)
|
||||
.build())
|
||||
.build());
|
||||
groups.add(OptionGroup.createBuilder()
|
||||
.add(OptionImpl.createBuilder(boolean.class, sodiumOpts)
|
||||
.setName(I18n.format("sodium.options.always_defer_chunk_updates.name"))
|
||||
.setTooltip(I18n.format("sodium.options.always_defer_chunk_updates.tooltip"))
|
||||
.setControl(TickBoxControl::new)
|
||||
.setImpact(OptionImpact.HIGH)
|
||||
.setBinding((opts, value) -> opts.performance.alwaysDeferChunkUpdates = value, opts -> opts.performance.alwaysDeferChunkUpdates)
|
||||
.setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD)
|
||||
.build())
|
||||
.build());
|
||||
|
||||
groups.add(OptionGroup.createBuilder()
|
||||
.add(OptionImpl.createBuilder(boolean.class, sodiumOpts)
|
||||
.setName(I18n.format("sodium.options.use_no_error_context.name"))
|
||||
.setTooltip(I18n.format("sodium.options.use_no_error_context.tooltip"))
|
||||
.setControl(TickBoxControl::new)
|
||||
.setImpact(OptionImpact.LOW)
|
||||
.setBinding((opts, value) -> opts.performance.useNoErrorGLContext = value, opts -> opts.performance.useNoErrorGLContext)
|
||||
.setFlags(OptionFlag.REQUIRES_GAME_RESTART)
|
||||
.build())
|
||||
.build());
|
||||
|
||||
return new OptionPage(I18n.format("options.button.other"), ImmutableList.copyOf(groups));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package jss.notfine.gui.options.control.element;
|
||||
|
||||
import me.jellysquid.mods.sodium.client.gui.options.Option;
|
||||
import me.jellysquid.mods.sodium.client.util.Dim2i;
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
||||
public class CyclingControlElement<T extends Enum<T>> extends NotFineControlElement<T> {
|
||||
private final T[] allowedValues;
|
||||
private final String[] names;
|
||||
|
||||
public CyclingControlElement(Option<T> option, Dim2i dim, T[] allowedValues, String[] names) {
|
||||
super(option, dim);
|
||||
this.allowedValues = allowedValues;
|
||||
this.names = names;
|
||||
}
|
||||
|
||||
private int currentIndex() {
|
||||
for(int i = 0; i < allowedValues.length; ++i) {
|
||||
if(allowedValues[i] == option.getValue()) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel() {
|
||||
Enum<T> value = option.getValue();
|
||||
return super.getLabel() + formatValue(names[value.ordinal()]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mousePressed(Minecraft mc, int mouseX, int mouseY) {
|
||||
if(super.mousePressed(mc, mouseX, mouseY)) {
|
||||
option.setValue(allowedValues[(currentIndex() + 1) % allowedValues.length]);
|
||||
onOptionValueChanged();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
package jss.notfine.gui.options.control.element;
|
||||
|
||||
import jss.notfine.gui.GuiCustomMenu;
|
||||
import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.Option;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.OptionFlag;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.control.ControlElement;
|
||||
import me.jellysquid.mods.sodium.client.util.Dim2i;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public class NotFineControlElement<T> extends GuiButton implements ControlElement<T> {
|
||||
protected final Option<T> option;
|
||||
protected final Dim2i dim;
|
||||
|
||||
public NotFineControlElement(Option<T> option, Dim2i dim) {
|
||||
super(-5, dim.getOriginX(), dim.getOriginY(), dim.getWidth(), dim.getHeight(), option.getName());
|
||||
this.option = option;
|
||||
this.dim = dim;
|
||||
enabled = option.isAvailable();
|
||||
}
|
||||
|
||||
private static String disabledStyle() {
|
||||
return String.valueOf(EnumChatFormatting.GRAY) + EnumChatFormatting.STRIKETHROUGH;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawButton(Minecraft mc, int mouseX, int mouseY) {
|
||||
displayString = getLabel();
|
||||
//TODO: tooltips
|
||||
//hovered
|
||||
super.drawButton(mc, mouseX, mouseY);
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
String name = option.getName();
|
||||
String label;
|
||||
enabled = option.isAvailable();
|
||||
if (!enabled) {
|
||||
label = disabledStyle() + name;
|
||||
} else if (option.hasChanged()) {
|
||||
label = EnumChatFormatting.ITALIC + name;
|
||||
} else {
|
||||
label = name;
|
||||
}
|
||||
label += ": ";
|
||||
return label;
|
||||
}
|
||||
|
||||
protected String formatValue(String value) {
|
||||
return option.isAvailable() ? value : disabledStyle() + value;
|
||||
}
|
||||
|
||||
protected void onOptionValueChanged() {
|
||||
option.applyChanges();
|
||||
|
||||
Collection<OptionFlag> flags = option.getFlags();
|
||||
Minecraft mc = Minecraft.getMinecraft();
|
||||
if (flags.contains(OptionFlag.REQUIRES_ASSET_RELOAD)) {
|
||||
SodiumGameOptions.applyAtlasSettings();
|
||||
mc.refreshResources();
|
||||
} else if (flags.contains(OptionFlag.REQUIRES_RENDERER_RELOAD)) {
|
||||
mc.renderGlobal.loadRenderers();
|
||||
}
|
||||
GuiCustomMenu.dirtyStorages.add(option.getStorage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHovered() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Option<T> getOption() {
|
||||
return this.option;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dim2i getDimensions() {
|
||||
return this.dim;
|
||||
}
|
||||
}
|
||||
-26
@@ -1,26 +0,0 @@
|
||||
package jss.notfine.gui.options.control.element;
|
||||
|
||||
import me.jellysquid.mods.sodium.client.gui.options.Option;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.control.ControlElement;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.control.ControlValueFormatter;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.control.element.ControlElementFactory;
|
||||
import me.jellysquid.mods.sodium.client.util.Dim2i;
|
||||
|
||||
public class NotFineControlElementFactory implements ControlElementFactory {
|
||||
|
||||
@Override
|
||||
public <T extends Enum<T>> ControlElement<T> cyclingControlElement(Option<T> option, Dim2i dim, T[] allowedValues, String[] names) {
|
||||
return new CyclingControlElement<>(option, dim, allowedValues, names);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ControlElement<Integer> sliderControlElement(Option<Integer> option, Dim2i dim, int min, int max, int interval, ControlValueFormatter formatter) {
|
||||
return new SliderControlElement(option, dim, min, max, interval, formatter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ControlElement<Boolean> tickBoxElement(Option<Boolean> option, Dim2i dim) {
|
||||
return new TickBoxControlElement(option, dim);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
package jss.notfine.gui.options.control.element;
|
||||
|
||||
import me.jellysquid.mods.sodium.client.gui.options.Option;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.control.ControlValueFormatter;
|
||||
import me.jellysquid.mods.sodium.client.util.Dim2i;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.util.MathHelper;
|
||||
import org.lwjgl.input.Keyboard;
|
||||
|
||||
public class SliderControlElement extends NotFineControlElement<Integer> {
|
||||
private final ControlValueFormatter formatter;
|
||||
private final int min, max, interval;
|
||||
|
||||
private float value;
|
||||
private boolean mousePressed;
|
||||
private boolean dirty = false;
|
||||
|
||||
public SliderControlElement(Option<Integer> option, Dim2i dim, int min, int max, int interval, ControlValueFormatter formatter) {
|
||||
super(option, dim);
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
this.interval = interval;
|
||||
this.formatter = formatter;
|
||||
value = option.getValue();
|
||||
//Normalize value
|
||||
value = MathHelper.clamp_float((value - min) / (max - min), 0f, 1f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel() {
|
||||
return super.getLabel() + formatValue(formatter.format(option.getValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHoverState(boolean mouseOver) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void mouseDragged(Minecraft mc, int mouseX, int mouseY) {
|
||||
if(visible) {
|
||||
if(mousePressed) {
|
||||
updateSlider(mouseX);
|
||||
}
|
||||
GLStateManager.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
drawTexturedModalRect(xPosition + (int)(value * (float)(width - 8)), yPosition, 0, 66, 4, 20);
|
||||
drawTexturedModalRect(xPosition + (int)(value * (float)(width - 8)) + 4, yPosition, 196, 66, 4, 20);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mousePressed(Minecraft mc, int mouseX, int mouseY) {
|
||||
if(super.mousePressed(mc, mouseX, mouseY)) {
|
||||
updateSlider(mouseX);
|
||||
mousePressed = true;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased(int mouseX, int mouseY) {
|
||||
mousePressed = false;
|
||||
if(dirty) {
|
||||
onOptionValueChanged();
|
||||
dirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean keyTyped(int keyCode) {
|
||||
if(!option.isAvailable()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final int step;
|
||||
if(keyCode == Keyboard.KEY_LEFT) {
|
||||
step = -interval;
|
||||
} else if(keyCode == Keyboard.KEY_RIGHT) {
|
||||
step = interval;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
final int stepped = MathHelper.clamp_int(option.getValue() + step, min, max);
|
||||
if(stepped != option.getValue()) {
|
||||
option.setValue(stepped);
|
||||
value = MathHelper.clamp_float((float)(stepped - min) / (max - min), 0f, 1f);
|
||||
onOptionValueChanged();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void updateSlider(int mouseX) {
|
||||
value = (float)(mouseX - (xPosition + 4)) / (float)(width - 8);
|
||||
//Clamp normalized value
|
||||
value = MathHelper.clamp_float(value, 0f, 1f);
|
||||
//Un-normalize value
|
||||
value = min + (max - min) * MathHelper.clamp_float(value, 0f, 1f);
|
||||
//Clamp value
|
||||
value = MathHelper.clamp_float(value, min, max);
|
||||
//Snap value
|
||||
if(interval > 0) {
|
||||
value = interval * (float)Math.round(value / interval);
|
||||
}
|
||||
//Commit value
|
||||
option.setValue((int)value);
|
||||
//Normalize value
|
||||
value = MathHelper.clamp_float((value - min) / (max - min), 0f, 1f);
|
||||
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package jss.notfine.gui.options.control.element;
|
||||
|
||||
import me.jellysquid.mods.sodium.client.gui.options.Option;
|
||||
import me.jellysquid.mods.sodium.client.util.Dim2i;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
|
||||
public class TickBoxControlElement extends NotFineControlElement<Boolean> {
|
||||
public TickBoxControlElement(Option<Boolean> option, Dim2i dim) {
|
||||
super(option, dim);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel() {
|
||||
return super.getLabel() + formatValue(I18n.format(option.getValue() ? "options.on" : "options.off"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mousePressed(Minecraft mc, int mouseX, int mouseY) {
|
||||
if(super.mousePressed(mc, mouseX, mouseY)) {
|
||||
option.setValue(!option.getValue());
|
||||
onOptionValueChanged();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+72
-15
@@ -1,9 +1,15 @@
|
||||
package me.flashyreese.mods.reeses_sodium_options.client.gui;
|
||||
|
||||
import com.gtnewhorizons.angelica.client.gui.DynamicLightsOptionPages;
|
||||
import com.gtnewhorizons.angelica.client.gui.FontConfigScreen;
|
||||
import com.gtnewhorizons.angelica.client.gui.RendererOptionPages;
|
||||
import com.gtnewhorizons.angelica.client.gui.ScrollableGuiScreen;
|
||||
import com.gtnewhorizons.angelica.client.gui.TracyOptionPages;
|
||||
import com.gtnewhorizons.angelica.compat.mojang.Element;
|
||||
import com.gtnewhorizons.angelica.config.AngelicaConfig;
|
||||
import jss.notfine.gui.GuiCustomMenu;
|
||||
import com.gtnewhorizons.angelica.config.SystemProperties;
|
||||
import com.gtnewhorizons.angelica.dynamiclights.DynamicLights;
|
||||
import com.gtnewhorizons.angelica.glsm.profiling.TracyOptions;
|
||||
import me.flashyreese.mods.reeses_sodium_options.client.gui.frame.AbstractFrame;
|
||||
import me.flashyreese.mods.reeses_sodium_options.client.gui.frame.BasicFrame;
|
||||
import me.flashyreese.mods.reeses_sodium_options.client.gui.frame.components.SearchTextFieldComponent;
|
||||
@@ -11,7 +17,6 @@ import me.flashyreese.mods.reeses_sodium_options.client.gui.frame.tab.Tab;
|
||||
import me.flashyreese.mods.reeses_sodium_options.client.gui.frame.tab.TabFrame;
|
||||
import me.jellysquid.mods.sodium.client.gui.SodiumGameOptionPages;
|
||||
import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions;
|
||||
import me.jellysquid.mods.sodium.client.gui.SodiumOptionsGUI;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.Option;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.OptionFlag;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.OptionGroup;
|
||||
@@ -27,13 +32,16 @@ import net.minecraft.client.resources.I18n;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.lwjgl.input.Keyboard;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class ReeseSodiumVideoOptionsScreen extends SodiumOptionsGUI {
|
||||
public class ReeseSodiumVideoOptionsScreen extends ScrollableGuiScreen {
|
||||
private static final float ASPECT_RATIO = 5f / 4f;
|
||||
private static final int MINIMUM_WIDTH = 550;
|
||||
|
||||
@@ -46,15 +54,63 @@ public class ReeseSodiumVideoOptionsScreen extends SodiumOptionsGUI {
|
||||
|
||||
private static final AtomicReference<String> lastSearch = new AtomicReference<>("");
|
||||
|
||||
private final List<Element> children = new CopyOnWriteArrayList<>();
|
||||
private final List<OptionPage> pages = new ArrayList<>();
|
||||
|
||||
public final GuiScreen prevScreen;
|
||||
|
||||
private FlatButtonWidget applyButton, closeButton, undoButton;
|
||||
private boolean hasPendingChanges;
|
||||
private String pendingPage;
|
||||
|
||||
private AbstractFrame frame;
|
||||
private SearchTextFieldComponent searchTextField;
|
||||
|
||||
public ReeseSodiumVideoOptionsScreen(GuiScreen prevScreen) {
|
||||
super(prevScreen);
|
||||
this.prevScreen = prevScreen;
|
||||
|
||||
this.pages.add(RendererOptionPages.withLink(SodiumGameOptionPages.general(), this));
|
||||
this.pages.add(RendererOptionPages.renderer());
|
||||
this.pages.add(SodiumGameOptionPages.quality());
|
||||
this.pages.add(SodiumGameOptionPages.advanced());
|
||||
this.pages.add(SodiumGameOptionPages.performance());
|
||||
this.pages.add(SodiumGameOptionPages.fpsReducer());
|
||||
this.pages.add(SodiumGameOptionPages.appearance());
|
||||
this.pages.add(SodiumGameOptionPages.text());
|
||||
|
||||
if (DynamicLights.configEnabled) {
|
||||
this.pages.add(DynamicLightsOptionPages.dynamicLights());
|
||||
}
|
||||
|
||||
if (SystemProperties.debugTooling() || TracyOptions.backendPresent()) {
|
||||
this.pages.add(TracyOptionPages.tracy());
|
||||
}
|
||||
}
|
||||
|
||||
public void showPage(String name) {
|
||||
this.pendingPage = name;
|
||||
}
|
||||
|
||||
private void applyPendingPage() {
|
||||
if (this.pendingPage == null) return;
|
||||
lastSearch.set("");
|
||||
tabFrameSelectedTab.set(this.pendingPage);
|
||||
optionPageScrollBarOffset.set(0);
|
||||
this.pendingPage = null;
|
||||
this.rebuildGUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends Element> children() {
|
||||
return children;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGuiClosed() {
|
||||
Keyboard.enableRepeatEvents(false);
|
||||
}
|
||||
|
||||
// Hackalicious! Rebuild UI
|
||||
@Override
|
||||
public void rebuildGUI() {
|
||||
// Preserve search focus state across rebuilds
|
||||
boolean wasSearchFocused = this.searchTextField != null && this.searchTextField.isFocused();
|
||||
@@ -196,6 +252,7 @@ public class ReeseSodiumVideoOptionsScreen extends SodiumOptionsGUI {
|
||||
|
||||
@Override
|
||||
public void drawScreen(int mouseX, int mouseY, float partialTicks) {
|
||||
this.applyPendingPage();
|
||||
super.drawDefaultBackground();
|
||||
handleMouseScroll(mouseX, mouseY, partialTicks);
|
||||
this.updateControls();
|
||||
@@ -275,14 +332,6 @@ public class ReeseSodiumVideoOptionsScreen extends SodiumOptionsGUI {
|
||||
onClose();
|
||||
return;
|
||||
}
|
||||
if (keyCode == Keyboard.KEY_P) {
|
||||
if(isShiftKeyDown()){
|
||||
this.mc.displayGuiScreen(new GuiCustomMenu(this.prevScreen, SodiumGameOptionPages.general(), SodiumGameOptionPages.quality(), SodiumGameOptionPages.advanced(), SodiumGameOptionPages.performance(), SodiumGameOptionPages.appearance()));
|
||||
} else if (isCtrlKeyDown()) {
|
||||
this.mc.displayGuiScreen(new SodiumOptionsGUI(this.prevScreen));
|
||||
}
|
||||
}
|
||||
|
||||
if(focused != null) {
|
||||
focused.keyTyped(typedChar, keyCode);
|
||||
}
|
||||
@@ -293,6 +342,7 @@ public class ReeseSodiumVideoOptionsScreen extends SodiumOptionsGUI {
|
||||
final boolean onSearchField = this.searchTextField.isMouseOver(mouseX, mouseY);
|
||||
|
||||
super.mouseClicked(mouseX, mouseY, mouseButton);
|
||||
this.children.forEach(element -> element.mouseClicked(mouseX, mouseY, mouseButton));
|
||||
|
||||
if (!onSearchField) {
|
||||
this.searchTextField.setFocused(false);
|
||||
@@ -301,13 +351,20 @@ public class ReeseSodiumVideoOptionsScreen extends SodiumOptionsGUI {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void mouseClickMove(int mouseX, int mouseY, int mouseButton, long timeSinceLastClick) {
|
||||
super.mouseClickMove(mouseX, mouseY, mouseButton, timeSinceLastClick);
|
||||
|
||||
this.children.forEach(element -> element.mouseDragged(mouseX, mouseY, mouseButton));
|
||||
}
|
||||
|
||||
public boolean shouldCloseOnEsc() {
|
||||
return !this.hasPendingChanges;
|
||||
}
|
||||
|
||||
@Override
|
||||
// We can't override onGuiClosed due to StackOverflow
|
||||
public void onClose() {
|
||||
lastSearch.set("");
|
||||
super.onClose();
|
||||
this.mc.displayGuiScreen(this.prevScreen);
|
||||
super.onGuiClosed();
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ import com.gtnewhorizons.angelica.config.GpuCullingMode;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import cpw.mods.fml.common.Optional.Method;
|
||||
import com.gtnewhorizons.angelica.glsm.streaming.StreamingUploader;
|
||||
import jss.notfine.config.NotFineConfig;
|
||||
import jss.notfine.core.Settings;
|
||||
import jss.notfine.core.SettingsManager;
|
||||
import me.flashyreese.mods.reeses_sodium_options.client.gui.ReeseSodiumVideoOptionsScreen;
|
||||
@@ -131,9 +132,6 @@ public class SodiumGameOptionPages {
|
||||
if(Minecraft.getMinecraft().currentScreen instanceof ReeseSodiumVideoOptionsScreen oldGui) {
|
||||
Minecraft.getMinecraft().displayGuiScreen(new ReeseSodiumVideoOptionsScreen(oldGui.prevScreen));
|
||||
}
|
||||
else if(Minecraft.getMinecraft().currentScreen instanceof SodiumOptionsGUI oldGui) {
|
||||
Minecraft.getMinecraft().displayGuiScreen(new SodiumOptionsGUI(oldGui.prevScreen));
|
||||
}
|
||||
}, opts -> opts.guiScale)
|
||||
.build())
|
||||
.add(OptionImpl.createBuilder(boolean.class, vanillaOpts)
|
||||
@@ -812,6 +810,21 @@ public class SodiumGameOptionPages {
|
||||
groups.add(OptionGroup.createBuilder()
|
||||
.add(Settings.MODE_GUI_BACKGROUND.option)
|
||||
.add(Settings.GUI_BACKGROUND.option)
|
||||
.add(OptionImpl.createBuilder(boolean.class, vanillaOpts)
|
||||
.setName(I18n.format("options.showCape"))
|
||||
.setTooltip(I18n.format("sodium.options.show_cape.tooltip"))
|
||||
.setControl(TickBoxControl::new)
|
||||
.setBinding((opts, value) -> opts.showCape = value, opts -> opts.showCape)
|
||||
.build())
|
||||
.add(OptionImpl.createBuilder(boolean.class, vanillaOpts)
|
||||
.setName(I18n.format("options.anaglyph"))
|
||||
.setTooltip(I18n.format("sodium.options.anaglyph.tooltip"))
|
||||
.setControl(TickBoxControl::new)
|
||||
.setBinding((opts, value) -> opts.anaglyph = value, opts -> opts.anaglyph)
|
||||
.setImpact(OptionImpact.HIGH)
|
||||
.setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD)
|
||||
.setEnabled(NotFineConfig.allowToggle3DAnaglyph)
|
||||
.build())
|
||||
.add(OptionImpl.createBuilder(boolean.class, angelicaOpts)
|
||||
.setName(I18n.format("options.angelica.disablef3"))
|
||||
.setTooltip(I18n.format("options.angelica.disablef3.tooltip"))
|
||||
|
||||
@@ -204,7 +204,6 @@ public class SodiumGameOptions {
|
||||
public static class AdvancedSettings {
|
||||
public VSyncMode vsyncMode;
|
||||
public boolean useVertexArrayObjects = true;
|
||||
public boolean useChunkMultidraw = true;
|
||||
public MultiDrawMode multiDrawMode = MultiDrawMode.DIRECT;
|
||||
|
||||
public boolean useParticleCulling = true;
|
||||
|
||||
@@ -1,343 +0,0 @@
|
||||
package me.jellysquid.mods.sodium.client.gui;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.gtnewhorizons.angelica.client.gui.DynamicLightsOptionPages;
|
||||
import com.gtnewhorizons.angelica.client.gui.ScrollableGuiScreen;
|
||||
import com.gtnewhorizons.angelica.client.gui.TracyOptionPages;
|
||||
import com.gtnewhorizons.angelica.compat.mojang.Drawable;
|
||||
import com.gtnewhorizons.angelica.compat.mojang.Element;
|
||||
import com.gtnewhorizons.angelica.config.SystemProperties;
|
||||
import com.gtnewhorizons.angelica.dynamiclights.DynamicLights;
|
||||
import com.gtnewhorizons.angelica.glsm.profiling.TracyOptions;
|
||||
import jss.notfine.gui.GuiCustomMenu;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.Option;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.OptionFlag;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.OptionGroup;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.OptionImpact;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.OptionPage;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.control.Control;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.control.ControlElement;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.control.element.SodiumControlElementFactory;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.storage.OptionStorage;
|
||||
import me.jellysquid.mods.sodium.client.gui.widgets.FlatButtonWidget;
|
||||
import me.jellysquid.mods.sodium.client.util.Dim2i;
|
||||
import net.coderbot.iris.Iris;
|
||||
import net.coderbot.iris.gui.screen.ShaderPackScreen;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
import org.lwjgl.input.Keyboard;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class SodiumOptionsGUI extends ScrollableGuiScreen {
|
||||
|
||||
protected static final SodiumControlElementFactory elementFactory = new SodiumControlElementFactory();
|
||||
|
||||
protected final List<Element> children = new CopyOnWriteArrayList<>();
|
||||
|
||||
protected final List<OptionPage> pages = new ArrayList<>();
|
||||
|
||||
protected final List<ControlElement<?>> controls = new ArrayList<>();
|
||||
protected final List<Drawable> drawable = new ArrayList<>();
|
||||
|
||||
public final GuiScreen prevScreen;
|
||||
|
||||
protected OptionPage currentPage;
|
||||
|
||||
protected FlatButtonWidget applyButton, closeButton, undoButton;
|
||||
|
||||
protected boolean hasPendingChanges;
|
||||
protected ControlElement<?> hoveredElement;
|
||||
private Element focusedElement;
|
||||
|
||||
protected OptionPage shaderPacks;
|
||||
|
||||
public SodiumOptionsGUI(GuiScreen prevScreen) {
|
||||
this.prevScreen = prevScreen;
|
||||
|
||||
this.pages.add(SodiumGameOptionPages.general());
|
||||
this.pages.add(SodiumGameOptionPages.quality());
|
||||
this.pages.add(SodiumGameOptionPages.advanced());
|
||||
this.pages.add(SodiumGameOptionPages.performance());
|
||||
this.pages.add(SodiumGameOptionPages.fpsReducer());
|
||||
this.pages.add(SodiumGameOptionPages.appearance());
|
||||
this.pages.add(SodiumGameOptionPages.text());
|
||||
|
||||
// Add Dynamic Lights page if enabled
|
||||
if (DynamicLights.configEnabled) {
|
||||
this.pages.add(DynamicLightsOptionPages.dynamicLights());
|
||||
}
|
||||
|
||||
if (SystemProperties.debugTooling() || TracyOptions.backendPresent()) {
|
||||
this.pages.add(TracyOptionPages.tracy());
|
||||
}
|
||||
|
||||
if (Iris.enabled) {
|
||||
shaderPacks = new OptionPage(I18n.format("options.iris.shaderPackSelection"), ImmutableList.of());
|
||||
this.pages.add(shaderPacks);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void setPage(OptionPage page) {
|
||||
if (Iris.enabled && page == shaderPacks) {
|
||||
mc.displayGuiScreen(new ShaderPackScreen(this));
|
||||
return;
|
||||
}
|
||||
|
||||
this.currentPage = page;
|
||||
|
||||
this.rebuildGUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initGui() {
|
||||
Keyboard.enableRepeatEvents(true);
|
||||
this.rebuildGUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGuiClosed() {
|
||||
Keyboard.enableRepeatEvents(false);
|
||||
}
|
||||
|
||||
protected void rebuildGUI() {
|
||||
this.controls.clear();
|
||||
this.children.clear();
|
||||
this.drawable.clear();
|
||||
this.focusedElement = null;
|
||||
|
||||
if (this.currentPage == null) {
|
||||
if (this.pages.isEmpty()) {
|
||||
throw new IllegalStateException("No pages are available?!");
|
||||
}
|
||||
|
||||
// Just use the first page for now
|
||||
this.currentPage = this.pages.getFirst();
|
||||
}
|
||||
|
||||
this.rebuildGUIPages();
|
||||
this.rebuildGUIOptions();
|
||||
|
||||
this.undoButton = new FlatButtonWidget(new Dim2i(this.width - 211, this.height - 26, 65, 20), I18n.format("sodium.options.buttons.undo"), this::undoChanges);
|
||||
this.applyButton = new FlatButtonWidget(new Dim2i(this.width - 142, this.height - 26, 65, 20), I18n.format("sodium.options.buttons.apply"), this::applyChanges);
|
||||
this.closeButton = new FlatButtonWidget(new Dim2i(this.width - 73, this.height - 26, 65, 20), I18n.format("gui.done"), this::onClose);
|
||||
|
||||
this.children.add(this.undoButton);
|
||||
this.children.add(this.applyButton);
|
||||
this.children.add(this.closeButton);
|
||||
|
||||
for (Element element : this.children) {
|
||||
if (element instanceof Drawable) {
|
||||
this.drawable.add((Drawable) element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void rebuildGUIPages() {
|
||||
int x = 6;
|
||||
final int y = 6;
|
||||
|
||||
for (OptionPage page : this.pages) {
|
||||
final int width = 12 + this.fontRendererObj.getStringWidth(page.getName());
|
||||
|
||||
final FlatButtonWidget button = new FlatButtonWidget(new Dim2i(x, y, width, 18), page.getName(), () -> this.setPage(page));
|
||||
button.setSelected(this.currentPage == page);
|
||||
|
||||
x += width + 6;
|
||||
|
||||
this.children.add(button);
|
||||
}
|
||||
}
|
||||
|
||||
private void rebuildGUIOptions() {
|
||||
final int x = 6;
|
||||
int y = 28;
|
||||
|
||||
for (OptionGroup group : this.currentPage.getGroups()) {
|
||||
// Add each option's control element
|
||||
for (Option<?> option : group.getOptions()) {
|
||||
final Control<?> control = option.getControl();
|
||||
final ControlElement<?> element = control.createElement(new Dim2i(x, y, 200, 18), elementFactory);
|
||||
|
||||
this.controls.add(element);
|
||||
//Safe if SodiumControlElementFactory or a compatible ControlElementFactory is used to create element.
|
||||
this.children.add((Element)element);
|
||||
|
||||
// Move down to the next option
|
||||
y += 18;
|
||||
}
|
||||
|
||||
// Add padding beneath each option group
|
||||
y += 4;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawScreen(int mouseX, int mouseY, float delta) {
|
||||
super.drawScreen(mouseX, mouseY, delta);
|
||||
super.drawDefaultBackground();
|
||||
|
||||
this.updateControls();
|
||||
|
||||
for (Drawable drawable : this.drawable) {
|
||||
drawable.render(mouseX, mouseY, delta);
|
||||
}
|
||||
|
||||
if (this.hoveredElement != null) {
|
||||
this.renderOptionTooltip(this.hoveredElement);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends Element> children() {
|
||||
return children;
|
||||
}
|
||||
|
||||
private void updateControls() {
|
||||
ControlElement<?> hovered = this.getActiveControls()
|
||||
.filter(ControlElement::isHovered)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
|
||||
final boolean hasChanges = this.getAllOptions().anyMatch(Option::hasChanged);
|
||||
|
||||
this.applyButton.setEnabled(hasChanges);
|
||||
this.undoButton.setVisible(hasChanges);
|
||||
this.closeButton.setEnabled(!hasChanges);
|
||||
|
||||
this.hasPendingChanges = hasChanges;
|
||||
this.hoveredElement = hovered;
|
||||
}
|
||||
|
||||
private Stream<Option<?>> getAllOptions() {
|
||||
return this.pages.stream()
|
||||
.flatMap(s -> s.getOptions().stream());
|
||||
}
|
||||
|
||||
private Stream<ControlElement<?>> getActiveControls() {
|
||||
return this.controls.stream();
|
||||
}
|
||||
|
||||
private void renderOptionTooltip(ControlElement<?> element) {
|
||||
final Dim2i dim = element.getDimensions();
|
||||
|
||||
final int textPadding = 3;
|
||||
final int boxPadding = 3;
|
||||
|
||||
final int boxWidth = 200;
|
||||
|
||||
int boxY = dim.getOriginY();
|
||||
final int boxX = dim.getLimitX() + boxPadding;
|
||||
|
||||
final Option<?> option = element.getOption();
|
||||
final List<String> tooltip = new ArrayList<>(this.fontRendererObj.listFormattedStringToWidth(option.getTooltip(), boxWidth - (textPadding * 2)));
|
||||
|
||||
final OptionImpact impact = option.getImpact();
|
||||
|
||||
if (impact != null) {
|
||||
tooltip.add(EnumChatFormatting.GRAY + I18n.format("sodium.options.performance_impact_string", impact.toDisplayString()));
|
||||
}
|
||||
|
||||
final int boxHeight = (tooltip.size() * 12) + boxPadding;
|
||||
final int boxYLimit = boxY + boxHeight;
|
||||
final int boxYCutoff = this.height - 40;
|
||||
|
||||
// If the box is going to be cutoff on the Y-axis, move it back up the difference
|
||||
if (boxYLimit > boxYCutoff) {
|
||||
boxY -= boxYLimit - boxYCutoff;
|
||||
}
|
||||
|
||||
this.drawGradientRect(boxX, boxY, boxX + boxWidth, boxY + boxHeight, 0xE0000000, 0xE0000000);
|
||||
|
||||
for (int i = 0; i < tooltip.size(); i++) {
|
||||
this.fontRendererObj.drawString(tooltip.get(i), boxX + textPadding, boxY + textPadding + (i * 12), 0xFFFFFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
private void applyChanges() {
|
||||
final HashSet<OptionStorage<?>> dirtyStorages = new HashSet<>();
|
||||
final EnumSet<OptionFlag> flags = EnumSet.noneOf(OptionFlag.class);
|
||||
|
||||
this.getAllOptions().forEach((option -> {
|
||||
if (!option.hasChanged()) {
|
||||
return;
|
||||
}
|
||||
|
||||
option.applyChanges();
|
||||
|
||||
flags.addAll(option.getFlags());
|
||||
dirtyStorages.add(option.getStorage());
|
||||
}));
|
||||
|
||||
if (flags.contains(OptionFlag.REQUIRES_ASSET_RELOAD)) {
|
||||
SodiumGameOptions.applyAtlasSettings();
|
||||
this.mc.refreshResources();
|
||||
} else if (flags.contains(OptionFlag.REQUIRES_RENDERER_RELOAD)) {
|
||||
this.mc.renderGlobal.loadRenderers();
|
||||
}
|
||||
|
||||
for (OptionStorage<?> storage : dirtyStorages) {
|
||||
storage.save();
|
||||
}
|
||||
}
|
||||
|
||||
private void undoChanges() {
|
||||
this.getAllOptions().forEach(Option::reset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyTyped(char typedChar, int keyCode) {
|
||||
if(keyCode == Keyboard.KEY_ESCAPE && !shouldCloseOnEsc()) {
|
||||
return;
|
||||
} else if (keyCode == Keyboard.KEY_ESCAPE) {
|
||||
onClose();
|
||||
return;
|
||||
}
|
||||
|
||||
if (keyCode == Keyboard.KEY_P && isShiftKeyDown()) {
|
||||
this.mc.displayGuiScreen(new GuiCustomMenu(this.prevScreen, SodiumGameOptionPages.general(),
|
||||
SodiumGameOptionPages.quality(), SodiumGameOptionPages.advanced(), SodiumGameOptionPages.performance(),
|
||||
SodiumGameOptionPages.appearance()));
|
||||
}
|
||||
|
||||
if (this.focusedElement != null) {
|
||||
this.focusedElement.keyTyped(typedChar, keyCode);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean shouldCloseOnEsc() {
|
||||
return !this.hasPendingChanges;
|
||||
}
|
||||
|
||||
// We can't override onGuiClosed due to StackOverflow
|
||||
public void onClose() {
|
||||
this.mc.displayGuiScreen(this.prevScreen);
|
||||
super.onGuiClosed();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void mouseClicked(int mouseX, int mouseY, int mouseButton) {
|
||||
super.mouseClicked(mouseX, mouseY, mouseButton);
|
||||
|
||||
this.children.forEach(element -> {
|
||||
if (element.mouseClicked(mouseX, mouseY, mouseButton)) {
|
||||
this.focusedElement = element;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void mouseClickMove(int mouseX, int mouseY, int mouseButton, long timeSinceLastClick) {
|
||||
super.mouseClickMove(mouseX, mouseY, mouseButton, timeSinceLastClick);
|
||||
|
||||
this.children.forEach(element -> element.mouseDragged(mouseX, mouseY, mouseButton));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,12 +8,27 @@ public class ActionOption extends ButtonOption {
|
||||
private final Supplier<String> label;
|
||||
private final Runnable action;
|
||||
private final BooleanSupplier available;
|
||||
private final boolean clickable;
|
||||
|
||||
public ActionOption(String name, String tooltip, Supplier<String> label, Runnable action, BooleanSupplier available) {
|
||||
this(name, tooltip, label, action, available, true);
|
||||
}
|
||||
|
||||
private ActionOption(String name, String tooltip, Supplier<String> label, Runnable action, BooleanSupplier available, boolean clickable) {
|
||||
super(name, tooltip, 100);
|
||||
this.label = label;
|
||||
this.action = action;
|
||||
this.available = available;
|
||||
this.clickable = clickable;
|
||||
}
|
||||
|
||||
public static ActionOption label(String name, String tooltip, Supplier<String> label) {
|
||||
return new ActionOption(name, tooltip, label, () -> {}, () -> true, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean clickable() {
|
||||
return this.clickable;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -40,6 +40,10 @@ public abstract class ButtonOption implements Option<Void> {
|
||||
|
||||
protected abstract void invoke();
|
||||
|
||||
protected boolean clickable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.name;
|
||||
@@ -127,12 +131,12 @@ public abstract class ButtonOption implements Option<Void> {
|
||||
|
||||
final String label = this.target.label();
|
||||
final int width = this.font.getStringWidth(label);
|
||||
this.drawString(label, this.dim.getLimitX() - width - 6, this.dim.getCenterY() - 4, this.hovered ? LABEL_HOVERED : LABEL_IDLE);
|
||||
this.drawString(label, this.dim.getLimitX() - width - 6, this.dim.getCenterY() - 4, this.hovered && this.target.clickable() ? LABEL_HOVERED : LABEL_IDLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseClicked(double mouseX, double mouseY, int button) {
|
||||
if (!this.target.isAvailable() || button != 0 || !this.dim.containsCursor(mouseX, mouseY)) return false;
|
||||
if (!this.target.clickable() || !this.target.isAvailable() || button != 0 || !this.dim.containsCursor(mouseX, mouseY)) return false;
|
||||
|
||||
this.playClickSound();
|
||||
this.target.invoke();
|
||||
|
||||
+4
-14
@@ -1,6 +1,5 @@
|
||||
package me.jellysquid.mods.sodium.client.gui.options.control.element;
|
||||
|
||||
import com.gtnewhorizons.angelica.config.AngelicaConfig;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.Option;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.control.ControlElement;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.control.ControlValueFormatter;
|
||||
@@ -58,20 +57,11 @@ public class SodiumControlElementFactory implements ControlElementFactory {
|
||||
|
||||
@Override
|
||||
public boolean mouseClicked(double mouseX, double mouseY, int button) {
|
||||
if(AngelicaConfig.enableReesesSodiumOptions) {
|
||||
if (this.option.isAvailable() && this.dim.containsCursor(mouseX, mouseY) && (button == 0 || button == 1)) {
|
||||
this.option.setValue(this.allowedValues[Math.floorMod(this.currentIndex() + (button == 0 ? 1 : -1), this.allowedValues.length)]);
|
||||
this.playClickSound();
|
||||
if (this.option.isAvailable() && this.dim.containsCursor(mouseX, mouseY) && (button == 0 || button == 1)) {
|
||||
this.option.setValue(this.allowedValues[Math.floorMod(this.currentIndex() + (button == 0 ? 1 : -1), this.allowedValues.length)]);
|
||||
this.playClickSound();
|
||||
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (this.option.isAvailable() && button == 0 && this.dim.containsCursor(mouseX, mouseY)) {
|
||||
this.option.setValue(this.allowedValues[(this.currentIndex() + 1) % this.allowedValues.length]);
|
||||
this.playClickSound();
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -43,8 +43,6 @@ sodium.options.entity_shadows.tooltip=Einfache Schatten unter Entitäten werden
|
||||
sodium.options.vignette.name=Vignette
|
||||
sodium.options.vignette.tooltip=Aktiviert einen Vignetteneffekt in der Spieleransicht. Beeinflusst die Bildrate nur selten, es sei denn, die Leistung ist durch die Fillrate begrenzt.
|
||||
sodium.options.mipmap_levels.tooltip=Steuert die Anzahl an Mipmaps, die für Blockmodelle verwendet werden. Höhere Werte sorgen für bessere Anzeigequalität in der Ferne, aber kann für animierte Texturen die Performance verschlechtern.
|
||||
sodium.options.use_chunk_multidraw.name=Chunk-Multidraw
|
||||
sodium.options.use_chunk_multidraw.tooltip=Multidraw ermöglicht das Rendern mehrerer Chunks mit weniger Zeichenbefehlen, wodurch die Rechenlast beim Rendern der Welt erheblich reduziert und die Ressourcennutzung effizienter wird. Diese Optimierung verursacht manchmal Probleme mit Grafiktreibern, und wenn du Grafikfehler bemerkt, könnte sie auszuschalten helfen.
|
||||
sodium.options.use_vertex_objects.name=Vertex-Array-Objekte
|
||||
sodium.options.use_vertex_objects.tooltip=Erhöht die Performance, indem Scheitelpunktinformation in den Treiber übertragen werden, um bessere Optimierung bei wiederholtem Rendern derselben Entitäten zu erlauben. Es gibt eigentlich keinen Grund, diese Option auszuschalten, außer du benutzt Mods, die damit nicht funktionieren.
|
||||
sodium.options.use_block_face_culling.name=Blockflächen-Culling
|
||||
|
||||
@@ -66,8 +66,6 @@ sodium.options.entity_shadows.tooltip=If enabled, basic shadows will be rendered
|
||||
sodium.options.vignette.name=Vignette
|
||||
sodium.options.vignette.tooltip=If enabled, a vignette effect will be rendered on the player's view. This is very unlikely to make a difference to frame rates unless you are fill-rate limited.
|
||||
sodium.options.mipmap_levels.tooltip=Controls the number of mipmaps which will be used for block model textures. Higher values provide better rendering of blocks in the distance, but may adversely affect performance with many animated textures.
|
||||
sodium.options.use_chunk_multidraw.name=Chunk Multi-Draw
|
||||
sodium.options.use_chunk_multidraw.tooltip=Multi-draw allows multiple chunks to be rendered with fewer draw calls, greatly reducing CPU overhead when rendering the world while also potentially allowing for more efficient GPU utilization. This optimization may cause issues with some graphics drivers, so you should try disabling it if you are experiencing glitches.
|
||||
sodium.options.use_vertex_objects.name=Vertex Array Objects
|
||||
sodium.options.use_vertex_objects.tooltip=Helps to improve performance by moving information about how vertex data should be rendered into the driver, allowing it to better optimize for repeated rendering of the same objects. There is generally no reason to disable this unless you're using incompatible mods.
|
||||
sodium.options.use_block_face_culling.name=Block Face Culling
|
||||
@@ -314,6 +312,46 @@ options.angelica.gpuCullingMode.tooltip=Selects the chunk culling pipeline. CPU
|
||||
options.angelica.gpuCullingMode.cpu_only=CPU Only
|
||||
options.angelica.gpuCullingMode.compute=Compute
|
||||
|
||||
options.angelica.overriddenBy=Overridden by -D%s
|
||||
options.angelica.status.restart=Restart to apply
|
||||
|
||||
options.angelica.renderer.page=Renderer
|
||||
options.angelica.renderer.link=Renderer
|
||||
options.angelica.renderer.link.tooltip=The graphics backend the game is running on. Click to open the Renderer page.
|
||||
options.angelica.renderer.backend=Backend
|
||||
options.angelica.renderer.backend.tooltip=Graphics API used to render the game. OpenGL is the default. SDL GPU renders through Vulkan, Metal or Direct3D 12 and returns to OpenGL when no device can be created. Takes effect after a game restart.
|
||||
options.angelica.renderer.backend.experimental=SDL GPU is experimental: expect crashes and rendering bugs.
|
||||
options.angelica.renderer.backend.unavailable=SDL GPU is unavailable: %s
|
||||
options.angelica.renderer.backend.opengl=OpenGL
|
||||
options.angelica.renderer.backend.sdl_gpu=SDL GPU (Experimental)
|
||||
options.angelica.renderer.driver=SDL GPU Driver
|
||||
options.angelica.renderer.driver.tooltip=Graphics API the SDL GPU backend uses. If the chosen driver cannot start, SDL's default is tried, then OpenGL. Takes effect after a game restart.
|
||||
options.angelica.renderer.driver.tooltip.macos=Auto uses Metal. Vulkan needs MoltenVK: put angelica-moltenvk.jar in the mods folder or install MoltenVK. Metal is used when Vulkan cannot start.
|
||||
options.angelica.renderer.driver.tooltip.windows=Auto uses Vulkan.
|
||||
options.angelica.renderer.driver.tooltip.d3d12=Direct3D 12 is very experimental and likely performs worse than Vulkan.
|
||||
options.angelica.renderer.driver.tooltip.other=Auto uses Vulkan.
|
||||
options.angelica.renderer.driver.auto=Auto
|
||||
options.angelica.renderer.driver.vulkan=Vulkan
|
||||
options.angelica.renderer.driver.metal=Metal
|
||||
options.angelica.renderer.driver.d3d12=Direct3D 12
|
||||
options.angelica.renderer.glVersion=OpenGL Version
|
||||
options.angelica.renderer.glVersion.tooltip=OpenGL context version to request. Auto uses the highest your hardware supports. Applies whenever the game runs on OpenGL, including when SDL GPU cannot start. Takes effect after a game restart.
|
||||
options.angelica.renderer.glVersion.auto=Auto
|
||||
options.angelica.renderer.status=Status
|
||||
options.angelica.renderer.status.tooltip=Whether the running backend matches the settings above.
|
||||
options.angelica.renderer.status.active=Active
|
||||
options.angelica.renderer.status.forced=Forced by JVM flag
|
||||
options.angelica.renderer.status.failed=SDL GPU failed to start, see log
|
||||
options.angelica.renderer.status.reset=Reset to OpenGL after a failed start
|
||||
options.angelica.renderer.active=Running On
|
||||
options.angelica.renderer.active.tooltip=The backend the game is rendering with right now.
|
||||
options.angelica.renderer.moltenvk=MoltenVK
|
||||
options.angelica.renderer.moltenvk.tooltip=Where MoltenVK was found. The SDL GPU Vulkan driver needs it on macOS.
|
||||
options.angelica.renderer.moltenvk.env=SDL_VULKAN_LIBRARY
|
||||
options.angelica.renderer.moltenvk.jar=angelica-moltenvk.jar
|
||||
options.angelica.renderer.moltenvk.system=System install
|
||||
options.angelica.renderer.moltenvk.none=Not found
|
||||
|
||||
options.angelica.tracy.page=Tracy Profiler
|
||||
options.angelica.tracy.enable=Enable Tracy
|
||||
options.angelica.tracy.enable.tooltip=Enable the Tracy profiler backend. Requires angelica-tracy.jar on the classpath. Takes effect after a game restart.
|
||||
@@ -323,10 +361,8 @@ options.angelica.tracy.fineZones=Fine Zones
|
||||
options.angelica.tracy.fineZones.tooltip=Emit Tracy zones for many more call sites. More detail, more overhead. Takes effect after a game restart.
|
||||
options.angelica.tracy.maxSrcLocs=Max Source Locations
|
||||
options.angelica.tracy.maxSrcLocs.tooltip=Maximum distinct Tracy zone and message call sites to preallocate. Takes effect after a game restart.
|
||||
options.angelica.tracy.overriddenBy=Overridden by -D%s
|
||||
options.angelica.tracy.status=Status
|
||||
options.angelica.tracy.status.tooltip=Whether Tracy is currently running and whether it matches the settings above.
|
||||
options.angelica.tracy.status.restart=Restart to apply
|
||||
options.angelica.tracy.status.running=Running
|
||||
options.angelica.tracy.status.runningForced=Running (forced by JVM flag)
|
||||
options.angelica.tracy.status.failed=Failed to start, see log
|
||||
|
||||
@@ -46,8 +46,6 @@ sodium.options.entity_shadows.tooltip=有効にすると、エンティティの
|
||||
sodium.options.vignette.name=ビネット
|
||||
sodium.options.vignette.tooltip=有効にすると、ゲーム画面にビネット効果が適用されます。フィルレートが制限されていない限り、FPSに影響が出る可能性は非常に低いでしょう。
|
||||
sodium.options.mipmap_levels.tooltip=ブロックのテクスチャに使用するミップマップの数を設定します。値が大きいほど遠くのブロックの見た目が良くなりますが、アニメーションが多いとパフォーマンスに悪影響を与える可能性があります。
|
||||
sodium.options.use_chunk_multidraw.name=チャンクの同時描画
|
||||
sodium.options.use_chunk_multidraw.tooltip=複数のチャンクを少ない回数で描画できます。CPU負荷を大幅に削減し、GPUの利用効率も向上する可能性があります。一部のグラフィックドライバで問題を引き起こす可能性があるため、不具合が発生する場合は無効にしてください。
|
||||
sodium.options.use_vertex_objects.name=頂点配列オブジェクト
|
||||
sodium.options.use_vertex_objects.tooltip=頂点の描画方法に関する情報をグラフィックドライバに移動することでパフォーマンスが向上し、同じオブジェクトの反復描画をより最適化できるようになります。互換性の無いMODを使用している場合を除き、通常はこの機能を無効にする必要はありません。
|
||||
sodium.options.use_block_face_culling.name=ブロック表面カリング
|
||||
|
||||
@@ -39,8 +39,6 @@ sodium.options.entity_shadows.tooltip=Jeśli włączone, podstawowe cienie będ
|
||||
sodium.options.vignette.name=Winieta
|
||||
sodium.options.vignette.tooltip=Jeśli włączone, efekt winiety będzie renderowany na widoku gracza. To raczej nie wpłynie na klatki na sekundę, chyba że jesteś ograniczany przez szybkość wypełniania.
|
||||
sodium.options.mipmap_levels.tooltip=Kontroluje ilość mipmap, które będą użyte do tekstur modeli bloków. Wyższe wartości skutkują lepszym renderowaniem bloków w oddali, lecz mogą spowodować pogorszenie wydajności przy dużej ilości animowanych tekstur.
|
||||
sodium.options.use_chunk_multidraw.name=Chunk Multi-Draw
|
||||
sodium.options.use_chunk_multidraw.tooltip=Multi-draw pozwala na renderowanie wielu chunków przy mniejszej liczbie wywołań rysowania, znacznie zmniejszając obciążenie CPU przy renderowaniu świata, jednocześnie potencjalnie pozwalając na bardziej efektywne użycie GPU. Ta optymalizacja może powodować problemy z niektórymi sterownikami graficznymi, więc powinieneś spróbować ją wyłączyć, jeśli napotykasz błędy.
|
||||
sodium.options.use_vertex_objects.name=Obiekty układu wierzchołków
|
||||
sodium.options.use_vertex_objects.tooltip=Pomaga poprawić wydajność poprzez przenoszenie informacji o tym, jak dane wierzchołków powinny być renderowane do sterownika, pozwalając na lepszą optymalizację dla wielokrotnego renderowania tych samych obiektów. Generalnie, nie ma potrzebyy wyłączania tego, chyba że używasz niekompatybilnych modów.
|
||||
sodium.options.use_block_face_culling.name=Chowanie ścian bloków
|
||||
|
||||
@@ -41,8 +41,6 @@ sodium.options.entity_shadows.tooltip=Если включено, под моба
|
||||
sodium.options.vignette.name=Виньетка
|
||||
sodium.options.vignette.tooltip=Если включено, на вид игрока будет наложен эффект виньетки. Это вряд ли повлияет на частоту кадров, если вы не ограничены заполнением.
|
||||
sodium.options.mipmap_levels.tooltip=Контролирует количество мип-карт, которые будут использоваться для текстур моделей блоков. Более высокие значения обеспечивают лучшую отрисовку блоков на расстоянии, но могут негативно повлиять на производительность при наличии многих анимированных текстур.
|
||||
sodium.options.use_chunk_multidraw.name=Мульти-Рисование Чанков
|
||||
sodium.options.use_chunk_multidraw.tooltip=Мульти-рисование позволяет отрисовывать несколько чанков с меньшим количеством вызовов рисования, значительно снижая нагрузку на CPU при рендеринге мира, а также потенциально позволяя более эффективное использование GPU. Эта оптимизация может вызвать проблемы с некоторыми графическими драйверами, поэтому вы должны попробовать отключить ее, если у вас возникают сбои.
|
||||
sodium.options.use_vertex_objects.name=Объекты Вершин
|
||||
sodium.options.use_vertex_objects.tooltip=Помогает улучшить производительность, перемещая информацию о том, как должны отображаться вершинные данные, в драйвер, позволяя ему лучше оптимизировать повторное отображение одних и тех же объектов. Обычно нет причин отключать это, если вы не используете несовместимые моды.
|
||||
sodium.options.use_block_face_culling.name=Отсечение Лиц Блока
|
||||
|
||||
@@ -57,8 +57,6 @@ sodium.options.entity_shadows.tooltip=Якщо увімкнено, під моб
|
||||
sodium.options.vignette.name=Віньєтка
|
||||
sodium.options.vignette.tooltip=Якщо увімкнено, на екрані відображатиметься ефект затемнення по краях. Це навряд чи вплине на частоту кадрів, за винятком випадків, коли продуктивність обмежена швидкістю заповнення вашої відеокарти.
|
||||
sodium.options.mipmap_levels.tooltip=Керує кількістю рівнів MIP-текстурування для моделей блоків. Вищі значення покращують вигляд віддалених блоків, але можуть негативно вплинути на продуктивність, якщо у грі багато анімованих текстур.
|
||||
sodium.options.use_chunk_multidraw.name=Мультипромальовування чанків
|
||||
sodium.options.use_chunk_multidraw.tooltip=Мультипромальовування дозволяє рендерити кілька чанків із меншою кількістю викликів промальовування. Це суттєво знижує навантаження на процесор під час відтворення світу, а також дозволяє ефективніше використовувати відеокарту. Ця оптимізація може викликати проблеми з деякими графічними драйверами, тому її варто вимкнути, якщо ви помітили збої чи артефакти.
|
||||
sodium.options.use_vertex_objects.name=Об’єкти буферів вершин
|
||||
sodium.options.use_vertex_objects.tooltip=Допомагає підвищити продуктивність, передаючи інформацію про спосіб рендерингу вершин безпосередньо драйверу. Це дозволяє краще оптимізувати повторний рендеринг тих самих об’єктів. Зазвичай немає причин вимикати цей параметр, якщо ви не використовуєте несумісні моди.
|
||||
sodium.options.use_block_face_culling.name=Відсікання граней блоків
|
||||
@@ -300,4 +298,4 @@ sodium.options.upload_method.buffer_data=BufferData
|
||||
sodium.options.upload_method.buffer_subdata=BufferSubData
|
||||
sodium.options.upload_method.map_buffer=MapBufferRange
|
||||
sodium.options.enable_deferred_batching.name=Відкладене групування частинок
|
||||
sodium.options.enable_deferred_batching.tooltip=Групує виклики малювання частинок, об’єднуючи їх у значно меншу кількість викликів для кожного шару рендерингу. Вимкніть, якщо частинки відображаються некоректно.
|
||||
sodium.options.enable_deferred_batching.tooltip=Групує виклики малювання частинок, об’єднуючи їх у значно меншу кількість викликів для кожного шару рендерингу. Вимкніть, якщо частинки відображаються некоректно.
|
||||
@@ -45,8 +45,6 @@ sodium.options.entity_shadows.tooltip=如果启用,将在生物和其他实体
|
||||
sodium.options.vignette.name=晕影
|
||||
sodium.options.vignette.tooltip=如果启用,将在玩家的画面上显示晕影效果。除非你的显卡像素填充率有限,否则这不太可能对帧率产生影响。
|
||||
sodium.options.mipmap_levels.tooltip=控制多级纹理的生成等级。较高的等级可以更好地渲染远处的方块,但可能会对许多纹理动画的性能产生不利影响。
|
||||
sodium.options.use_chunk_multidraw.name=使用区块多重绘制
|
||||
sodium.options.use_chunk_multidraw.tooltip=多重绘制允许通过更少的绘制请求来进行多区块渲染,在大大减少了渲染世界时的CPU负载的同时也可能提高了GPU利用率。此选项可能会让一些图形驱动程序出现问题,因此如果遇到相关问题,应尝试禁用它。
|
||||
sodium.options.use_vertex_objects.name=使用顶点数组对象
|
||||
sodium.options.use_vertex_objects.tooltip=通过将与顶点数据渲染方式相关的信息存储到驱动程序中,以优化对相同对象的重复渲染并提高性能。通常应保持开启,除非你使用了不兼容的模组
|
||||
sodium.options.use_block_face_culling.name=使用方块面剔除
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
options.button.detail=Details...
|
||||
options.button.other=Sonstige...
|
||||
options.button.particle=Partikel...
|
||||
options.button.sky=Atmosphäre...
|
||||
options.chunks=%s Chunks
|
||||
options.graphics.shelledfancy=Schön [Hybrid]
|
||||
options.graphics.shelledfast=Schnell [Hybrid]
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
options.button.detail=Details...
|
||||
options.button.other=Other...
|
||||
options.button.particle=Particles...
|
||||
options.button.sky=Atmosphere...
|
||||
options.chunks=%s chunks
|
||||
options.framerate=%s FPS
|
||||
options.graphics.shelledfancy=Hybrid Fancy
|
||||
@@ -84,4 +80,4 @@ options.zoom_smooth.tooltip=Smoothly interpolates the camera toward the zoom lev
|
||||
options.zoom_smooth_speed=Smooth Zoom Speed
|
||||
options.zoom_smooth_speed.tooltip=How fast smooth zoom converges to the target zoom. Higher is snappier, lower is floatier. No effect when Smooth Zoom is off.
|
||||
options.zoom_cinematic=Cinematic Camera Zoom
|
||||
options.zoom_cinematic.tooltip=Whether or not to use the Cinematic Camera smooth movement. Off is standard Minecraft mouse camera movement where camera snaps to mouse position. On is floating uninterrupted movement after initial mouse movement, where the camera continues to shift after halting mouse movement.
|
||||
options.zoom_cinematic.tooltip=Whether or not to use the Cinematic Camera smooth movement. Off is standard Minecraft mouse camera movement where camera snaps to mouse position. On is floating uninterrupted movement after initial mouse movement, where the camera continues to shift after halting mouse movement.
|
||||
@@ -1,7 +1,3 @@
|
||||
options.button.detail=詳細...
|
||||
options.button.other=その他...
|
||||
options.button.particle=パーティクル...
|
||||
options.button.sky=環境...
|
||||
options.chunks=%s チャンク
|
||||
options.framerate=%s FPS
|
||||
options.graphics.shelledfancy=描画優先(ハイブリッド)
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
options.button.detail=Detale...
|
||||
options.button.other=Inne...
|
||||
options.button.particle=Cząstki...
|
||||
options.button.sky=Atmosfera...
|
||||
options.chunks=%s chunków
|
||||
options.framerate=%s FPS
|
||||
options.graphics.shelledfancy=Hybrydowe dokładne
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
options.button.detail=Детали...
|
||||
options.button.other=Другое...
|
||||
options.button.particle=Частицы...
|
||||
options.button.sky=Атмосфера...
|
||||
options.chunks=%s чанков
|
||||
options.framerate=%s FPS
|
||||
options.graphics.shelledfancy=Гибридный Красивый
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
options.button.detail=Деталі...
|
||||
options.button.other=Інше...
|
||||
options.button.particle=Частинки...
|
||||
options.button.sky=Атмосфера...
|
||||
options.chunks=%s чанків
|
||||
options.framerate=%s FPS
|
||||
options.graphics.shelledfancy=Гібридна красива
|
||||
@@ -82,4 +78,4 @@ options.background.random=Випадково
|
||||
options.zoom_smooth=Плавне наближення
|
||||
options.zoom_smooth.tooltip=Плавно зміщує камеру до рівня наближення замість миттєвого перемикання.
|
||||
options.zoom_smooth_speed=Швидкість плавного наближення
|
||||
options.zoom_smooth_speed.tooltip=Швидкість, з якою плавне наближення досягає цільового рівня. Вищі значення роблять наближення різкішим, нижчі — м’якшим. Не має ефекту, якщо плавне наближення вимкнено.
|
||||
options.zoom_smooth_speed.tooltip=Швидкість, з якою плавне наближення досягає цільового рівня. Вищі значення роблять наближення різкішим, нижчі — м’якшим. Не має ефекту, якщо плавне наближення вимкнено.
|
||||
@@ -1,7 +1,3 @@
|
||||
options.button.detail=细节...
|
||||
options.button.other=杂项...
|
||||
options.button.particle=粒子...
|
||||
options.button.sky=天空...
|
||||
options.chunks=%s 个区块
|
||||
options.framerate=%s 帧率
|
||||
options.graphics.shelledfancy=默认
|
||||
|
||||
+17
-1
@@ -3,6 +3,7 @@ package com.gtnewhorizons.angelica.mixins.early.angelica;
|
||||
import com.gtnewhorizon.gtnhlib.config.ConfigurationManager;
|
||||
import com.gtnewhorizons.angelica.AngelicaMod;
|
||||
import com.gtnewhorizons.angelica.config.AngelicaConfig;
|
||||
import com.gtnewhorizons.angelica.config.GLVersionChoice;
|
||||
import com.gtnewhorizons.angelica.glsm.RenderSystem;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import net.minecraftforge.client.ForgeHooksClient;
|
||||
@@ -80,9 +81,24 @@ public abstract class MixinForgeHooksClient_CoreProfile {
|
||||
|
||||
int maxProbe = platformMax;
|
||||
|
||||
final int requested = GLVersionChoice.of(AngelicaConfig.glVersion, platformMax).version();
|
||||
if (requested >= 33) {
|
||||
final Exception e = angelica$tryCreate(attribs, format, setMajor, setMinor, requested / 10, requested % 10);
|
||||
if (e == null) {
|
||||
final int cap = angelica$validateContext(requested / 10, requested % 10);
|
||||
if (cap == 0) {
|
||||
LOGGER.info("Created GL {}.{} core profile context (requested)", requested / 10, requested % 10);
|
||||
return;
|
||||
}
|
||||
maxProbe = Math.min(maxProbe, cap);
|
||||
} else {
|
||||
LOGGER.warn("Requested GL version {}.{} failed", requested / 10, requested % 10);
|
||||
}
|
||||
}
|
||||
|
||||
// Try pinned version first if configured
|
||||
final int pinned = angelica$clampPinned(AngelicaConfig.pinnedGLVersion, platformMax);
|
||||
if (pinned >= 33) {
|
||||
if (pinned >= 33 && pinned != requested) {
|
||||
final Exception e = angelica$tryCreate(attribs, format, setMajor, setMinor, pinned / 10, pinned % 10);
|
||||
if (e == null) {
|
||||
final int cap = angelica$validateContext(pinned / 10, pinned % 10);
|
||||
|
||||
@@ -26,6 +26,7 @@ configurations {
|
||||
|
||||
val lwjglNatives: String by extra
|
||||
val tracyVersion = libs.versions.tracy.get()
|
||||
val tracyJarVersion = (findProperty("tracyJarVersion") as String?) ?: tracyVersion
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
@@ -118,7 +119,7 @@ tasks.named<Jar>("jar") {
|
||||
|
||||
val distJar = tasks.register<Jar>("distJar") {
|
||||
archiveBaseName.set("angelica-tracy")
|
||||
archiveVersion.set(tracyVersion)
|
||||
archiveVersion.set(tracyJarVersion)
|
||||
from(sourceSets["main"].output)
|
||||
manifest {
|
||||
attributes(
|
||||
@@ -133,7 +134,7 @@ publishing {
|
||||
create<MavenPublication>("mavenJava") {
|
||||
groupId = "com.gtnewhorizons.angelica"
|
||||
artifactId = "angelica-tracy"
|
||||
version = tracyVersion
|
||||
version = tracyJarVersion
|
||||
artifact(distJar)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package com.gtnewhorizons.umbra.loading;
|
||||
|
||||
import com.gtnewhorizon.gtnhmixins.IEarlyMixinLoader;
|
||||
import com.gtnewhorizon.gtnhmixins.builders.IMixins;
|
||||
import com.gtnewhorizons.angelica.config.SystemProperties;
|
||||
import com.gtnewhorizons.angelica.glsm.backend.BackendOptions;
|
||||
import com.gtnewhorizons.angelica.glsm.loading.DependencyVerifier;
|
||||
import com.gtnewhorizons.angelica.glsm.loading.Lwjgl3ifyExclusions;
|
||||
import com.gtnewhorizons.angelica.lwjgl3.MissingDependencySdl;
|
||||
@@ -54,7 +54,7 @@ public class UmbraClientTweaker implements IFMLLoadingPlugin, IEarlyMixinLoader
|
||||
DependencyVerifier.gtnhLibChecks("Umbra"), LOGGER,
|
||||
(title, message) -> MissingDependencySdl.showFatal(title, message));
|
||||
|
||||
if (SystemProperties.USE_SDL_GPU) {
|
||||
if (BackendOptions.sdlGpuRequested()) {
|
||||
if (SDLGPUGate.isSDLGPUAvailable()) {
|
||||
LOGGER.info("SDL GPU window mode enabled");
|
||||
} else {
|
||||
|
||||
@@ -2,7 +2,7 @@ package com.gtnewhorizons.umbra.mixins;
|
||||
|
||||
import com.gtnewhorizon.gtnhmixins.builders.IMixins;
|
||||
import com.gtnewhorizon.gtnhmixins.builders.MixinBuilder;
|
||||
import com.gtnewhorizons.angelica.config.SystemProperties;
|
||||
import com.gtnewhorizons.angelica.glsm.backend.BackendOptions;
|
||||
import com.gtnewhorizons.angelica.sdlgpu.SDLGPUGate;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -41,7 +41,7 @@ public enum Mixins implements IMixins {
|
||||
|
||||
UMBRA_SDL_GPU_DISPLAY(new MixinBuilder("SDL-GPU-aware Display.create path")
|
||||
.setPhase(Phase.EARLY)
|
||||
.setApplyIf(() -> SystemProperties.USE_SDL_GPU && SDLGPUGate.isSDLGPUAvailable())
|
||||
.setApplyIf(() -> BackendOptions.sdlGpuRequested() && SDLGPUGate.isSDLGPUAvailable())
|
||||
.addClientMixins(
|
||||
"early.sdlgpu.MixinForgeHooksClient_SDLGPUDisplay",
|
||||
"early.sdlgpu.MixinMinecraft_SDLGPUIcons"
|
||||
|
||||
Reference in new issue
Block a user