diff --git a/src/main/java/me/ramidzkh/fabrishot/Fabrishot.java b/src/main/java/me/ramidzkh/fabrishot/Fabrishot.java index 04d5e0f..94d79e9 100644 --- a/src/main/java/me/ramidzkh/fabrishot/Fabrishot.java +++ b/src/main/java/me/ramidzkh/fabrishot/Fabrishot.java @@ -120,4 +120,8 @@ public static float getScaleFactor() { return 1; } } + + public static boolean isInCapture() { + return task != null; + } } diff --git a/src/main/java/me/ramidzkh/fabrishot/config/ClothConfigBridge.java b/src/main/java/me/ramidzkh/fabrishot/config/ClothConfigBridge.java index 087aa8d..5086db4 100644 --- a/src/main/java/me/ramidzkh/fabrishot/config/ClothConfigBridge.java +++ b/src/main/java/me/ramidzkh/fabrishot/config/ClothConfigBridge.java @@ -29,6 +29,7 @@ import me.shedaniel.clothconfig2.api.ConfigBuilder; import me.shedaniel.clothconfig2.api.ConfigCategory; import me.shedaniel.clothconfig2.api.ConfigEntryBuilder; +import me.shedaniel.clothconfig2.gui.entries.IntegerListEntry; import net.minecraft.client.gui.screen.Screen; import net.minecraft.text.Text; @@ -69,19 +70,23 @@ public Screen create(Screen parent) { .setSaveConsumer(b -> Config.DISABLE_GUI_SCALING = b) .build()); - category.addEntry(entryBuilder.startIntField(Text.translatable("fabrishot.config.width"), Config.CAPTURE_WIDTH) + IntegerListEntry width = entryBuilder.startIntField(Text.translatable("fabrishot.config.width"), Config.CAPTURE_WIDTH) .setDefaultValue(3840) .setMin(1) .setMax(Math.min(65535, RenderSystem.maxSupportedTextureSize())) .setSaveConsumer(i -> Config.CAPTURE_WIDTH = i) - .build()); + .build(); + category.addEntry(width); - category.addEntry(entryBuilder.startIntField(Text.translatable("fabrishot.config.height"), Config.CAPTURE_HEIGHT) + IntegerListEntry height = entryBuilder.startIntField(Text.translatable("fabrishot.config.height"), Config.CAPTURE_HEIGHT) .setDefaultValue(2160) .setMin(1) .setMax(Math.min(65535, RenderSystem.maxSupportedTextureSize())) .setSaveConsumer(i -> Config.CAPTURE_HEIGHT = i) - .build()); + .build(); + category.addEntry(height); + + category.addEntry(new ScalingPresetEntry(220, width, height)); category.addEntry(entryBuilder.startIntField(Text.translatable("fabrishot.config.delay"), Config.CAPTURE_DELAY) .setTooltip(Text.translatable("fabrishot.config.delay.tooltip")) diff --git a/src/main/java/me/ramidzkh/fabrishot/config/ScalingPresetEntry.java b/src/main/java/me/ramidzkh/fabrishot/config/ScalingPresetEntry.java new file mode 100644 index 0000000..13e8feb --- /dev/null +++ b/src/main/java/me/ramidzkh/fabrishot/config/ScalingPresetEntry.java @@ -0,0 +1,103 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022, 2023 shedaniel + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.ramidzkh.fabrishot.config; + +import me.ramidzkh.fabrishot.MinecraftInterface; +import me.shedaniel.clothconfig2.api.AbstractConfigListEntry; +import me.shedaniel.clothconfig2.gui.entries.IntegerListEntry; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.Element; +import net.minecraft.client.gui.Selectable; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.text.Text; +import net.minecraft.util.Unit; + +import java.util.List; +import java.util.Optional; +import java.util.function.Supplier; +import java.util.stream.IntStream; + +public class ScalingPresetEntry extends AbstractConfigListEntry { + + private final List children; + private final int width; + + public ScalingPresetEntry(int myWidth, IntegerListEntry widthConfig, IntegerListEntry heightConfig) { + super(Text.empty(), false); + + this.children = IntStream.rangeClosed(1, 4) + .mapToObj(scaleFactor -> (ButtonWidget) new ButtonWidget(0, 0, 0, 20, Text.literal(scaleFactor + "x"), button -> { + int width = MinecraftInterface.getDisplayWidth() * scaleFactor; + int height = MinecraftInterface.getDisplayHeight() * scaleFactor; + + widthConfig.setValue(Integer.toString(width)); + heightConfig.setValue(Integer.toString(height)); + }, Supplier::get) { + }) + .toList(); + this.width = myWidth; + } + + @Override + public Unit getValue() { + return Unit.INSTANCE; + } + + @Override + public Optional getDefaultValue() { + return Optional.of(Unit.INSTANCE); + } + + @Override + public void save() { + } + + @Override + public void render(DrawContext graphics, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean isHovered, float delta) { + super.render(graphics, index, y, x, entryWidth, entryHeight, mouseX, mouseY, isHovered, delta); + + int totalGap = (this.children.size() - 1) * 4; + int childWidth = (this.width - totalGap) / this.children.size(); + + for (int i = 0; i < children.size(); i++) { + ButtonWidget child = children.get(i); + child.active = this.isEditable(); + child.setX(x + entryWidth / 2 - this.width / 2 + i * (childWidth + 4)); + child.setY(y); + child.setWidth(childWidth - 2); + + child.render(graphics, mouseX, mouseY, delta); + } + } + + @Override + public List children() { + return children; + } + + @Override + public List narratables() { + return children; + } +} diff --git a/src/main/java/me/ramidzkh/fabrishot/mixins/RenderSystemMixin.java b/src/main/java/me/ramidzkh/fabrishot/mixins/RenderSystemMixin.java new file mode 100644 index 0000000..58233f4 --- /dev/null +++ b/src/main/java/me/ramidzkh/fabrishot/mixins/RenderSystemMixin.java @@ -0,0 +1,32 @@ +package me.ramidzkh.fabrishot.mixins; + +import com.mojang.blaze3d.systems.RenderSystem; +import me.ramidzkh.fabrishot.Fabrishot; +import org.lwjgl.glfw.GLFW; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(RenderSystem.class) +public class RenderSystemMixin { + + @Unique + private static boolean wasLastFrameInCapture; + + @Redirect(method = "flipFrame", at = @At(value = "INVOKE", target = "Lorg/lwjgl/glfw/GLFW;glfwSwapBuffers(J)V")) + private static void glfwSwapBuffers(long window) { + if (Fabrishot.isInCapture()) { + wasLastFrameInCapture = true; + return; + } + + // skip a single black frame + if (wasLastFrameInCapture) { + wasLastFrameInCapture = false; + return; + } + + GLFW.glfwSwapBuffers(window); + } +} diff --git a/src/main/resources/mixins.fabrishot.json b/src/main/resources/mixins.fabrishot.json index c6abacf..b4907f3 100644 --- a/src/main/resources/mixins.fabrishot.json +++ b/src/main/resources/mixins.fabrishot.json @@ -6,6 +6,7 @@ "mixins": [ "KeyboardMixin", "MinecraftClientMixin", + "RenderSystemMixin", "WindowAccessor" ], "injectors": {