diff --git a/build.gradle b/build.gradle deleted file mode 100644 index 6a04a5e..0000000 --- a/build.gradle +++ /dev/null @@ -1,87 +0,0 @@ -import java.time.Instant - -buildscript { - repositories { - maven { url = 'https://files.minecraftforge.net/maven' } - jcenter() - mavenCentral() - } - dependencies { - classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '3.+', changing: true - } -} - -apply plugin: 'net.minecraftforge.gradle' - -group = "com.unascribed" -archivesBaseName = "BlockRenderer" -version = "1.16.1-1.3.0" - -sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = JavaVersion.VERSION_1_8 - -minecraft { - mappings channel: 'snapshot', version: '20200820-1.16.1' - - // accessTransformer = file('src/main/resources/META-INF/block_renderer_at.cfg') - - runs { - client { - workingDirectory project.file('run') - - property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP' - property 'forge.logging.console.level', 'debug' - - mods { - blockrenderer { - source sourceSets.main - } - } - } - - server { - workingDirectory project.file('run') - - property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP' - property 'forge.logging.console.level', 'debug' - - mods { - blockrenderer { - source sourceSets.main - } - } - } - } -} - -dependencies { - minecraft 'net.minecraftforge:forge:1.16.1-32.0.108' - - // Javax Annotations (N.B. ForgeGradle currently provides this) - implementation 'com.google.code.findbugs:jsr305:3+' -} - -jar { - manifest { - attributes([ - 'Specification-Title' : rootProject.name, - 'Specification-Vendor' : project.group, - 'Specification-Version' : '1', - 'Implementation-Title' : rootProject.name, - 'Implementation-Version' : project.version, - 'Implementation-Vendor' : project.group, - 'Implementation-Timestamp': Instant.now() - ]) - } -} - -jar.finalizedBy('reobfJar') - -task sourcesJar(type: Jar, dependsOn: classes) { - classifier = 'sources' - from sourceSets.main.allSource -} -build.dependsOn sourcesJar - -artifacts { - archives sourcesJar -} diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000..65e8b4a --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,141 @@ +/*================================================================================================== BuildScript ==== */ +buildscript { + repositories { + maven(url = "https://files.minecraftforge.net/maven") + jcenter() + mavenCentral() + } + + dependencies { + classpath(group = "net.minecraftforge.gradle", name = "ForgeGradle", version = "3.+") { + isChanging = true + } + } +} + +/*========================================================================================== Config -> Minecraft ==== */ +val forgeVersion: String by extra +val mappingsChannel: String by extra +val mappingsVersion: String by extra +val minecraftVersion: String by extra + +/*================================================================================================ Config -> Mod ==== */ +val modId: String by extra +val modVersion: String by extra +val modGroup: String by extra +val vendor: String by extra + +/*========================================================================================= Config -> Run Config ==== */ +val level: String by extra +val markers: String by extra + +/*======================================================================================= Config -> Dependencies ==== */ +val jetbrainsAnnotationVersion: String by extra + +/*================================================================================== Config -> Test Dependencies ==== */ +val junitVersion: String by extra + +/*====================================================================================================== Plugins ==== */ +plugins { + `java-library` +} + +apply(plugin = "net.minecraftforge.gradle") + +/*========================================================================================= Minecraft Dependency ==== */ + +/* Note: Due to the way kotlin gradle works we need to define the minecraft dependency before we configure Minecraft */ +dependencies { + "minecraft"(group = "net.minecraftforge", name = "forge", version = "$minecraftVersion-$forgeVersion") +} + +/*==================================================================================================== Minecraft ==== */ + +minecraft { + mappingChannel = mappingsChannel + mappingVersion = mappingsVersion + + runs { + config("client") + config("server") + +// config("data") { +// args("--mod", modId, "--all", "--output", file("src/generated/resources/")) +// } + } +} + +/*======================================================================================================== Setup ==== */ +project.group = modGroup +project.version = "$minecraftVersion-$modVersion" + +/* Java 8 Target + Parameter Names */ +tasks.withType { + sourceCompatibility = "1.8" + targetCompatibility = "1.8" + options.compilerArgs.add("-parameters") +} + +/* Finalize the jar by Reobf */ +tasks.named("jar") { + finalizedBy("reobfJar") +} + +/* Manifest */ +tasks.withType { + manifest { + attributes( + "Specification-Title" to modId, + "Specification-Vendor" to vendor, + "Specification-Version" to modVersion, + "Implementation-Title" to project.name, + "Implementation-Version" to project.version, + "Implementation-Vendor" to vendor, + "Implementation-Timestamp" to Date().format("yyyy-MM-dd'T'HH:mm:ssZ") + ) + } +} + +/* Generate Package Infos */ +apply(from = "utils.gradle.kts") + +/*================================================================================================= Dependencies ==== */ + +dependencies { + /* JUnit 5 */ + testImplementation(group = "org.junit.jupiter", name = "junit-jupiter", version = junitVersion) + + /* Jetbrains Annotations */ + implementation(group = "org.jetbrains", name = "annotations", version = jetbrainsAnnotationVersion) +} + +/*==================================================================================================== Utilities ==== */ + +typealias Date = java.util.Date +typealias SimpleDateFormat = java.text.SimpleDateFormat + +fun Date.format(format: String) = SimpleDateFormat(format).format(this) + +typealias RunConfig = net.minecraftforge.gradle.common.util.RunConfig +typealias UserDevExtension = net.minecraftforge.gradle.userdev.UserDevExtension + +typealias RunConfiguration = RunConfig.() -> Unit + +fun minecraft(configuration: UserDevExtension.() -> Unit) = + configuration(extensions.getByName("minecraft") as UserDevExtension) + +fun NamedDomainObjectContainerScope.config(name: String, additionalConfiguration: RunConfiguration = {}) { + val runDirectory = project.file("run") + val sourceSet = the().sourceSets["main"] + + create(name) { + workingDirectory(runDirectory) + property("forge.logging.markers", markers) + property("forge.logging.console.level", level) + environment("MOD_VERSION", modVersion) + + additionalConfiguration(this) + + mods { create(modId) { source(sourceSet) } } + } +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 29b2ac4..a17c3bb 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,31 @@ -org.gradle.jvmargs=-Xmx3G -org.gradle.daemon=false +################################## Intellij ################################### +# suppress inspection "UnusedProperty" for whole file + +################################### Gradle #################################### +# Default Memory for Gradle Commands. Required for Minecraft de-compilation +org.gradle.jvmargs =-Xmx3G +# ForgeGradle shouldn't be run as a Daemon. +org.gradle.daemon =false + +################################## Minecraft ################################## +forgeVersion =32.0.108 +mappingsChannel =snapshot +mappingsVersion =20200820-1.16.1 +minecraftVersion =1.16.1 + +##################################### Mod ##################################### +modId =block_renderer +modVersion =1.4.0 +modGroup =com.unascribed +vendor =AterAnimAvis + +################################# Run Config ################################## +level =debug +markers =NONE +defaultMarkers =SCAN,REGISTRIES,REGISTRYDUMP + +################################ Dependencies ################################# +jetbrainsAnnotationVersion=20.1.+ + +############################## Test Dependencies ############################## +junitVersion =5.6.+ \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 7134c02..2f7ae08 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Tue Apr 28 18:20:48 BST 2020 -distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-all.zip +distributionUrl =https\://services.gradle.org/distributions/gradle-5.3-all.zip distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -zipStorePath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME +zipStorePath =wrapper/dists +zipStoreBase =GRADLE_USER_HOME \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/BlockRenderer.java b/src/main/java/com/unascribed/blockrenderer/BlockRenderer.java index 8b53eff..a91e1fe 100644 --- a/src/main/java/com/unascribed/blockrenderer/BlockRenderer.java +++ b/src/main/java/com/unascribed/blockrenderer/BlockRenderer.java @@ -1,6 +1,6 @@ package com.unascribed.blockrenderer; -import com.unascribed.blockrenderer.proxy.ClientProxy; +import com.unascribed.blockrenderer.client.proxy.ClientProxy; import com.unascribed.blockrenderer.proxy.CommonProxy; import com.unascribed.blockrenderer.proxy.DedicatedProxy; import net.minecraftforge.fml.DistExecutor; @@ -18,14 +18,15 @@ @Mod(Reference.MOD_ID) public class BlockRenderer { - public static final Logger LOGGER = LogManager.getLogger("BlockRenderer"); + public static final Logger LOGGER = LogManager.getLogger(Reference.NAME); - public static CommonProxy proxy; + public static CommonProxy proxy = DistExecutor.safeRunForDist(() -> ClientProxy::new, () -> DedicatedProxy::new); public BlockRenderer() { - proxy = DistExecutor.safeRunForDist(() -> ClientProxy::new, () -> DedicatedProxy::new); proxy.init(); + LOGGER.info("Running Version: " + Reference.VERSION); + registerDisplayTest(ModLoadingContext.get()); } diff --git a/src/main/java/com/unascribed/blockrenderer/Reference.java b/src/main/java/com/unascribed/blockrenderer/Reference.java index 0fa5254..9438897 100644 --- a/src/main/java/com/unascribed/blockrenderer/Reference.java +++ b/src/main/java/com/unascribed/blockrenderer/Reference.java @@ -1,9 +1,15 @@ package com.unascribed.blockrenderer; +import net.minecraftforge.fml.loading.FMLEnvironment; +import net.minecraftforge.fml.loading.JarVersionLookupHandler; + public interface Reference { String MOD_ID = "block_renderer"; String NAME = "BlockRenderer"; - String VERSION = "1.2.0"; + + String VERSION = JarVersionLookupHandler.getSpecificationVersion(Reference.class).orElseGet(() -> System.getenv("MOD_VERSION")); + + boolean isDebug = !FMLEnvironment.production; } diff --git a/src/main/java/com/unascribed/blockrenderer/annotation/MethodsReturnNonnullByDefault.java b/src/main/java/com/unascribed/blockrenderer/annotation/MethodsReturnNonnullByDefault.java deleted file mode 100644 index 9c6fe10..0000000 --- a/src/main/java/com/unascribed/blockrenderer/annotation/MethodsReturnNonnullByDefault.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.unascribed.blockrenderer.annotation; - -import javax.annotation.Nonnull; -import javax.annotation.meta.TypeQualifierDefault; -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * This annotation can be applied to a package, class or method to indicate that - * the method in that element are nonnull by default unless there is: - *
    - *
  • An explicit nullness annotation - *
  • The method overrides a method in a superclass (in which case the - * annotation of the corresponding method in the superclass applies) - *
  • there is a default parameter annotation applied to a more tightly nested - * element. - *
- * - */ -@Documented -@Nonnull -@TypeQualifierDefault(ElementType.METHOD) -@Retention(RetentionPolicy.RUNTIME) -public @interface MethodsReturnNonnullByDefault {} diff --git a/src/main/java/com/unascribed/blockrenderer/init/Keybindings.java b/src/main/java/com/unascribed/blockrenderer/client/init/Keybindings.java similarity index 94% rename from src/main/java/com/unascribed/blockrenderer/init/Keybindings.java rename to src/main/java/com/unascribed/blockrenderer/client/init/Keybindings.java index 24e8a2d..6783ae5 100644 --- a/src/main/java/com/unascribed/blockrenderer/init/Keybindings.java +++ b/src/main/java/com/unascribed/blockrenderer/client/init/Keybindings.java @@ -1,4 +1,4 @@ -package com.unascribed.blockrenderer.init; +package com.unascribed.blockrenderer.client.init; import net.minecraft.client.settings.KeyBinding; import net.minecraftforge.api.distmarker.Dist; diff --git a/src/main/java/com/unascribed/blockrenderer/client/init/package-info.java b/src/main/java/com/unascribed/blockrenderer/client/init/package-info.java new file mode 100644 index 0000000..bbc9c2d --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/init/package-info.java @@ -0,0 +1,4 @@ +@NonnullDefault +package com.unascribed.blockrenderer.client.init; + +import org.lwjgl.system.NonnullDefault; \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/proxy/ClientProxy.java b/src/main/java/com/unascribed/blockrenderer/client/proxy/ClientProxy.java similarity index 69% rename from src/main/java/com/unascribed/blockrenderer/proxy/ClientProxy.java rename to src/main/java/com/unascribed/blockrenderer/client/proxy/ClientProxy.java index d589d60..149992e 100644 --- a/src/main/java/com/unascribed/blockrenderer/proxy/ClientProxy.java +++ b/src/main/java/com/unascribed/blockrenderer/client/proxy/ClientProxy.java @@ -1,11 +1,12 @@ -package com.unascribed.blockrenderer.proxy; - -import com.unascribed.blockrenderer.init.Keybindings; -import com.unascribed.blockrenderer.render.SingleRenderer; -import com.unascribed.blockrenderer.render.impl.ItemStackRenderer; -import com.unascribed.blockrenderer.render.request.IRequest; -import com.unascribed.blockrenderer.screens.EnterNamespaceScreen; -import com.unascribed.blockrenderer.screens.EnterSizeScreen; +package com.unascribed.blockrenderer.client.proxy; + +import com.unascribed.blockrenderer.client.init.Keybindings; +import com.unascribed.blockrenderer.client.render.RenderManager; +import com.unascribed.blockrenderer.client.render.item.ItemRenderer; +import com.unascribed.blockrenderer.client.screens.SelectionScreen; +import com.unascribed.blockrenderer.client.screens.item.EnterSizeScreen; +import com.unascribed.blockrenderer.client.varia.Registries; +import com.unascribed.blockrenderer.proxy.CommonProxy; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.recipebook.IRecipeShownListener; import net.minecraft.client.gui.recipebook.RecipeBookGui; @@ -16,40 +17,31 @@ import net.minecraft.entity.player.PlayerEntity; import net.minecraft.inventory.container.Slot; import net.minecraft.item.ItemStack; -import net.minecraft.util.ResourceLocation; import net.minecraft.util.text.TranslationTextComponent; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.TickEvent; import net.minecraftforge.eventbus.api.EventPriority; import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.registries.ForgeRegistries; import org.lwjgl.glfw.GLFW; -import java.util.Deque; -import java.util.LinkedList; - -import static com.unascribed.blockrenderer.utils.StringUtils.addMessage; +import static com.unascribed.blockrenderer.client.varia.StringUtils.addMessage; public class ClientProxy extends CommonProxy { private boolean down = false; - private final Deque pendingRequests = new LinkedList<>(); @Override public void init() { MinecraftForge.EVENT_BUS.register(this); + Registries.clazzLoad(); } - @Override - public void render(IRequest request) { - pendingRequests.add(request); - } @SubscribeEvent(priority = EventPriority.HIGHEST) public void onFrameStart(TickEvent.RenderTickEvent e) { if (e.phase != TickEvent.Phase.START) return; - if (pendingRequests.size() > 0) pendingRequests.poll().render(); + RenderManager.onFrameStart(); if (!isKeyDown()) { down = false; @@ -62,24 +54,17 @@ public void onFrameStart(TickEvent.RenderTickEvent e) { Minecraft client = Minecraft.getInstance(); Slot hovered = null; Screen currentScreen = client.currentScreen; - boolean isContainerScreen = currentScreen instanceof ContainerScreen; + boolean isContainerScreen = currentScreen instanceof ContainerScreen; - if (isContainerScreen) hovered = ((ContainerScreen) currentScreen).getSlotUnderMouse(); + // Intellij Bork-ing wants explicit null check. + if (currentScreen != null && isContainerScreen) hovered = ((ContainerScreen) currentScreen).getSlotUnderMouse(); if (Screen.hasControlDown()) { - String namespace = ""; - if (hovered != null && hovered.getHasStack()) { - ResourceLocation identifier = ForgeRegistries.ITEMS.getKey(hovered.getStack().getItem()); - if (identifier != null) namespace = identifier.getNamespace(); - } - PlayerEntity player = client.player; - if (!isContainerScreen && player != null && !player.getHeldItemMainhand().isEmpty()) { - ResourceLocation identifier = ForgeRegistries.ITEMS.getKey(player.getHeldItemMainhand().getItem()); - if (identifier != null) namespace = identifier.getNamespace(); - } + ItemStack input = hovered != null && hovered.getHasStack() ? hovered.getStack() : null; + if (input == null && player != null) input = player.getHeldItemMainhand(); - client.displayGuiScreen(new EnterNamespaceScreen(client.currentScreen, namespace.trim())); + client.displayGuiScreen(new SelectionScreen(client.currentScreen, input)); return; } @@ -117,7 +102,7 @@ private static void renderStack(ItemStack stack) { return; } - SingleRenderer.render(new ItemStackRenderer(), stack, 512, false, false); + RenderManager.push(ItemRenderer.single(stack, 512, false, false)); } private static boolean isKeyDown() { @@ -134,7 +119,7 @@ private static boolean isKeyDown() { if (currentScreen == null) return false; /* Non Containers seem to behave ok */ - boolean hasSlots = currentScreen instanceof ContainerScreen; + boolean hasSlots = currentScreen instanceof ContainerScreen; if (!hasSlots) return false; /* TextFieldWidgets */ diff --git a/src/main/java/com/unascribed/blockrenderer/client/proxy/package-info.java b/src/main/java/com/unascribed/blockrenderer/client/proxy/package-info.java new file mode 100644 index 0000000..28ff592 --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/proxy/package-info.java @@ -0,0 +1,4 @@ +@NonnullDefault +package com.unascribed.blockrenderer.client.proxy; + +import org.lwjgl.system.NonnullDefault; \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/render/IAnimatedRenderer.java b/src/main/java/com/unascribed/blockrenderer/client/render/IAnimatedRenderer.java new file mode 100644 index 0000000..8b143b7 --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/render/IAnimatedRenderer.java @@ -0,0 +1,14 @@ +package com.unascribed.blockrenderer.client.render; + +import com.unascribed.blockrenderer.client.render.request.lambda.ImageHandler; + +public interface IAnimatedRenderer extends IRenderer { + + @Override + default void render(T instance, ImageHandler consumer) { + render(instance, consumer, 0L); + } + + void render(T instance, ImageHandler consumer, long nano); + +} \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/render/IRenderer.java b/src/main/java/com/unascribed/blockrenderer/client/render/IRenderer.java new file mode 100644 index 0000000..4b8b37e --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/render/IRenderer.java @@ -0,0 +1,13 @@ +package com.unascribed.blockrenderer.client.render; + +import com.unascribed.blockrenderer.client.render.request.lambda.ImageHandler; + +public interface IRenderer { + + void setup(S parameters); + + void render(T instance, ImageHandler consumer); + + void teardown(); + +} \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/render/IRequest.java b/src/main/java/com/unascribed/blockrenderer/client/render/IRequest.java new file mode 100644 index 0000000..4c1441a --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/render/IRequest.java @@ -0,0 +1,7 @@ +package com.unascribed.blockrenderer.client.render; + +public interface IRequest { + + boolean render(); + +} \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/render/RenderManager.java b/src/main/java/com/unascribed/blockrenderer/client/render/RenderManager.java new file mode 100644 index 0000000..621fb55 --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/render/RenderManager.java @@ -0,0 +1,167 @@ +package com.unascribed.blockrenderer.client.render; + +import com.unascribed.blockrenderer.client.render.report.ProgressManager; +import com.unascribed.blockrenderer.client.render.request.lambda.ImageHandler; +import com.unascribed.blockrenderer.client.varia.Images; +import com.unascribed.blockrenderer.client.varia.gif.GifWriter; +import com.unascribed.blockrenderer.client.varia.logging.Log; +import com.unascribed.blockrenderer.client.varia.logging.Markers; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.StringTextComponent; +import net.minecraft.util.text.TextFormatting; +import org.jetbrains.annotations.Nullable; + +import javax.imageio.stream.ImageOutputStream; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.util.Collection; +import java.util.PriorityQueue; +import java.util.Queue; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; +import java.util.function.Function; + +public class RenderManager { + + public static boolean isRendering = false; + public static Queue requests = new PriorityQueue<>(); + @Nullable + private static IRequest request = null; + + public static void push(IRequest request) { + requests.add(request); + } + + public static void onFrameStart() { + if (request == null) request = requests.poll(); + if (request == null) return; + + if (request.render()) + request = null; + + isRendering = false; + } + + public static void render(IRenderer renderer, ImageHandler handler, + S params, T value, Consumer callback) { + isRendering = true; + + renderer.setup(params); + renderer.render(value, handler); + renderer.teardown(); + callback.accept(value); + + isRendering = false; + } + + private static final ITextComponent RENDERING_BULK = new StringTextComponent("Rendering Bulk").mergeStyle(TextFormatting.GOLD); + + public static void bulk(IRenderer renderer, ImageHandler handler, + S params, Collection values) { + isRendering = true; + + renderer.setup(params); + + ProgressManager.init(RENDERING_BULK, values.size()); + for (T value : values) { + ProgressManager.push(ProgressManager.getProgress()); + renderer.render(value, handler); + ProgressManager.pop(); + + ProgressManager.render(); + } + ProgressManager.end(); + + renderer.teardown(); + + isRendering = false; + } + + private static final int FPS = 20; + private static final int AUTO_LOOP_LENGTH = 30; + private static final long NANOS_IN_A_SECOND = 1_000_000_000L; + + public static void animated(IAnimatedRenderer renderer, + Function provider, + Consumer callback, + S params, + int length, + boolean loop, + T value) { + try { + try (ImageOutputStream stream = provider.apply(value)) { + if (stream == null) return; + + try (GifWriter writer = new GifWriter(stream, FPS, true)) { + ImageHandler writeFrame = (v, img) -> { + try { + writer.writeFrame(img); + } catch (IOException e) { + throw new RuntimeException(e); + } + }; + + animated(renderer, callback, params, length, loop, value, writeFrame); + } + } + } catch (Exception e) { + Log.error(Markers.MANAGER, "Exception", e); + } finally { + ProgressManager.end(); + isRendering = false; + } + } + + private static final ITextComponent RENDERING_GIF = new StringTextComponent("Rendering GIF").mergeStyle(TextFormatting.GOLD); + private static final ITextComponent RENDERING_AUTO = new StringTextComponent("Auto Loop").mergeStyle(TextFormatting.GOLD); + + private static void animated(IAnimatedRenderer renderer, Consumer callback, S params, int length, boolean loop, T value, ImageHandler write) throws RuntimeException { + + AtomicBoolean isSameAsInitial = new AtomicBoolean(false); + AtomicReference initial = new AtomicReference<>(); + + RenderManager.isRendering = true; + + renderer.setup(params); + + ImageHandler init = (v, image) -> initial.compareAndSet(null, image); + ImageHandler checkImage = (v, image) -> isSameAsInitial.set(Images.same(initial.get(), image)); + ImageHandler writeFinal = checkImage.andThen((v, image) -> { + if (!isSameAsInitial.get()) write.accept(v, image); + }); + + /* Render for Specified Length */ + ProgressManager.init(RENDERING_GIF, length); + for (int i = 0; i < length; i++) { + final ImageHandler consumer = i == 0 ? init.andThen(write) : i == length - 1 ? checkImage.andThen(write) : write; + + ProgressManager.push(ProgressManager.getProgress()); + renderer.render(value, consumer, NANOS_IN_A_SECOND / FPS * i); + ProgressManager.pop(); + + ProgressManager.render(); + + } + ProgressManager.end(); + + if (loop) { + /* Search for Loop Point */ + ProgressManager.init(RENDERING_AUTO, -1); + for (int i = 0; i < FPS * AUTO_LOOP_LENGTH; i++) { + ProgressManager.push(ProgressManager.getProgress()); + renderer.render(value, writeFinal, NANOS_IN_A_SECOND / FPS * (length + i)); + ProgressManager.pop(); + + if (isSameAsInitial.get()) break; + ProgressManager.render(); + } + ProgressManager.end(); + } + + callback.accept(value); + + renderer.teardown(); + } + +} \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/render/item/BaseItemStackHandler.java b/src/main/java/com/unascribed/blockrenderer/client/render/item/BaseItemStackHandler.java new file mode 100644 index 0000000..4eec844 --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/render/item/BaseItemStackHandler.java @@ -0,0 +1,57 @@ +package com.unascribed.blockrenderer.client.render.item; + +import com.unascribed.blockrenderer.client.varia.Identifiers; +import com.unascribed.blockrenderer.client.varia.StringUtils; +import net.minecraft.item.ItemStack; +import net.minecraft.util.text.StringTextComponent; +import net.minecraft.util.text.Style; +import net.minecraft.util.text.TextFormatting; +import net.minecraft.util.text.event.ClickEvent; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.util.function.Consumer; + +import static com.unascribed.blockrenderer.client.varia.StringUtils.sanitize; + +public class BaseItemStackHandler implements Consumer { + + @Nullable + protected File future = null; + + protected final File folder; + protected final int size; + protected final boolean useIdentifier; + protected final boolean addSize; + protected final boolean addDate; + + public BaseItemStackHandler(File folder, int size, boolean useIdentifier, boolean addSize, boolean addDate) { + this.folder = folder; + this.size = size; + this.useIdentifier = useIdentifier; + this.addSize = addSize; + this.addDate = addDate; + } + + @Override + public void accept(ItemStack value) { + Style open = Style.EMPTY.applyFormatting(TextFormatting.GOLD); + + if (future != null) + open = open.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_FILE, future.getAbsolutePath())); + + StringUtils.addMessage(new StringTextComponent("> Finished Rendering " + Identifiers.get(value.getItem())).setStyle(open)); + } + + protected String getFilename(ItemStack value) { + String sizeString = addSize ? size + "x" + size + "_" : ""; + String fileName = _getFilename(value, useIdentifier); + + return (addDate ? StringUtils.dateTime() + "_" : "") + sizeString + fileName; + } + + private String _getFilename(ItemStack value, boolean useIdentifier) { + return useIdentifier ? sanitize(Identifiers.get(value.getItem())) : sanitize(value.getDisplayName()); + } + +} \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/render/item/DefaultGifItemStackHandler.java b/src/main/java/com/unascribed/blockrenderer/client/render/item/DefaultGifItemStackHandler.java new file mode 100644 index 0000000..6cddd3f --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/render/item/DefaultGifItemStackHandler.java @@ -0,0 +1,25 @@ +package com.unascribed.blockrenderer.client.render.item; + +import com.unascribed.blockrenderer.client.varia.Files; +import net.minecraft.item.ItemStack; +import org.jetbrains.annotations.Nullable; + +import javax.imageio.stream.FileImageOutputStream; +import javax.imageio.stream.ImageOutputStream; +import java.io.File; +import java.util.function.Function; + +public class DefaultGifItemStackHandler extends BaseItemStackHandler implements Function { + + public DefaultGifItemStackHandler(File folder, int size, boolean useIdentifier, boolean addSize, boolean addDate) { + super(folder, size, useIdentifier, addSize, addDate); + } + + @Override + @Nullable + public ImageOutputStream apply(ItemStack value) { + future = Files.wrap("Exception whilst generating gif", () -> Files.getGif(folder, getFilename(value))); + return Files.wrap("Exception whilst generating gif", () -> new FileImageOutputStream(future)); + } + +} \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/render/item/DefaultPngItemStackHandler.java b/src/main/java/com/unascribed/blockrenderer/client/render/item/DefaultPngItemStackHandler.java new file mode 100644 index 0000000..ec7e4ea --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/render/item/DefaultPngItemStackHandler.java @@ -0,0 +1,40 @@ +package com.unascribed.blockrenderer.client.render.item; + +import com.unascribed.blockrenderer.client.render.request.lambda.ImageHandler; +import com.unascribed.blockrenderer.client.varia.Files; +import com.unascribed.blockrenderer.client.varia.StringUtils; +import net.minecraft.item.ItemStack; +import net.minecraft.util.text.StringTextComponent; +import net.minecraft.util.text.Style; +import net.minecraft.util.text.TextFormatting; +import net.minecraft.util.text.event.ClickEvent; + +import java.awt.image.BufferedImage; +import java.io.File; + +public class DefaultPngItemStackHandler extends BaseItemStackHandler implements ImageHandler, Runnable { + + public DefaultPngItemStackHandler(File folder, int size, boolean useIdentifier, boolean addSize, boolean addDate) { + super(folder, size, useIdentifier, addSize, addDate); + } + + @Override + public void accept(ItemStack value, BufferedImage image) { + Files.IOSupplier provider = () -> { + File file = Files.getPng(folder, getFilename(value)); + return Files.savePng(file, image); + }; + + future = Files.wrap("Exception whilst saving image", provider); + } + + @Override + public void run() { + Style open = Style.EMPTY + .applyFormatting(TextFormatting.GOLD) + .setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_FILE, folder.getAbsolutePath())); + + StringUtils.addMessage(new StringTextComponent("> Finished Rendering").setStyle(open)); + } + +} \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/render/item/ItemRenderer.java b/src/main/java/com/unascribed/blockrenderer/client/render/item/ItemRenderer.java new file mode 100644 index 0000000..b0c9755 --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/render/item/ItemRenderer.java @@ -0,0 +1,83 @@ +package com.unascribed.blockrenderer.client.render.item; + +import com.google.common.base.Joiner; +import com.unascribed.blockrenderer.client.render.IRequest; +import com.unascribed.blockrenderer.client.render.map.DefaultPngMapHandler; +import com.unascribed.blockrenderer.client.render.map.MapDecorations; +import com.unascribed.blockrenderer.client.render.map.MapParameters; +import com.unascribed.blockrenderer.client.render.map.MapRenderer; +import com.unascribed.blockrenderer.client.render.request.AnimatedRenderingRequest; +import com.unascribed.blockrenderer.client.render.request.BulkRenderingRequest; +import com.unascribed.blockrenderer.client.render.request.RenderingRequest; +import com.unascribed.blockrenderer.client.varia.Files; +import net.minecraft.item.ItemStack; +import net.minecraft.world.storage.MapData; + +import java.io.File; +import java.util.List; +import java.util.Set; + +import static com.unascribed.blockrenderer.client.varia.MiscUtils.collectStacks; +import static com.unascribed.blockrenderer.client.varia.StringUtils.*; + +public class ItemRenderer { + + public static IRequest single(ItemStack stack, int size, boolean useId, boolean addSize) { + DefaultPngItemStackHandler handler = new DefaultPngItemStackHandler(Files.DEFAULT_FOLDER, size, useId, addSize, true); + + return new RenderingRequest<>( + new ItemStackRenderer(), + new ItemStackParameters(size), + stack, + handler, + handler + ); + } + + public static IRequest single(ItemStack stack, MapData data, int size, boolean useId, boolean addSize, MapDecorations decorations) { + DefaultPngMapHandler handler = new DefaultPngMapHandler(stack, Files.DEFAULT_FOLDER, size, useId, addSize, true); + + return new RenderingRequest<>( + new MapRenderer(), + new MapParameters(size, decorations), + data, + handler, + handler + ); + } + + public static IRequest bulk(String spec, int size, boolean useId, boolean addSize) { + Set namespaces = getNamespaces(spec); + List renders = collectStacks(namespaces); + String joined = Joiner.on(", ").join(namespaces); + + String sizeString = addSize ? size + "x" + size + "_" : ""; + File folder = new File(Files.DEFAULT_FOLDER, dateTime() + "_" + sizeString + sanitize(joined) + "/"); + + //TODO: Split out into BulkPngItemStackHandler + DefaultPngItemStackHandler handler = new DefaultPngItemStackHandler(folder, size, useId, false, false); + + return new BulkRenderingRequest<>( + new ItemStackRenderer(), + new ItemStackParameters(size), + renders, + handler, + handler + ); + } + + public static IRequest animated(ItemStack stack, int size, boolean useId, boolean addSize, int length, boolean loop) { + DefaultGifItemStackHandler handler = new DefaultGifItemStackHandler(Files.DEFAULT_FOLDER, size, useId, addSize, true); + + return new AnimatedRenderingRequest<>( + new ItemStackRenderer(), + new ItemStackParameters(size), + stack, + length, + loop, + handler, + handler + ); + } + +} \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/render/item/ItemStackParameters.java b/src/main/java/com/unascribed/blockrenderer/client/render/item/ItemStackParameters.java new file mode 100644 index 0000000..7014a5e --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/render/item/ItemStackParameters.java @@ -0,0 +1,11 @@ +package com.unascribed.blockrenderer.client.render.item; + +public class ItemStackParameters { + + public final int size; + + public ItemStackParameters(int size) { + this.size = size; + } + +} \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/render/item/ItemStackRenderer.java b/src/main/java/com/unascribed/blockrenderer/client/render/item/ItemStackRenderer.java new file mode 100644 index 0000000..0d2b7f2 --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/render/item/ItemStackRenderer.java @@ -0,0 +1,121 @@ +package com.unascribed.blockrenderer.client.render.item; + +import com.unascribed.blockrenderer.client.render.IAnimatedRenderer; +import com.unascribed.blockrenderer.client.render.request.lambda.ImageHandler; +import com.unascribed.blockrenderer.client.varia.Identifiers; +import com.unascribed.blockrenderer.client.varia.Images; +import com.unascribed.blockrenderer.client.varia.Maths; +import com.unascribed.blockrenderer.client.varia.debug.Debug; +import com.unascribed.blockrenderer.client.varia.rendering.GL; +import com.unascribed.blockrenderer.client.varia.rendering.TileRenderer; +import net.minecraft.client.MainWindow; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.ItemRenderer; +import net.minecraft.item.ItemStack; +import net.minecraft.util.Util; +import org.jetbrains.annotations.Nullable; + +import java.util.function.LongSupplier; + +public class ItemStackRenderer implements IAnimatedRenderer { + + /** + * {@link ItemRenderer#renderItemIntoGUI(ItemStack, int, int)} -> renderItemModelIntoGUI uses 100F as Base Z Level + */ + private static final int BASE_Z_LEVEL = 100; + private static final float ITEM_STACK_SIZE = 16; + + private final ItemRenderer renderer = Minecraft.getInstance().getItemRenderer(); + + private float zLevel; + + @Nullable + private TileRenderer tr; + + @Override + public void setup(ItemStackParameters parameters) { + Debug.push("item/setup"); + + MainWindow window = Minecraft.getInstance().getMainWindow(); + int displayWidth = window.getFramebufferWidth(); + int displayHeight = window.getFramebufferHeight(); + + int size = Maths.minimum(displayHeight, displayWidth, parameters.size); + tr = TileRenderer.forSize(parameters.size, size); + + /* Push Stack */ + GL.pushMatrix("item/setup"); + + /* Setup Projection */ + GL.setupItemStackRendering(tr); + + /* Setup Lighting */ + GL.setupItemStackLighting(); + + /* Scale based on desired size */ + // TODO: do we need to scale / translate in z axis + float scale = parameters.size / ITEM_STACK_SIZE; + GL.scaleFixedZLevel(scale, -BASE_Z_LEVEL); + + /* Save old zLevel so we can reset it */ + zLevel = renderer.zLevel; + + /* Modify zLevel */ + renderer.zLevel = -BASE_Z_LEVEL / 2f; + + Debug.pop(); + } + + @Override + public void render(ItemStack instance, ImageHandler consumer, long nano) { + assert tr != null; + + Debug.endFrame(); + Debug.push("item/" + Identifiers.get(instance.getItem())); + + /* Clear Pixel Buffer */ + tr.clearBuffer(); + + /* Force Glint to be the same between renders by changing nano supplier */ + LongSupplier oldSupplier = Util.nanoTimeSupplier; + Util.nanoTimeSupplier = () -> nano; + + Minecraft.getInstance().textureManager.tick(); + + do { + tr.beginTile(); + GL.pushMatrix("item/render"); + + /* Clear Framebuffer */ + GL.clearFrameBuffer(); + + /* Render */ + renderer.renderItemAndEffectIntoGUI(instance, 0, 0); + + GL.popMatrix("item/render"); + } while (tr.endTile()); + + /* Reset nano supplier */ + Util.nanoTimeSupplier = oldSupplier; + + /* Pass the value and its resulting render to the consumer */ + /* Note: The rendered image needs to be flipped vertically */ + consumer.accept(instance, Images.fromTRFlipped(tr)); + + Debug.pop(); + } + + @Override + public void teardown() { + Debug.push("item/teardown"); + + /* Reset zLevel */ + renderer.zLevel = zLevel; + + /* Pop Stack */ + GL.popMatrix("item/teardown"); + + Debug.pop(); + } + +} \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/render/item/package-info.java b/src/main/java/com/unascribed/blockrenderer/client/render/item/package-info.java new file mode 100644 index 0000000..945ac4b --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/render/item/package-info.java @@ -0,0 +1,4 @@ +@NonnullDefault +package com.unascribed.blockrenderer.client.render.item; + +import org.lwjgl.system.NonnullDefault; \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/render/map/DefaultPngMapHandler.java b/src/main/java/com/unascribed/blockrenderer/client/render/map/DefaultPngMapHandler.java new file mode 100644 index 0000000..e6bd111 --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/render/map/DefaultPngMapHandler.java @@ -0,0 +1,32 @@ +package com.unascribed.blockrenderer.client.render.map; + +import com.unascribed.blockrenderer.client.render.item.DefaultPngItemStackHandler; +import com.unascribed.blockrenderer.client.render.request.lambda.ImageHandler; +import net.minecraft.item.ItemStack; +import net.minecraft.world.storage.MapData; + +import java.awt.image.BufferedImage; +import java.io.File; +import java.util.function.Consumer; + +public class DefaultPngMapHandler implements ImageHandler, Consumer { + + private final DefaultPngItemStackHandler delegate; + private final ItemStack stack; + + public DefaultPngMapHandler(ItemStack stack, File folder, int size, boolean useIdentifier, boolean addSize, boolean addDate) { + this.delegate = new DefaultPngItemStackHandler(folder, size, useIdentifier, addSize, addDate); + this.stack = stack; + } + + @Override + public void accept(MapData value) { + delegate.accept(stack); + } + + @Override + public void accept(MapData value, BufferedImage image) { + delegate.accept(stack, image); + } + +} \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/render/map/MapDecorations.java b/src/main/java/com/unascribed/blockrenderer/client/render/map/MapDecorations.java new file mode 100644 index 0000000..14a1d02 --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/render/map/MapDecorations.java @@ -0,0 +1,15 @@ +package com.unascribed.blockrenderer.client.render.map; + +import java.util.Locale; + +public enum MapDecorations { + DEFAULT, ALL, NONE; + + public String lowercaseName() { + return name().toLowerCase(Locale.ROOT); + } + + public static MapDecorations byId(int id) { + return values()[id % values().length]; + } +} \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/render/map/MapParameters.java b/src/main/java/com/unascribed/blockrenderer/client/render/map/MapParameters.java new file mode 100644 index 0000000..09579e0 --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/render/map/MapParameters.java @@ -0,0 +1,13 @@ +package com.unascribed.blockrenderer.client.render.map; + +public class MapParameters { + + public final int size; + public final MapDecorations decorations; + + public MapParameters(int size, MapDecorations decorations) { + this.size = size; + this.decorations = decorations; + } + +} \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/render/map/MapRenderer.java b/src/main/java/com/unascribed/blockrenderer/client/render/map/MapRenderer.java new file mode 100644 index 0000000..ecb4f8c --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/render/map/MapRenderer.java @@ -0,0 +1,115 @@ +package com.unascribed.blockrenderer.client.render.map; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.unascribed.blockrenderer.client.render.IRenderer; +import com.unascribed.blockrenderer.client.render.request.lambda.ImageHandler; +import com.unascribed.blockrenderer.client.varia.Images; +import com.unascribed.blockrenderer.client.varia.Maths; +import com.unascribed.blockrenderer.client.varia.debug.Debug; +import com.unascribed.blockrenderer.client.varia.rendering.GL; +import com.unascribed.blockrenderer.client.varia.rendering.TileRenderer; +import net.minecraft.client.MainWindow; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.MapItemRenderer; +import net.minecraft.client.renderer.IRenderTypeBuffer; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.util.Util; +import net.minecraft.world.storage.MapData; +import org.jetbrains.annotations.Nullable; + +import java.util.function.LongSupplier; + +public class MapRenderer implements IRenderer { + + private static final float MAP_SIZE = 128.0F; + + @Nullable + private TileRenderer tr; + private MapDecorations decorations = MapDecorations.ALL; + + @Override + public void setup(MapParameters parameters) { + Debug.push("map/setup"); + + decorations = parameters.decorations; + + MainWindow window = Minecraft.getInstance().getMainWindow(); + int displayWidth = window.getFramebufferWidth(); + int displayHeight = window.getFramebufferHeight(); + + int size = Maths.minimum(displayHeight, displayWidth, parameters.size); + tr = TileRenderer.forSize(parameters.size, size); + + /* Push Stack */ + GL.pushMatrix("map/setup"); + + /* Setup Projection */ + GL.setupMapRendering(tr); + + /* Setup Lighting */ + GL.displayLighting(); + + /* Scale based on desired size */ + float scale = parameters.size / MAP_SIZE; + GL.scale(scale, scale, decorations == MapDecorations.NONE ? 1 : -1); + + Debug.pop(); + } + + @Override + public void render(MapData instance, ImageHandler consumer) { + assert tr != null; + + Debug.endFrame(); + Debug.push("map/render"); + + /* Clear Pixel Buffer */ + tr.clearBuffer(); + + /* Force Glint to be the same between renders by changing nano supplier */ + LongSupplier oldSupplier = Util.nanoTimeSupplier; + Util.nanoTimeSupplier = () -> 0; + + Minecraft.getInstance().textureManager.tick(); + + IRenderTypeBuffer.Impl buffers = IRenderTypeBuffer.getImpl(Tessellator.getInstance().getBuffer()); + try (MapItemRenderer renderer = new MapItemRenderer(Minecraft.getInstance().textureManager)) { + renderer.updateMapTexture(instance); + + do { + tr.beginTile(); + GL.pushMatrix("map/render"); + + /* Clear Framebuffer */ + GL.clearFrameBuffer(); + + /* Render (MatrixStack, Buffers, Data, RenderBorder, LightMap) */ + renderer.renderMap(new MatrixStack(), buffers, instance, decorations != MapDecorations.ALL, 240); + + buffers.finish(); + + GL.popMatrix("map/render"); + } while (tr.endTile()); + } + + /* Reset nano supplier */ + Util.nanoTimeSupplier = oldSupplier; + + /* Pass the value and its resulting render to the consumer */ + /* Note: The rendered image needs to be flipped vertically */ + consumer.accept(instance, Images.fromTRFlipped(tr)); + + Debug.pop(); + } + + @Override + public void teardown() { + Debug.push("map/teardown"); + + /* Pop Stack */ + GL.popMatrix("map/teardown"); + + Debug.pop(); + } + +} \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/render/map/package-info.java b/src/main/java/com/unascribed/blockrenderer/client/render/map/package-info.java new file mode 100644 index 0000000..03f9a06 --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/render/map/package-info.java @@ -0,0 +1,4 @@ +@NonnullDefault +package com.unascribed.blockrenderer.client.render.map; + +import org.lwjgl.system.NonnullDefault; \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/render/package-info.java b/src/main/java/com/unascribed/blockrenderer/client/render/package-info.java new file mode 100644 index 0000000..366a2e5 --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/render/package-info.java @@ -0,0 +1,4 @@ +@NonnullDefault +package com.unascribed.blockrenderer.client.render; + +import org.lwjgl.system.NonnullDefault; \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/render/report/ProgressManager.java b/src/main/java/com/unascribed/blockrenderer/client/render/report/ProgressManager.java new file mode 100644 index 0000000..4f3a5fd --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/render/report/ProgressManager.java @@ -0,0 +1,136 @@ +package com.unascribed.blockrenderer.client.render.report; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.unascribed.blockrenderer.client.varia.debug.Debug; +import com.unascribed.blockrenderer.client.varia.logging.Log; +import com.unascribed.blockrenderer.client.varia.logging.Markers; +import com.unascribed.blockrenderer.client.varia.rendering.Display; +import com.unascribed.blockrenderer.client.varia.rendering.GL; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.StringTextComponent; +import org.apache.logging.log4j.message.MessageFormatMessage; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class ProgressManager { + + private static final int DARK_GREEN = 0xFF001100; + private static final int LIGHT_GREEN = 0xFF55FF55; + + @Nonnull + public static ITextComponent title = new StringTextComponent("Rendering"); + @Nullable + public static ITextComponent message = null; + + public static int steps = -1; + public static int step = 0; + + private static long start; + private static long last; + + public static void init(ITextComponent title, int steps) { + reset(); + + ProgressManager.title = title; + ProgressManager.steps = steps; + start = System.nanoTime(); + last = start; + } + + public static void push(@Nullable ITextComponent message) { + ProgressManager.message = message; + + step++; + + if (steps >= 0 && step > steps) Log.warn(Markers.PROGRESS, "Too many steps"); + } + + public static void pop() { + /* Log Time */ + long now = System.nanoTime(); + float time = (now - last) / 1_000_000_000F; + String subtitle = message == null ? "null" : message.getString(); + Log.debug(Markers.PROGRESS, new MessageFormatMessage("Step: {0} - {1} took {2,number,#.###}s", title.getString(), subtitle, time)); + last = now; + } + + public static void end() { + /* Log Time */ + long now = System.nanoTime(); + if (start != 0) { + float time = (now - start) / 1_000_000_000F; + String subtitle = message == null ? "null" : message.getString(); + Log.debug(Markers.PROGRESS, new MessageFormatMessage("Finished: {0} - {1} took {2,number,#.###}s", title.getString(), subtitle, time)); + } + + reset(); + } + + public static void reset() { + title = new StringTextComponent("Rendering"); + message = null; + steps = -1; + step = 0; + start = 0; + } + + public static ITextComponent getProgress() { + //TODO: Rendered, Total, Remaining + Elapsed Time + if (steps > 0) return new StringTextComponent(String.format("%s / %s", step + 1, steps)); + + return new StringTextComponent(String.format("%s", step)); + } + + public static void render() { + Debug.endFrame(); + Debug.push("progress-bar"); + + GL.unbindFBO(); + + GL.pushMatrix("progress/main"); + + int displayWidth = GL.window.getScaledWidth(); + int displayHeight = GL.window.getScaledHeight(); + GL.setupOverlayRendering(); + + // Draw the dirt background + Display.drawDirtBackground(displayWidth, displayHeight); + + // ...and the title + Display.drawCenteredString(new MatrixStack(), ProgressManager.title, displayWidth / 2, displayHeight / 2 - 24, -1); + + // ...and the progress bar + renderProgressBar(displayWidth, displayHeight); + + if (message != null) { + GL.pushMatrix("progress/message"); + + GL.scale(0.5f, 0.5f, 1); + + // ...and the subtitle + Display.drawCenteredString(new MatrixStack(), message, displayWidth, displayHeight - 20, -1); + + GL.popMatrix("progress/message"); + } + + GL.popMatrix("progress/main"); + + GL.flipFrame(); + GL.rebindFBO(); + + Debug.pop(); + } + + private static void renderProgressBar(int displayWidth, int displayHeight) { + int progress = steps > 0 ? MathHelper.clamp(100 * step / steps, 0, 100) : 100; + + int hw = displayWidth / 2; + int hh = displayHeight / 2; + + Display.drawRect(new MatrixStack(), hw - 50, hh - 1, hw + 50, hh + 1, DARK_GREEN); + Display.drawRect(new MatrixStack(), hw - 50, hh - 1, hw - 50 + progress, hh + 1, LIGHT_GREEN); + } + +} \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/render/report/package-info.java b/src/main/java/com/unascribed/blockrenderer/client/render/report/package-info.java new file mode 100644 index 0000000..d73723d --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/render/report/package-info.java @@ -0,0 +1,4 @@ +@NonnullDefault +package com.unascribed.blockrenderer.client.render.report; + +import org.lwjgl.system.NonnullDefault; \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/render/request/AnimatedRenderingRequest.java b/src/main/java/com/unascribed/blockrenderer/client/render/request/AnimatedRenderingRequest.java new file mode 100644 index 0000000..86df13f --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/render/request/AnimatedRenderingRequest.java @@ -0,0 +1,46 @@ +package com.unascribed.blockrenderer.client.render.request; + +import com.unascribed.blockrenderer.client.render.IAnimatedRenderer; +import com.unascribed.blockrenderer.client.render.IRequest; +import com.unascribed.blockrenderer.client.render.RenderManager; + +import javax.imageio.stream.ImageOutputStream; +import java.util.function.Consumer; +import java.util.function.Function; + +public class AnimatedRenderingRequest implements IRequest { + + private final IAnimatedRenderer renderer; + private final S parameters; + private final T value; + private final Function provider; + private final Consumer callback; + private final int length; + private final boolean loop; + + public AnimatedRenderingRequest(IAnimatedRenderer renderer, + S parameters, + T value, + int length, + boolean loop, + Function provider, + Consumer callback) { + this.renderer = renderer; + this.parameters = parameters; + this.value = value; + this.length = length; + this.loop = loop; + this.provider = provider; + this.callback = callback; + } + + /** + * @return true when rendering has been completed + */ + @Override + public boolean render() { + RenderManager.animated(renderer, provider, callback, parameters, length, loop, value); + return true; + } + +} \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/render/request/BulkRenderingRequest.java b/src/main/java/com/unascribed/blockrenderer/client/render/request/BulkRenderingRequest.java new file mode 100644 index 0000000..c2ce18a --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/render/request/BulkRenderingRequest.java @@ -0,0 +1,41 @@ +package com.unascribed.blockrenderer.client.render.request; + +import com.unascribed.blockrenderer.client.render.IRenderer; +import com.unascribed.blockrenderer.client.render.IRequest; +import com.unascribed.blockrenderer.client.render.RenderManager; +import com.unascribed.blockrenderer.client.render.request.lambda.ImageHandler; + +import java.util.Collection; + +public class BulkRenderingRequest implements IRequest { + + private final IRenderer renderer; + private final S parameters; + private final Collection values; + private final ImageHandler handler; + private final Runnable callback; + + public BulkRenderingRequest(IRenderer renderer, + S parameters, + Collection values, + ImageHandler handler, + Runnable callback) { + this.renderer = renderer; + this.parameters = parameters; + this.values = values; + this.handler = handler; + this.callback = callback; + } + + /** + * @return true when rendering has been completed + */ + @Override + public boolean render() { + RenderManager.bulk(renderer, handler, parameters, values); + callback.run(); + + return true; + } + +} \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/render/request/RenderingRequest.java b/src/main/java/com/unascribed/blockrenderer/client/render/request/RenderingRequest.java new file mode 100644 index 0000000..2e1df1b --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/render/request/RenderingRequest.java @@ -0,0 +1,40 @@ +package com.unascribed.blockrenderer.client.render.request; + +import com.unascribed.blockrenderer.client.render.IRenderer; +import com.unascribed.blockrenderer.client.render.IRequest; +import com.unascribed.blockrenderer.client.render.RenderManager; +import com.unascribed.blockrenderer.client.render.request.lambda.ImageHandler; + +import java.util.function.Consumer; + +public class RenderingRequest implements IRequest { + + private final IRenderer renderer; + private final S parameters; + private final T value; + private final ImageHandler handler; + private final Consumer callback; + + public RenderingRequest(IRenderer renderer, + S parameters, + T value, + ImageHandler handler, + Consumer callback) { + this.renderer = renderer; + this.parameters = parameters; + this.value = value; + this.handler = handler; + this.callback = callback; + } + + /** + * @return true when rendering has been completed + */ + @Override + public boolean render() { + RenderManager.render(renderer, handler, parameters, value, callback); + + return true; + } + +} \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/render/request/lambda/ImageHandler.java b/src/main/java/com/unascribed/blockrenderer/client/render/request/lambda/ImageHandler.java new file mode 100644 index 0000000..6d58e1a --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/render/request/lambda/ImageHandler.java @@ -0,0 +1,21 @@ +package com.unascribed.blockrenderer.client.render.request.lambda; + +import org.jetbrains.annotations.NotNull; + +import java.awt.image.BufferedImage; +import java.util.Objects; +import java.util.function.BiConsumer; + +@FunctionalInterface +public interface ImageHandler extends BiConsumer { + + @NotNull + default ImageHandler andThen(@NotNull ImageHandler after) { + Objects.requireNonNull(after); + + return (l, r) -> { + accept(l, r); + after.accept(l, r); + }; + } +} \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/render/request/lambda/package-info.java b/src/main/java/com/unascribed/blockrenderer/client/render/request/lambda/package-info.java new file mode 100644 index 0000000..9a82cf9 --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/render/request/lambda/package-info.java @@ -0,0 +1,4 @@ +@NonnullDefault +package com.unascribed.blockrenderer.client.render.request.lambda; + +import org.lwjgl.system.NonnullDefault; \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/render/request/package-info.java b/src/main/java/com/unascribed/blockrenderer/client/render/request/package-info.java new file mode 100644 index 0000000..f611901 --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/render/request/package-info.java @@ -0,0 +1,4 @@ +@NonnullDefault +package com.unascribed.blockrenderer.client.render.request; + +import org.lwjgl.system.NonnullDefault; \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/screens/BaseScreen.java b/src/main/java/com/unascribed/blockrenderer/client/screens/BaseScreen.java new file mode 100644 index 0000000..8fc23ac --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/screens/BaseScreen.java @@ -0,0 +1,123 @@ +package com.unascribed.blockrenderer.client.screens; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.unascribed.blockrenderer.client.screens.widgets.UpdateableSliderWidget; +import com.unascribed.blockrenderer.client.screens.widgets.options.ExtendedSliderPercentageOption; +import com.unascribed.blockrenderer.client.varia.Maths; +import net.minecraft.client.GameSettings; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.widget.Widget; +import net.minecraft.client.gui.widget.button.Button; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TranslationTextComponent; +import org.jetbrains.annotations.Nullable; +import org.lwjgl.glfw.GLFW; + +@SuppressWarnings("NotNullFieldNotInitialized") +public abstract class BaseScreen extends Screen { + + public static final int MIN_SIZE = 16; + public static final int THRESHOLD = 32; + public static final int MAX_SIZE = 2048; + + @Nullable + protected final Screen old; + + protected double size = 512; + protected UpdateableSliderWidget slider; + protected Button renderButton; + + public BaseScreen(ITextComponent title, @Nullable Screen old) { + super(title); + this.old = old; + } + + @Override + protected void init() { + assert minecraft != null; + boolean enabled = enabled(); + addButton(new Button(width / 2 - 100, height / 6 + 120, 98, 20, new TranslationTextComponent("gui.cancel"), button -> minecraft.displayGuiScreen(old))); + + renderButton = addButton(new Button(width / 2 + 2, height / 6 + 120, 98, 20, new TranslationTextComponent("block_renderer.gui.render"), this::onRender), enabled); + + size = MathHelper.clamp(size, getMinSize(), getMaxSize()); + + ExtendedSliderPercentageOption option = new ExtendedSliderPercentageOption("block_renderer.gui.renderSize", getMinSize(), getMaxSize(), 1, (settings) -> size, (settings, value) -> size = round(value), this::getSliderDisplay); + slider = addButton(new UpdateableSliderWidget(minecraft.gameSettings, width / 2 - 100, height / 6 + 80, 200, 20, option), enabled); + } + + protected boolean enabled() { + assert minecraft != null; + return minecraft.world != null; + } + + protected int getMinSize() { + return MIN_SIZE; + } + + protected int getThreshold() { + return THRESHOLD; + } + + protected int getMaxSize() { + return MAX_SIZE; + } + + protected int round(double value) { + return Maths.roundAndClamp(value, getMinSize(), getMaxSize(), getThreshold()); + } + + @Override + public boolean keyPressed(int keyCode, int scanCode, int modifiers) { + if (keyCode == GLFW.GLFW_KEY_ENTER && renderButton.visible) { + onRender(renderButton); + return true; + } + + return super.keyPressed(keyCode, scanCode, modifiers); + } + + @Override + public void render(MatrixStack stack, int mouseX, int mouseY, float partialTicks) { + assert minecraft != null; + + renderBackground(stack); + + super.render(stack, mouseX, mouseY, partialTicks); + + drawCenteredString(stack, minecraft.fontRenderer, title, width / 2, height / 6, -1); + + for (Widget widget : buttons) + if (widget.isHovered()) + widget.renderToolTip(stack, mouseX, mouseY); + + if (minecraft.world != null) return; + + drawCenteredString(stack, minecraft.fontRenderer, new TranslationTextComponent("block_renderer.gui.noWorld"), width / 2, height / 6 + 30, 0xFF5555); + } + + protected abstract void onRender(Button button); + + public ITextComponent getSliderDisplay(GameSettings settings, ExtendedSliderPercentageOption option) { + int px = round(size); + return option.getDisplayPrefix().copyRaw().appendString(": " + px + "x" + px); + } + + protected T addButton(T button, boolean active) { + addButton(button); + + button.active = active; + button.visible = active; + + return button; + } + + @Override + public void closeScreen() { + assert minecraft != null; + + minecraft.displayGuiScreen(old); + } + +} \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/screens/SelectionScreen.java b/src/main/java/com/unascribed/blockrenderer/client/screens/SelectionScreen.java new file mode 100644 index 0000000..7593122 --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/screens/SelectionScreen.java @@ -0,0 +1,96 @@ +package com.unascribed.blockrenderer.client.screens; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.unascribed.blockrenderer.client.screens.item.EnterNamespaceScreen; +import com.unascribed.blockrenderer.client.screens.item.RenderAnimatedScreen; +import com.unascribed.blockrenderer.client.screens.map.RenderMapScreen; +import com.unascribed.blockrenderer.client.screens.widgets.ItemButtonWidget; +import com.unascribed.blockrenderer.client.varia.Registries; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.text.TranslationTextComponent; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; + +public class SelectionScreen extends Screen { + + private static final TranslationTextComponent TITLE = new TranslationTextComponent("block_renderer.gui.choose"); + + @Nullable + private final Screen old; + + @Nullable + private final ItemStack stack; + + public SelectionScreen(@Nullable Screen old, @Nullable ItemStack stack) { + super(TITLE); + this.old = old; + this.stack = stack; + } + + @Override + protected void init() { + assert minecraft != null; + + addButton(new ItemButtonWidget( + this, + itemRenderer, + Registries.MAP.lazyMap(Item::getDefaultInstance), + width / 2 - 64 - 12, + height / 2, + new TranslationTextComponent("block_renderer.gui.choose.map"), + new TranslationTextComponent("block_renderer.gui.choose.map.tooltip"), + button -> { + assert stack != null; + minecraft.displayGuiScreen(new RenderMapScreen(old, stack)); + } + )).active = stack != null && Objects.equals(stack.getItem().getRegistryName(), new ResourceLocation("minecraft:filled_map")); + + addButton(new ItemButtonWidget( + this, + itemRenderer, + Registries.DISPENSER.lazyMap(Item::getDefaultInstance), + width / 2, + height / 2, + new TranslationTextComponent("block_renderer.gui.choose.item"), + new TranslationTextComponent("block_renderer.gui.choose.item.tooltip"), + button -> minecraft.displayGuiScreen(new EnterNamespaceScreen(old, stack)) + )); + + addButton(new ItemButtonWidget( + this, + itemRenderer, + Registries.CUTTER.lazyMap(Item::getDefaultInstance), + width / 2 + 64 + 12, + height / 2, + new TranslationTextComponent("block_renderer.gui.choose.animated"), + new TranslationTextComponent("block_renderer.gui.choose.animated.tooltip"), + button -> { + assert stack != null; + minecraft.displayGuiScreen(new RenderAnimatedScreen(old, stack)); + } + )).active = stack != null; + } + + @Override + public void render(MatrixStack stack, int mouseX, int mouseY, float partialTicks) { + assert minecraft != null; + + renderBackground(stack); + + super.render(stack, mouseX, mouseY, partialTicks); + + drawCenteredString(stack, minecraft.fontRenderer, title, width / 2, height / 6, -1); + } + + @Override + public void closeScreen() { + assert minecraft != null; + + minecraft.displayGuiScreen(old); + } + +} \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/screens/item/BaseItemScreen.java b/src/main/java/com/unascribed/blockrenderer/client/screens/item/BaseItemScreen.java new file mode 100644 index 0000000..787f7bb --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/screens/item/BaseItemScreen.java @@ -0,0 +1,38 @@ +package com.unascribed.blockrenderer.client.screens.item; + +import com.unascribed.blockrenderer.client.screens.BaseScreen; +import com.unascribed.blockrenderer.client.screens.widgets.HoverableCheckboxWidget; +import com.unascribed.blockrenderer.client.screens.widgets.HoverableTinyButtonWidget; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.widget.button.Button; +import net.minecraft.client.gui.widget.button.CheckboxButton; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TranslationTextComponent; +import org.jetbrains.annotations.Nullable; + +/* + * Note: Screen's get initialized in init + */ +@SuppressWarnings("NotNullFieldNotInitialized") +public abstract class BaseItemScreen extends BaseScreen { + + protected Button actualSize; + protected CheckboxButton useId; + protected CheckboxButton addSize; + + public BaseItemScreen(ITextComponent title, @Nullable Screen old) { + super(title, old); + } + + @Override + public void init() { + assert minecraft != null; + boolean enabled = enabled(); + + super.init(); + + actualSize = addButton(new HoverableTinyButtonWidget(this, width / 2 + 104, height / 6 + 80, new TranslationTextComponent("block_renderer.gui.actualSize"), new TranslationTextComponent("block_renderer.gui.actualSize.tooltip"), button -> slider.update((int) minecraft.getMainWindow().getGuiScaleFactor() * 16)), enabled); + useId = addButton(new HoverableCheckboxWidget(this, width / 2 - 100, height / 6 + 144, 98, 20, new TranslationTextComponent("block_renderer.gui.useId"), new TranslationTextComponent("block_renderer.gui.useId.tooltip"), false), enabled); + addSize = addButton(new HoverableCheckboxWidget(this, width / 2 + 2, height / 6 + 144, 98, 20, new TranslationTextComponent("block_renderer.gui.addSize"), new TranslationTextComponent("block_renderer.gui.addSize.tooltip"), false), enabled); + } +} \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/screens/item/EnterNamespaceScreen.java b/src/main/java/com/unascribed/blockrenderer/client/screens/item/EnterNamespaceScreen.java new file mode 100644 index 0000000..422533c --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/screens/item/EnterNamespaceScreen.java @@ -0,0 +1,124 @@ +package com.unascribed.blockrenderer.client.screens.item; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.unascribed.blockrenderer.client.render.RenderManager; +import com.unascribed.blockrenderer.client.render.item.ItemRenderer; +import com.unascribed.blockrenderer.client.screens.widgets.HoverableTinyButtonWidget; +import com.unascribed.blockrenderer.client.varia.StringUtils; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.widget.TextFieldWidget; +import net.minecraft.client.gui.widget.button.Button; +import net.minecraft.item.ItemStack; +import net.minecraft.util.text.TranslationTextComponent; +import org.jetbrains.annotations.Nullable; + +/* + * Note: Screen's get initialized in init + */ +@SuppressWarnings("NotNullFieldNotInitialized") +public class EnterNamespaceScreen extends BaseItemScreen { + + private static final TranslationTextComponent TITLE = new TranslationTextComponent("block_renderer.gui.namespace"); + + private boolean emptySpec = false; + + private final String prefill; + + private TextFieldWidget text; + + private final @Nullable ItemStack stack; + + public EnterNamespaceScreen(@Nullable Screen old, String prefill) { + super(TITLE, old); + this.prefill = prefill; + this.stack = null; + } + + public EnterNamespaceScreen(@Nullable Screen old, @Nullable ItemStack stack) { + super(TITLE, old); + this.prefill = StringUtils.getNamespace(stack); + this.stack = stack; + } + + @Override + public void init() { + assert minecraft != null; + minecraft.keyboardListener.enableRepeatEvents(true); + + boolean enabled = enabled(); + + /* Note: This is the initializer, text can be null! */ + @SuppressWarnings("ConstantConditions") + String oldText = (text == null ? prefill : text.getText()); + + text = addButton(new TextFieldWidget(minecraft.fontRenderer, width / 2 - 100, height / 6 + 50, 200, 20, new TranslationTextComponent("block_renderer.gui.namespace")), enabled); + text.setResponder((value) -> emptySpec = value.trim().isEmpty()); + text.setText(oldText); + text.setCanLoseFocus(false); + setFocusedDefault(text); + + if (stack != null) { + addButton(new HoverableTinyButtonWidget( + this, + width - 32, + height - 32, + new TranslationTextComponent("block_renderer.gui.switch.single"), + new TranslationTextComponent("block_renderer.gui.switch.single.tooltip"), + button -> minecraft.displayGuiScreen(new EnterSizeScreen(old, stack))) + ); + } + + super.init(); + + renderButton.visible = !emptySpec; + } + + @Override + public void tick() { + super.tick(); + text.tick(); + renderButton.visible = !emptySpec; + } + + @Override + public void onClose() { + assert minecraft != null; + minecraft.keyboardListener.enableRepeatEvents(false); + } + + @Override + public boolean keyPressed(int keyCode, int scanCode, int modifiers) { + if (text.keyPressed(keyCode, scanCode, modifiers)) return true; + return super.keyPressed(keyCode, scanCode, modifiers); + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + if (text.mouseClicked(mouseX, mouseY, button)) return true; + + return super.mouseClicked(mouseX, mouseY, button); + } + + @Override + public void render(MatrixStack stack, int mouseX, int mouseY, float partialTicks) { + assert minecraft != null; + + super.render(stack, mouseX, mouseY, partialTicks); + + if (!emptySpec) return; + + drawCenteredString(stack, minecraft.fontRenderer, new TranslationTextComponent("block_renderer.gui.emptySpec"), width / 2, height / 6 + 30, 0xFF5555); + } + + @Override + public void onRender(Button button) { + assert minecraft != null; + + if (!renderButton.visible) return; + + minecraft.displayGuiScreen(old); + if (minecraft.world == null) return; + + RenderManager.push(ItemRenderer.bulk(text.getText(), round(size), useId.isChecked(), addSize.isChecked())); + } +} \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/screens/item/EnterSizeScreen.java b/src/main/java/com/unascribed/blockrenderer/client/screens/item/EnterSizeScreen.java new file mode 100644 index 0000000..71dc93e --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/screens/item/EnterSizeScreen.java @@ -0,0 +1,60 @@ +package com.unascribed.blockrenderer.client.screens.item; + +import com.unascribed.blockrenderer.client.render.RenderManager; +import com.unascribed.blockrenderer.client.render.item.ItemRenderer; +import com.unascribed.blockrenderer.client.screens.widgets.HoverableTinyButtonWidget; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.widget.button.Button; +import net.minecraft.item.ItemStack; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TranslationTextComponent; +import org.jetbrains.annotations.Nullable; + +public class EnterSizeScreen extends BaseItemScreen { + + private static final TranslationTextComponent TITLE = new TranslationTextComponent("block_renderer.gui.renderItem"); + + protected final ItemStack stack; + private final boolean enableSwitch; + + public EnterSizeScreen(@Nullable Screen old, ItemStack stack) { + this(TITLE, old, stack, true); + } + + public EnterSizeScreen(ITextComponent title, @Nullable Screen old, ItemStack stack, boolean enableSwitch) { + super(title, old); + this.stack = stack; + this.enableSwitch = enableSwitch; + } + + @Override + public void init() { + assert minecraft != null; + + super.init(); + + slider.y = height / 6 + 50; + actualSize.y = height / 6 + 50; + actualSize.visible = enableSwitch; + + addButton(new HoverableTinyButtonWidget( + this, + width - 32, + height - 32, + new TranslationTextComponent("block_renderer.gui.switch.bulk"), + new TranslationTextComponent("block_renderer.gui.switch.bulk.tooltip"), + button -> minecraft.displayGuiScreen(new EnterNamespaceScreen(old, stack))), + enableSwitch + ); + } + + @Override + public void onRender(Button button) { + assert minecraft != null; + + minecraft.displayGuiScreen(old); + if (minecraft.world == null) return; + + RenderManager.push(ItemRenderer.single(stack, round(size), useId.isChecked(), addSize.isChecked())); + } +} \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/screens/item/RenderAnimatedScreen.java b/src/main/java/com/unascribed/blockrenderer/client/screens/item/RenderAnimatedScreen.java new file mode 100644 index 0000000..cc9a8ca --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/screens/item/RenderAnimatedScreen.java @@ -0,0 +1,94 @@ +package com.unascribed.blockrenderer.client.screens.item; + +import com.unascribed.blockrenderer.client.render.RenderManager; +import com.unascribed.blockrenderer.client.render.item.ItemRenderer; +import com.unascribed.blockrenderer.client.screens.widgets.HoverableCheckboxWidget; +import com.unascribed.blockrenderer.client.screens.widgets.HoverableTextFieldWidget; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.widget.TextFieldWidget; +import net.minecraft.client.gui.widget.button.Button; +import net.minecraft.client.gui.widget.button.CheckboxButton; +import net.minecraft.item.ItemStack; +import net.minecraft.util.text.TranslationTextComponent; +import org.jetbrains.annotations.Nullable; + +@SuppressWarnings("NotNullFieldNotInitialized") +public class RenderAnimatedScreen extends EnterSizeScreen { + + private static final TranslationTextComponent TITLE = new TranslationTextComponent("block_renderer.gui.renderAnimated"); + + private CheckboxButton autoLoop; + + private TextFieldWidget length; + + private boolean isInteger; + + public RenderAnimatedScreen(@Nullable Screen old, ItemStack stack) { + super(TITLE, old, stack, false); + } + + @Override + public void init() { + assert minecraft != null; + minecraft.keyboardListener.enableRepeatEvents(true); + boolean enabled = enabled(); + + super.init(); + + autoLoop = addButton(new HoverableCheckboxWidget(this, width / 2 + 2, height / 6 + 166, 98, 20, new TranslationTextComponent("block_renderer.gui.loop"), new TranslationTextComponent("block_renderer.gui.loop.tooltip"), false), enabled); + + /* Note: This is the initializer, text can be null! */ + @SuppressWarnings("ConstantConditions") + String prefill = (length == null ? "20" : length.getText()); + + length = addButton(new HoverableTextFieldWidget(this, minecraft.fontRenderer, width / 2 - 100, height / 6 + 74, 200, 20, new TranslationTextComponent("block_renderer.gui.animatedLength"), new TranslationTextComponent("block_renderer.gui.animatedLength.tooltip")), enabled); + length.setResponder((value) -> { + isInteger = false; + try { + int v = Integer.parseInt(value); + if (v > 0) isInteger = true; + } catch (NumberFormatException ignore) { + } + }); + length.setText(prefill); + length.setCanLoseFocus(false); + setFocusedDefault(length); + } + + @Override + public void tick() { + super.tick(); + length.tick(); + renderButton.visible = isInteger; + } + + @Override + public void onClose() { + assert minecraft != null; + minecraft.keyboardListener.enableRepeatEvents(false); + } + + @Override + public boolean keyPressed(int keyCode, int scanCode, int modifiers) { + if (length.keyPressed(keyCode, scanCode, modifiers)) return true; + return super.keyPressed(keyCode, scanCode, modifiers); + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + if (length.mouseClicked(mouseX, mouseY, button)) return true; + + return super.mouseClicked(mouseX, mouseY, button); + } + + @Override + public void onRender(Button button) { + assert minecraft != null; + + minecraft.displayGuiScreen(old); + if (minecraft.world == null) return; + + RenderManager.push(ItemRenderer.animated(stack, round(size), useId.isChecked(), addSize.isChecked(), Integer.parseInt(length.getText()), autoLoop.isChecked())); + } + +} \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/screens/item/package-info.java b/src/main/java/com/unascribed/blockrenderer/client/screens/item/package-info.java new file mode 100644 index 0000000..3fbbc4f --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/screens/item/package-info.java @@ -0,0 +1,4 @@ +@NonnullDefault +package com.unascribed.blockrenderer.client.screens.item; + +import org.lwjgl.system.NonnullDefault; \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/screens/map/RenderMapScreen.java b/src/main/java/com/unascribed/blockrenderer/client/screens/map/RenderMapScreen.java new file mode 100644 index 0000000..3bfdb3d --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/screens/map/RenderMapScreen.java @@ -0,0 +1,81 @@ +package com.unascribed.blockrenderer.client.screens.map; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.unascribed.blockrenderer.client.render.RenderManager; +import com.unascribed.blockrenderer.client.render.item.ItemRenderer; +import com.unascribed.blockrenderer.client.render.map.MapDecorations; +import com.unascribed.blockrenderer.client.screens.item.EnterSizeScreen; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.widget.button.Button; +import net.minecraft.item.FilledMapItem; +import net.minecraft.item.ItemStack; +import net.minecraft.util.text.TranslationTextComponent; +import net.minecraft.world.storage.MapData; +import org.jetbrains.annotations.Nullable; + +@SuppressWarnings("NotNullFieldNotInitialized") +public class RenderMapScreen extends EnterSizeScreen { + + private static final TranslationTextComponent TITLE = new TranslationTextComponent("block_renderer.gui.map"); + + @Nullable + private final MapData data; + protected Button decorationsButton; + protected MapDecorations decorations = MapDecorations.DEFAULT; + + public RenderMapScreen(@Nullable Screen old, ItemStack stack) { + super(TITLE, old, stack, false); + + minecraft = Minecraft.getInstance(); + data = minecraft.world != null ? FilledMapItem.getMapData(stack, minecraft.world) : null; + } + + @Override + public void init() { + super.init(); + + decorationsButton = addButton(new Button(width / 2 - 100, height / 6 + 96, 200, 20, new TranslationTextComponent("block_renderer.gui.map.decorations." + decorations.lowercaseName()), this::toggleDecorations), enabled()); + } + + private void toggleDecorations(Button button) { + decorations = MapDecorations.byId(decorations.ordinal() + 1); + decorationsButton.setMessage( + new TranslationTextComponent("block_renderer.gui.map.decorations." + decorations.lowercaseName()) + ); + } + + @Override + protected boolean enabled() { + return super.enabled() && data != null; + } + + @Override + protected int getMinSize() { + return 128; + } + + @Override + public void render(MatrixStack stack, int mouseX, int mouseY, float partialTicks) { + assert minecraft != null; + + super.render(stack, mouseX, mouseY, partialTicks); + + if (minecraft.world == null) return; + if (data != null) return; + + drawCenteredString(stack, minecraft.fontRenderer, new TranslationTextComponent("block_renderer.gui.noMapData"), width / 2, height / 6 + 30, 0xFF5555); + } + + @Override + public void onRender(Button button) { + assert minecraft != null; + + minecraft.displayGuiScreen(old); + if (minecraft.world == null) return; + if (data == null) return; + + //TODO: Map Background Image? "textures/map/map_background.png" + RenderManager.push(ItemRenderer.single(stack, data, round(size), useId.isChecked(), addSize.isChecked(), decorations)); + } +} \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/screens/map/package-info.java b/src/main/java/com/unascribed/blockrenderer/client/screens/map/package-info.java new file mode 100644 index 0000000..bd2c86f --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/screens/map/package-info.java @@ -0,0 +1,4 @@ +@NonnullDefault +package com.unascribed.blockrenderer.client.screens.map; + +import org.lwjgl.system.NonnullDefault; \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/screens/package-info.java b/src/main/java/com/unascribed/blockrenderer/client/screens/package-info.java new file mode 100644 index 0000000..69c9a24 --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/screens/package-info.java @@ -0,0 +1,4 @@ +@NonnullDefault +package com.unascribed.blockrenderer.client.screens; + +import org.lwjgl.system.NonnullDefault; \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/screens/widgets/HoverableCheckboxWidget.java b/src/main/java/com/unascribed/blockrenderer/client/screens/widgets/HoverableCheckboxWidget.java similarity index 83% rename from src/main/java/com/unascribed/blockrenderer/screens/widgets/HoverableCheckboxWidget.java rename to src/main/java/com/unascribed/blockrenderer/client/screens/widgets/HoverableCheckboxWidget.java index aa095db..5d2de47 100644 --- a/src/main/java/com/unascribed/blockrenderer/screens/widgets/HoverableCheckboxWidget.java +++ b/src/main/java/com/unascribed/blockrenderer/client/screens/widgets/HoverableCheckboxWidget.java @@ -1,7 +1,7 @@ -package com.unascribed.blockrenderer.screens.widgets; +package com.unascribed.blockrenderer.client.screens.widgets; import com.mojang.blaze3d.matrix.MatrixStack; -import com.unascribed.blockrenderer.utils.Rendering; +import com.unascribed.blockrenderer.client.varia.rendering.Display; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.widget.button.CheckboxButton; import net.minecraft.util.text.ITextComponent; @@ -27,7 +27,7 @@ public HoverableCheckboxWidget(Screen owner, int i, int j, int k, int l, ITextCo @Override public void renderToolTip(MatrixStack stack, int mouseX, int mouseY) { - Rendering.drawHoveringText(owner, stack, tooltip.get(), mouseX, mouseY); + Display.renderTooltip(owner, stack, tooltip.get(), mouseX, mouseY); } } diff --git a/src/main/java/com/unascribed/blockrenderer/client/screens/widgets/HoverableTextFieldWidget.java b/src/main/java/com/unascribed/blockrenderer/client/screens/widgets/HoverableTextFieldWidget.java new file mode 100644 index 0000000..082b6ac --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/screens/widgets/HoverableTextFieldWidget.java @@ -0,0 +1,34 @@ +package com.unascribed.blockrenderer.client.screens.widgets; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.unascribed.blockrenderer.client.varia.rendering.Display; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.widget.TextFieldWidget; +import net.minecraft.util.text.ITextComponent; + +import java.util.Collections; +import java.util.List; +import java.util.function.Supplier; + +public class HoverableTextFieldWidget extends TextFieldWidget { + + private final Screen owner; + private final Supplier> tooltip; + + public HoverableTextFieldWidget(Screen owner, FontRenderer font, int x, int y, int w, int h, ITextComponent title, ITextComponent tooltip) { + this(owner, font, x, y, w, h, title, () -> Collections.singletonList(tooltip)); + } + + public HoverableTextFieldWidget(Screen owner, FontRenderer font, int x, int y, int w, int h, ITextComponent title, Supplier> tooltip) { + super(font, x, y, w, h, title); + this.owner = owner; + this.tooltip = tooltip; + } + + @Override + public void renderToolTip(MatrixStack stack, int mouseX, int mouseY) { + if (isMouseOver(mouseX, mouseY)) + Display.renderTooltip(owner, stack, tooltip.get(), mouseX, mouseY); + } +} \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/screens/widgets/HoverableTinyButtonWidget.java b/src/main/java/com/unascribed/blockrenderer/client/screens/widgets/HoverableTinyButtonWidget.java similarity index 74% rename from src/main/java/com/unascribed/blockrenderer/screens/widgets/HoverableTinyButtonWidget.java rename to src/main/java/com/unascribed/blockrenderer/client/screens/widgets/HoverableTinyButtonWidget.java index d7a8094..00ff7f7 100644 --- a/src/main/java/com/unascribed/blockrenderer/screens/widgets/HoverableTinyButtonWidget.java +++ b/src/main/java/com/unascribed/blockrenderer/client/screens/widgets/HoverableTinyButtonWidget.java @@ -1,9 +1,9 @@ -package com.unascribed.blockrenderer.screens.widgets; +package com.unascribed.blockrenderer.client.screens.widgets; import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.platform.GlStateManager; -import com.mojang.blaze3d.systems.RenderSystem; -import com.unascribed.blockrenderer.utils.Rendering; +import com.unascribed.blockrenderer.client.varia.rendering.Display; +import com.unascribed.blockrenderer.client.varia.rendering.GL; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.widget.button.Button; @@ -23,7 +23,7 @@ public HoverableTinyButtonWidget(Screen owner, int x, int y, ITextComponent mess } public HoverableTinyButtonWidget(Screen owner, int x, int y, ITextComponent message, Supplier> tooltip, IPressable onPress) { - super(x, y, 20, 20, message, onPress); + super(x, y, 20, 20, message, onPress); this.tooltip = tooltip; this.owner = owner; } @@ -34,10 +34,9 @@ public void renderButton(MatrixStack stack, int mouseX, int mouseY, float partia Minecraft minecraft = Minecraft.getInstance(); minecraft.getTextureManager().bindTexture(WIDGETS_LOCATION); - RenderSystem.color4f(1.0F, 1.0F, 1.0F, alpha); - RenderSystem.enableBlend(); - RenderSystem.defaultBlendFunc(); - RenderSystem.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA); + GL.color(1.0F, 1.0F, 1.0F, alpha); + GL.enableDefaultBlend(); + GL.blendFunction(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA); blit(stack, x, y, 0, 46 + i * 20, width / 2, height); blit(stack, x + width / 2, y, 200 - width / 2, 46 + i * 20, width / 2, height); @@ -47,7 +46,7 @@ public void renderButton(MatrixStack stack, int mouseX, int mouseY, float partia @Override public void renderToolTip(MatrixStack stack, int mouseX, int mouseY) { - Rendering.drawHoveringText(owner, stack, tooltip.get(), mouseX, mouseY); + Display.renderTooltip(owner, stack, tooltip.get(), mouseX, mouseY); } } diff --git a/src/main/java/com/unascribed/blockrenderer/client/screens/widgets/ItemButtonWidget.java b/src/main/java/com/unascribed/blockrenderer/client/screens/widgets/ItemButtonWidget.java new file mode 100644 index 0000000..d509efe --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/screens/widgets/ItemButtonWidget.java @@ -0,0 +1,91 @@ +package com.unascribed.blockrenderer.client.screens.widgets; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.unascribed.blockrenderer.client.varia.Registries; +import com.unascribed.blockrenderer.client.varia.rendering.Display; +import com.unascribed.blockrenderer.client.varia.rendering.GL; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.widget.button.Button; +import net.minecraft.client.renderer.ItemRenderer; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.text.ITextComponent; + +import java.util.Collections; +import java.util.List; +import java.util.function.Supplier; + +public class ItemButtonWidget extends Button { + + public static final ResourceLocation CUSTOM_WIDGETS = new ResourceLocation("block_renderer:textures/gui/widgets.png"); + + private final Screen owner; + private final Supplier> tooltip; + private final ItemRenderer renderer; + private final Supplier stack; + private final boolean isMap; + + public ItemButtonWidget(Screen owner, ItemRenderer renderer, Supplier stack, int x, int y, ITextComponent message, ITextComponent tooltip, IPressable onPress) { + this(owner, renderer, stack, x, y, message, () -> Collections.singletonList(tooltip), onPress); + } + + public ItemButtonWidget(Screen owner, ItemRenderer renderer, Supplier stack, int x, int y, ITextComponent message, Supplier> tooltip, IPressable onPress) { + super(x - 32, y - 32, 64, 64, message, onPress); + this.tooltip = tooltip; + this.owner = owner; + this.renderer = renderer; + this.stack = stack; + this.isMap = stack.get().getItem() == Registries.MAP.get(); + } + + @Override + public void renderButton(MatrixStack matrix, int mouseX, int mouseY, float partialTicks) { + + if (isHovered() && active) + Display.drawRect(matrix, x, y, x + width, y + height, 0x33FFFFFF); + + renderItemStack(stack.get(), x, y, 4.0f); + + if (isHovered()) + renderToolTip(matrix, mouseX, mouseY); + + GL.pushMatrix(); + GL.translate(0, 0, 64.0f); + + if (!active) { + Minecraft minecraft = Minecraft.getInstance(); + minecraft.getTextureManager().bindTexture(CUSTOM_WIDGETS); + + blit(matrix, x + 44, y + 44, 22, 0, 20, 20); + + minecraft.getTextureManager().bindTexture(WIDGETS_LOCATION); + } + + GL.popMatrix(); + } + + private void renderItemStack(ItemStack stack, int x, int y, float scale) { + int BASE_Z_LEVEL = 100; + + GL.pushMatrix(); + + // Maps need more centering + if (isMap) GL.translate(-2f, 0f, 0f); + + GL.translate(x, y, 32.0f); + GL.scaleFixedZLevel(scale, -BASE_Z_LEVEL); + + renderer.zLevel = -BASE_Z_LEVEL / 2f; + renderer.renderItemAndEffectIntoGUI(stack, 0, 0); + renderer.zLevel = 0.0F; + GL.popMatrix(); + + } + + @Override + public void renderToolTip(MatrixStack stack, int mouseX, int mouseY) { + Display.renderTooltip(owner, stack, tooltip.get(), mouseX, mouseY); + } + +} \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/screens/widgets/UpdateableSliderWidget.java b/src/main/java/com/unascribed/blockrenderer/client/screens/widgets/UpdateableSliderWidget.java similarity index 92% rename from src/main/java/com/unascribed/blockrenderer/screens/widgets/UpdateableSliderWidget.java rename to src/main/java/com/unascribed/blockrenderer/client/screens/widgets/UpdateableSliderWidget.java index 1486e90..40b2a0e 100644 --- a/src/main/java/com/unascribed/blockrenderer/screens/widgets/UpdateableSliderWidget.java +++ b/src/main/java/com/unascribed/blockrenderer/client/screens/widgets/UpdateableSliderWidget.java @@ -1,4 +1,4 @@ -package com.unascribed.blockrenderer.screens.widgets; +package com.unascribed.blockrenderer.client.screens.widgets; import net.minecraft.client.GameSettings; import net.minecraft.client.gui.widget.OptionSlider; diff --git a/src/main/java/com/unascribed/blockrenderer/screens/widgets/options/ExtendedSliderPercentageOption.java b/src/main/java/com/unascribed/blockrenderer/client/screens/widgets/options/ExtendedSliderPercentageOption.java similarity index 93% rename from src/main/java/com/unascribed/blockrenderer/screens/widgets/options/ExtendedSliderPercentageOption.java rename to src/main/java/com/unascribed/blockrenderer/client/screens/widgets/options/ExtendedSliderPercentageOption.java index 71c7b23..1b33938 100644 --- a/src/main/java/com/unascribed/blockrenderer/screens/widgets/options/ExtendedSliderPercentageOption.java +++ b/src/main/java/com/unascribed/blockrenderer/client/screens/widgets/options/ExtendedSliderPercentageOption.java @@ -1,4 +1,4 @@ -package com.unascribed.blockrenderer.screens.widgets.options; +package com.unascribed.blockrenderer.client.screens.widgets.options; import net.minecraft.client.GameSettings; import net.minecraft.client.settings.SliderPercentageOption; diff --git a/src/main/java/com/unascribed/blockrenderer/client/screens/widgets/options/package-info.java b/src/main/java/com/unascribed/blockrenderer/client/screens/widgets/options/package-info.java new file mode 100644 index 0000000..aefadef --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/screens/widgets/options/package-info.java @@ -0,0 +1,4 @@ +@NonnullDefault +package com.unascribed.blockrenderer.client.screens.widgets.options; + +import org.lwjgl.system.NonnullDefault; \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/screens/widgets/package-info.java b/src/main/java/com/unascribed/blockrenderer/client/screens/widgets/package-info.java new file mode 100644 index 0000000..1eab252 --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/screens/widgets/package-info.java @@ -0,0 +1,4 @@ +@NonnullDefault +package com.unascribed.blockrenderer.client.screens.widgets; + +import org.lwjgl.system.NonnullDefault; \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/varia/Files.java b/src/main/java/com/unascribed/blockrenderer/client/varia/Files.java new file mode 100644 index 0000000..aaf7eb5 --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/varia/Files.java @@ -0,0 +1,56 @@ +package com.unascribed.blockrenderer.client.varia; + +import com.unascribed.blockrenderer.client.varia.logging.Log; +import com.unascribed.blockrenderer.client.varia.logging.Markers; +import org.jetbrains.annotations.Nullable; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; + +public interface Files { + + File DEFAULT_FOLDER = new File("renders"); + + @SuppressWarnings("UnstableApiUsage") + static File getFile(File folder, String filename, String type) throws IOException { + File file = new File(folder, filename + "." + type); + com.google.common.io.Files.createParentDirs(file); + + for (int i = 1; file.exists(); i++) + file = new File(folder, filename + "_" + i + "." + type); + + return file; + } + + static File getPng(File folder, String filename) throws IOException { + return getFile(folder, filename, "png"); + } + + static File savePng(File file, BufferedImage image) throws IOException { + ImageIO.write(image, "PNG", file); + return file; + } + + static File getGif(File folder, String filename) throws IOException { + return getFile(folder, filename, "gif"); + } + + @Nullable + static T wrap(String message, IOSupplier supplier) { + try { + return supplier.get(); + } catch (IOException e) { + Log.error(Markers.FILE, message, e); + } + + return null; + } + + @FunctionalInterface + interface IOSupplier { + T get() throws IOException; + } + +} \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/varia/Identifiers.java b/src/main/java/com/unascribed/blockrenderer/client/varia/Identifiers.java new file mode 100644 index 0000000..34b545b --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/varia/Identifiers.java @@ -0,0 +1,16 @@ +package com.unascribed.blockrenderer.client.varia; + +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.registries.IForgeRegistryEntry; + +public interface Identifiers { + + static ResourceLocation get(IForgeRegistryEntry value) { + ResourceLocation identifier = value.getRegistryName(); + + if (identifier == null) return new ResourceLocation("air"); + + return identifier; + } + +} \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/varia/Images.java b/src/main/java/com/unascribed/blockrenderer/client/varia/Images.java new file mode 100644 index 0000000..4c6f81b --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/varia/Images.java @@ -0,0 +1,67 @@ +package com.unascribed.blockrenderer.client.varia; + +import com.unascribed.blockrenderer.client.varia.rendering.TileRenderer; + +import java.awt.*; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; + +public class Images { + + public static BufferedImage fromTRFlipped(TileRenderer renderer) { + return flip(fromTR(renderer)); + } + + public static BufferedImage fromTR(TileRenderer renderer) { + int width = renderer.getImageWidth(); + int height = renderer.getImageHeight(); + + BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + + int[] pixels = new int[width * height]; + + renderer.getBuffer().asIntBuffer().get(pixels); + + img.setRGB(0, 0, width, height, pixels, 0, width); + + return img; + } + + private static BufferedImage flip(BufferedImage image) { + AffineTransform at = new AffineTransform(); + at.concatenate(AffineTransform.getScaleInstance(1, -1)); + at.concatenate(AffineTransform.getTranslateInstance(0, -image.getHeight())); + return createTransformed(image, at); + } + + private static BufferedImage createTransformed(BufferedImage old, AffineTransform at) { + /* Create a new Image the same size and type as the old image */ + BufferedImage img = new BufferedImage(old.getWidth(), old.getHeight(), old.getType()); + + /* Get the graphics */ + Graphics2D g = img.createGraphics(); + + /* Apply the transformations */ + g.transform(at); + + /* Render the old */ + g.drawImage(old, 0, 0, null); + g.dispose(); + + /* Return Resulting */ + return img; + } + + public static boolean same(BufferedImage a, BufferedImage b) { + if (a.getWidth() != b.getWidth()) return false; + if (a.getHeight() != b.getHeight()) return false; + + for (int x = 0; x < a.getWidth(); x++) + for (int y = 0; y < a.getHeight(); y++) + if (a.getRGB(x, y) != b.getRGB(x, y)) + return false; + + return true; + } + +} \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/utils/MathUtils.java b/src/main/java/com/unascribed/blockrenderer/client/varia/Maths.java similarity index 80% rename from src/main/java/com/unascribed/blockrenderer/utils/MathUtils.java rename to src/main/java/com/unascribed/blockrenderer/client/varia/Maths.java index 4a1eda4..e158ac0 100644 --- a/src/main/java/com/unascribed/blockrenderer/utils/MathUtils.java +++ b/src/main/java/com/unascribed/blockrenderer/client/varia/Maths.java @@ -1,8 +1,8 @@ -package com.unascribed.blockrenderer.utils; +package com.unascribed.blockrenderer.client.varia; import net.minecraft.util.math.MathHelper; -public interface MathUtils { +public interface Maths { static int minimum(int... args) { if (args.length < 1) return 0; @@ -19,7 +19,7 @@ static int roundAndClamp(double value, int minimum, int maximum, int threshold) static int roundAndClamp(int value, int minimum, int maximum, int threshold) { int nearestPowerOfTwo = nearestPowerOfTwo(value); - if (nearestPowerOfTwo < maximum && Math.abs(value-nearestPowerOfTwo) < threshold) value = nearestPowerOfTwo; + if (nearestPowerOfTwo < maximum && Math.abs(value - nearestPowerOfTwo) < threshold) value = nearestPowerOfTwo; return MathHelper.clamp(value, minimum, maximum); } diff --git a/src/main/java/com/unascribed/blockrenderer/utils/MiscUtils.java b/src/main/java/com/unascribed/blockrenderer/client/varia/MiscUtils.java similarity index 88% rename from src/main/java/com/unascribed/blockrenderer/utils/MiscUtils.java rename to src/main/java/com/unascribed/blockrenderer/client/varia/MiscUtils.java index e02d515..4c2119a 100644 --- a/src/main/java/com/unascribed/blockrenderer/utils/MiscUtils.java +++ b/src/main/java/com/unascribed/blockrenderer/client/varia/MiscUtils.java @@ -1,4 +1,4 @@ -package com.unascribed.blockrenderer.utils; +package com.unascribed.blockrenderer.client.varia; import com.google.common.collect.Lists; import net.minecraft.client.Minecraft; @@ -36,7 +36,9 @@ static List collectStacks(Set namespaces) { try { item.fillItemGroup(ItemGroup.SEARCH, list); - } catch (Throwable t) { LOGGER.warn("Failed to get render-able items for {}", identifier, t); } + } catch (Throwable t) { + LOGGER.warn("Failed to get render-able items for {}", identifier, t); + } stacks.addAll(list); } diff --git a/src/main/java/com/unascribed/blockrenderer/client/varia/Registries.java b/src/main/java/com/unascribed/blockrenderer/client/varia/Registries.java new file mode 100644 index 0000000..1a65576 --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/varia/Registries.java @@ -0,0 +1,17 @@ +package com.unascribed.blockrenderer.client.varia; + +import net.minecraft.item.Item; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.RegistryObject; +import net.minecraftforge.registries.ForgeRegistries; + +public interface Registries { + + RegistryObject MAP = RegistryObject.of(new ResourceLocation("minecraft:filled_map"), ForgeRegistries.ITEMS); + RegistryObject DISPENSER = RegistryObject.of(new ResourceLocation("minecraft:dispenser"), ForgeRegistries.ITEMS); + RegistryObject CUTTER = RegistryObject.of(new ResourceLocation("minecraft:stonecutter"), ForgeRegistries.ITEMS); + + static void clazzLoad() { + // INTENTIONAL LEFT BLANK + } +} \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/utils/StringUtils.java b/src/main/java/com/unascribed/blockrenderer/client/varia/StringUtils.java similarity index 87% rename from src/main/java/com/unascribed/blockrenderer/utils/StringUtils.java rename to src/main/java/com/unascribed/blockrenderer/client/varia/StringUtils.java index a285b3e..1759a39 100644 --- a/src/main/java/com/unascribed/blockrenderer/utils/StringUtils.java +++ b/src/main/java/com/unascribed/blockrenderer/client/varia/StringUtils.java @@ -1,4 +1,4 @@ -package com.unascribed.blockrenderer.utils; +package com.unascribed.blockrenderer.client.varia; import com.google.common.collect.Sets; import net.minecraft.client.Minecraft; @@ -10,6 +10,8 @@ import net.minecraft.util.text.TranslationTextComponent; import net.minecraft.util.text.event.ClickEvent; import net.minecraft.util.text.event.HoverEvent; +import net.minecraftforge.registries.ForgeRegistries; +import org.jetbrains.annotations.Nullable; import java.io.File; import java.text.DateFormat; @@ -22,6 +24,14 @@ public interface StringUtils { DateFormat DATETIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd_HH.mm.ss"); + static String getNamespace(@Nullable ItemStack stack) { + if (stack == null) return ""; + + ResourceLocation identifier = ForgeRegistries.ITEMS.getKey(stack.getItem()); + + return identifier == null ? "" : identifier.getNamespace(); + } + static Set getNamespaces(String namespaceSpec) { Set namespaces = Sets.newHashSet(); diff --git a/src/main/java/com/unascribed/blockrenderer/client/varia/debug/Debug.java b/src/main/java/com/unascribed/blockrenderer/client/varia/debug/Debug.java new file mode 100644 index 0000000..8800ccd --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/varia/debug/Debug.java @@ -0,0 +1,61 @@ +package com.unascribed.blockrenderer.client.varia.debug; + +import com.unascribed.blockrenderer.Reference; +import com.unascribed.blockrenderer.client.varia.logging.Log; +import com.unascribed.blockrenderer.client.varia.logging.Markers; +import org.lwjgl.opengl.GL; +import org.lwjgl.opengl.GREMEDYFrameTerminator; +import org.lwjgl.opengl.GREMEDYStringMarker; +import org.lwjgl.opengl.KHRDebug; + +@SuppressWarnings("UnnecessaryReturnStatement") +public class Debug { + + private static final int SOURCE = KHRDebug.GL_DEBUG_SOURCE_APPLICATION; + + private static final boolean isKHREnabled = GL.getCapabilities().GL_KHR_debug; + private static final boolean isGREMEDYEnabled = GL.getCapabilities().GL_GREMEDY_string_marker; + private static final boolean isGREMEDYFrameEnabled = GL.getCapabilities().GL_GREMEDY_frame_terminator; + + public static void push(String group) { + if (Reference.isDebug) + Log.debug(Markers.OPEN_GL_DEBUG, "Push Group '{}'", group); + + if (isKHREnabled) { + KHRDebug.glPushDebugGroup(SOURCE, 0, Reference.MOD_ID + ":" + group); + return; + } + + if (isGREMEDYEnabled) { + GREMEDYStringMarker.glStringMarkerGREMEDY(">> " + Reference.MOD_ID + ":" + group); + return; + } + } + + public static void pop() { + if (Reference.isDebug) + Log.debug(Markers.OPEN_GL_DEBUG, "Pop Group"); + + if (isKHREnabled) { + KHRDebug.glPopDebugGroup(); + return; + } + + if (isGREMEDYEnabled) { + GREMEDYStringMarker.glStringMarkerGREMEDY("<<"); + return; + } + } + + public static void endFrame() { + if (Reference.isDebug) + Log.info(Markers.OPEN_GL_DEBUG, "End Frame"); + + if (isGREMEDYFrameEnabled) { + GREMEDYFrameTerminator.glFrameTerminatorGREMEDY(); + return; + } + } + + +} \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/varia/debug/package-info.java b/src/main/java/com/unascribed/blockrenderer/client/varia/debug/package-info.java new file mode 100644 index 0000000..bcf411e --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/varia/debug/package-info.java @@ -0,0 +1,4 @@ +@NonnullDefault +package com.unascribed.blockrenderer.client.varia.debug; + +import org.lwjgl.system.NonnullDefault; \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/varia/gif/GifWriter.java b/src/main/java/com/unascribed/blockrenderer/client/varia/gif/GifWriter.java new file mode 100644 index 0000000..7864f63 --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/varia/gif/GifWriter.java @@ -0,0 +1,88 @@ +package com.unascribed.blockrenderer.client.varia.gif; + +import net.minecraft.util.math.MathHelper; +import org.w3c.dom.Node; + +import javax.imageio.*; +import javax.imageio.metadata.IIOMetadata; +import javax.imageio.metadata.IIOMetadataNode; +import javax.imageio.stream.ImageOutputStream; +import java.awt.image.BufferedImage; +import java.awt.image.RenderedImage; +import java.io.Closeable; +import java.io.IOException; +import java.util.Iterator; + +public class GifWriter implements Closeable { + + protected ImageWriter writer; + protected ImageWriteParam parameters; + protected IIOMetadata metadata; + + public GifWriter(ImageOutputStream stream, int delayMS, boolean loop) throws IOException { + writer = getGifWriter(); + parameters = writer.getDefaultWriteParam(); + + ImageTypeSpecifier specifier = ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_ARGB); + metadata = writer.getDefaultImageMetadata(specifier, parameters); + + setupMetadata(metadata, delayMS, loop); + + writer.setOutput(stream); + writer.prepareWriteSequence(null); + } + + public void writeFrame(RenderedImage image) throws IOException { + writer.writeToSequence(new IIOImage(image, null, metadata), parameters); + } + + @Override + public void close() throws IOException { + writer.endWriteSequence(); + } + + private static ImageWriter getGifWriter() throws IOException { + Iterator iter = ImageIO.getImageWritersBySuffix("gif"); + + if (iter.hasNext()) return iter.next(); + + throw new IOException("No Gif Writers were found"); + } + + private static void setupMetadata(IIOMetadata metadata, int delayMS, boolean loop) throws IOException { + IIOMetadataNode node = (IIOMetadataNode) metadata.getAsTree(metadata.getNativeMetadataFormatName()); + + /* https://docs.oracle.com/javase/8/docs/api/javax/imageio/metadata/doc-files/gif_metadata.html */ + + /* Setup Graphics */ + IIOMetadataNode graphics = findOrCreateNode(node, "GraphicControlExtension"); + graphics.setAttribute("disposalMethod", "restoreToBackgroundColor"); + graphics.setAttribute("userInputFlag", "FALSE"); + graphics.setAttribute("transparentColorFlag", "FALSE"); + graphics.setAttribute("transparentColorIndex", "0"); + + /* Setup Delay */ + graphics.setAttribute("delayTime", String.valueOf(MathHelper.clamp(delayMS / 10, 0, 65535))); + + /* Setup Looping */ + IIOMetadataNode extensions = findOrCreateNode(node, "ApplicationExtensions"); + IIOMetadataNode netscape = findOrCreateNode(extensions, "ApplicationExtension"); + netscape.setAttribute("applicationID", "NETSCAPE"); + netscape.setAttribute("authenticationCode", "2.0"); + netscape.setUserObject(new byte[]{0x1, 0x0, (byte) (loop ? 0x0 : 0x1)}); + + metadata.setFromTree(metadata.getNativeMetadataFormatName(), node); + } + + private static IIOMetadataNode findOrCreateNode(IIOMetadataNode parent, String name) { + for (int i = 0; i < parent.getLength(); i++) { + Node child = parent.item(i); + if (child.getNodeName().equalsIgnoreCase(name)) return (IIOMetadataNode) child; + } + + IIOMetadataNode child = new IIOMetadataNode(name); + parent.appendChild(child); + return child; + } + +} \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/varia/gif/package-info.java b/src/main/java/com/unascribed/blockrenderer/client/varia/gif/package-info.java new file mode 100644 index 0000000..132ca72 --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/varia/gif/package-info.java @@ -0,0 +1,4 @@ +@NonnullDefault +package com.unascribed.blockrenderer.client.varia.gif; + +import org.lwjgl.system.NonnullDefault; \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/varia/logging/Log.java b/src/main/java/com/unascribed/blockrenderer/client/varia/logging/Log.java new file mode 100644 index 0000000..1ff69af --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/varia/logging/Log.java @@ -0,0 +1,47 @@ +package com.unascribed.blockrenderer.client.varia.logging; + +import com.unascribed.blockrenderer.Reference; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.Marker; +import org.apache.logging.log4j.message.Message; + +public class Log { + + public static final Logger LOGGER = LogManager.getLogger(Reference.NAME); + + /* ===================================================================================================== API ==== */ + + public static void info(Marker marker, String message, Object... args) { + LOGGER.info(marker, message, args); + } + + public static void trace(Marker marker, String message, Object... args) { + LOGGER.trace(marker, message, args); + } + + public static void debug(Marker marker, String message, Object... args) { + LOGGER.debug(marker, message, args); + } + + public static void debug(Marker marker, Message message) { + LOGGER.debug(marker, message); + } + + public static void warn(Marker marker, String message, Object... args) { + LOGGER.warn(marker, message, args); + } + + public static void error(Marker marker, String message, Throwable t) { + LOGGER.error(marker, message, t); + } + + public static void error(Marker marker, String message, Object... args) { + LOGGER.error(marker, message, args); + } + + public static void fatal(Marker marker, String message, Object... args) { + LOGGER.fatal(marker, message, args); + } + +} \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/varia/logging/Markers.java b/src/main/java/com/unascribed/blockrenderer/client/varia/logging/Markers.java new file mode 100644 index 0000000..821f807 --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/varia/logging/Markers.java @@ -0,0 +1,28 @@ +package com.unascribed.blockrenderer.client.varia.logging; + +import com.unascribed.blockrenderer.Reference; +import org.apache.logging.log4j.Marker; +import org.apache.logging.log4j.MarkerManager; + +public class Markers { + + public static final Marker ROOT = marker(); + + public static final Marker OPEN_GL_DEBUG = marker("OpenGLDebug"); + public static final Marker FILE = marker("FILE"); + public static final Marker MANAGER = marker("MANAGER"); + public static final Marker PROGRESS = marker("PROGRESS"); + + private static Marker marker() { + return MarkerManager.getMarker(Reference.NAME); + } + + public static Marker marker(String name) { + return MarkerManager.getMarker(Reference.NAME + "-" + name).addParents(ROOT); + } + + public static Marker marker(String name, Marker parent) { + return MarkerManager.getMarker(Reference.NAME + "-" + name).addParents(parent); + } + +} \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/varia/logging/package-info.java b/src/main/java/com/unascribed/blockrenderer/client/varia/logging/package-info.java new file mode 100644 index 0000000..065b779 --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/varia/logging/package-info.java @@ -0,0 +1,4 @@ +@NonnullDefault +package com.unascribed.blockrenderer.client.varia.logging; + +import org.lwjgl.system.NonnullDefault; \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/varia/package-info.java b/src/main/java/com/unascribed/blockrenderer/client/varia/package-info.java new file mode 100644 index 0000000..92a1a3b --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/varia/package-info.java @@ -0,0 +1,4 @@ +@NonnullDefault +package com.unascribed.blockrenderer.client.varia; + +import org.lwjgl.system.NonnullDefault; \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/varia/rendering/Display.java b/src/main/java/com/unascribed/blockrenderer/client/varia/rendering/Display.java new file mode 100644 index 0000000..45f6c75 --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/varia/rendering/Display.java @@ -0,0 +1,74 @@ +package com.unascribed.blockrenderer.client.varia.rendering; + +import com.mojang.blaze3d.matrix.MatrixStack; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.AbstractGui; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.util.text.ITextComponent; +import net.minecraftforge.fml.client.gui.GuiUtils; + +import java.util.List; + +public interface Display { + + Minecraft client = Minecraft.getInstance(); + FontRenderer font = client.fontRenderer; + + static void drawRect(MatrixStack stack, int x1, int y1, int x2, int y2, int color) { + AbstractGui.fill(stack, x1, y1, x2, y2, color); + } + + static void drawCenteredString(MatrixStack stack, ITextComponent component, int x, int y, int color) { + drawCenteredString(stack, component.getString(), x, y, color); + } + + static void drawCenteredString(MatrixStack stack, String str, int x, int y, int color) { + font.drawStringWithShadow(stack, str, x - font.getStringWidth(str) / 2F, y, color); + } + + static void drawHoveringText(MatrixStack stack, List tooltip, int x, int y, int width, int height) { + GuiUtils.drawHoveringText(stack, tooltip, x, y, width, height, -1, font); + } + + static void renderTooltip(Screen owner, MatrixStack stack, List tooltip, int x, int y) { + GuiUtils.drawHoveringText(stack, tooltip, x, y, owner.width, owner.height, -1, font); + } + + static void drawDirtBackground(int scaledWidth, int scaledHeight) { + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder bufferbuilder = tessellator.getBuffer(); + + client.getTextureManager().bindTexture(AbstractGui.BACKGROUND_LOCATION); + + GL.color(1.0F, 1.0F, 1.0F, 1.0F); + bufferbuilder.begin(7, DefaultVertexFormats.POSITION_COLOR_TEX); + + // 0 h + bufferbuilder.pos(0.0D, scaledHeight, 0.0D) + .color(64, 64, 64, 255) + .tex(0.0F, scaledHeight / 32.0F + 0.0F) + .endVertex(); + // w h + bufferbuilder.pos(scaledWidth, scaledHeight, 0.0D) + .color(64, 64, 64, 255) + .tex(scaledWidth / 32.0F, scaledHeight / 32.0F + 0.0F) + .endVertex(); + // w 0 + bufferbuilder.pos(scaledWidth, 0.0D, 0.0D) + .color(64, 64, 64, 255) + .tex(scaledWidth / 32.0F, 0.0F) + .endVertex(); + // 0 0 + bufferbuilder.pos(0.0D, 0.0D, 0.0D) + .color(64, 64, 64, 255) + .tex(0.0F, 0.0F) + .endVertex(); + + tessellator.draw(); + } + +} \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/varia/rendering/GL.java b/src/main/java/com/unascribed/blockrenderer/client/varia/rendering/GL.java new file mode 100644 index 0000000..138af85 --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/varia/rendering/GL.java @@ -0,0 +1,180 @@ +package com.unascribed.blockrenderer.client.varia.rendering; + +import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.systems.RenderSystem; +import com.unascribed.blockrenderer.Reference; +import com.unascribed.blockrenderer.client.varia.logging.Log; +import com.unascribed.blockrenderer.client.varia.logging.Markers; +import net.minecraft.client.MainWindow; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.RenderHelper; +import org.lwjgl.opengl.GL11; + +import static org.lwjgl.opengl.GL11.*; + +@SuppressWarnings("deprecation") +public interface GL { + + Minecraft client = Minecraft.getInstance(); + MainWindow window = client.getMainWindow(); + + /* ================================================================================================== Matrix ==== */ + + static void pushMatrix() { + RenderSystem.pushMatrix(); + } + + static void pushMatrix(String debug) { + RenderSystem.pushMatrix(); + if (Reference.isDebug) + Log.debug(Markers.OPEN_GL_DEBUG, "> Push Matrix {}", debug); + } + + static void popMatrix() { + RenderSystem.popMatrix(); + } + + static void popMatrix(String debug) { + RenderSystem.popMatrix(); + if (Reference.isDebug) + Log.debug(Markers.OPEN_GL_DEBUG, "< Pop Matrix {}", debug); + } + + static void loadIdentity() { + RenderSystem.loadIdentity(); + } + + /* ========================================================================================= Transformations ==== */ + + static void translate(float x, float y, float z) { + RenderSystem.translatef(x, y, z); + } + + static void scale(float x, float y, float z) { + RenderSystem.scalef(x, y, z); + } + + static void scaleFixedZLevel(float scale, float zLevel) { + translate(0F, 0F, scale * zLevel); + scale(scale, scale, scale); + } + + /* ================================================================================================ Lighting ==== */ + + static void setupItemStackLighting() { + RenderHelper.setupGui3DDiffuseLighting(); + } + + static void displayLighting() { + RenderHelper.disableStandardItemLighting(); + } + + /* =================================================================================================== State ==== */ + + static void color(float r, float g, float b, float a) { + RenderSystem.color4f(r, g, b, a); + } + + static void enableDefaultBlend() { + RenderSystem.enableBlend(); + RenderSystem.defaultBlendFunc(); + } + + static void blendFunction(GlStateManager.SourceFactor source, GlStateManager.DestFactor dest) { + RenderSystem.blendFunc(source, dest); + } + + /* ================================================================================================== Buffer ==== */ + + static void clearFrameBuffer() { + resetClearColor(); + clearColorBuffer(); + clearDepthBuffer(); + } + + static void resetClearColor() { + RenderSystem.clearColor(0, 0, 0, 0); + } + + static void clearColorBuffer() { + RenderSystem.clear(GL11.GL_COLOR_BUFFER_BIT, Minecraft.IS_RUNNING_ON_MAC); + } + + static void clearDepthBuffer() { + RenderSystem.clear(GL11.GL_DEPTH_BUFFER_BIT, Minecraft.IS_RUNNING_ON_MAC); + } + + /* ================================================================================================== Window ==== */ + + static void unbindFBO() { + client.getFramebuffer().unbindFramebuffer(); + } + + static void flipFrame() { + window.flipFrame(); + } + + static void rebindFBO() { + client.getFramebuffer().bindFramebuffer(false); + } + + /* ============================================================================================= Projections ==== */ + + static void matrixModeProjection() { + RenderSystem.matrixMode(GL11.GL_PROJECTION); + } + + static void matrixModeModelView() { + RenderSystem.matrixMode(GL11.GL_MODELVIEW); + } + + static void setupItemStackRendering(TileRenderer tr) { + clearDepthBuffer(); + + /* Projection */ + matrixModeProjection(); + loadIdentity(); + + /* Setup Orthographic Projection */ + /* + Whilst we can switch the top/bottom parameters to save flipping the image later, + culling issues sometime occur. + */ + tr.orthographic(0.0, tr.getImageWidth(), tr.getImageHeight(), 0, 1000.0, 3000.0); + + /* Model View */ + matrixModeModelView(); + loadIdentity(); + translate(0f, 0f, -2000f); + } + + static void setupMapRendering(TileRenderer tr) { + clearDepthBuffer(); + + /* Projection */ + matrixModeProjection(); + loadIdentity(); + + //TODO: Reduce Near / Far + tr.orthographic(0.0, tr.getImageWidth(), tr.getImageHeight(), 0, -1000.0F, 3000.0f); + + /* Model View */ + matrixModeModelView(); + loadIdentity(); + } + + static void setupOverlayRendering() { + Minecraft client = Minecraft.getInstance(); + MainWindow window = client.getMainWindow(); + double scaleFactor = window.getGuiScaleFactor(); + + RenderSystem.clear(GL_DEPTH_BUFFER_BIT, Minecraft.IS_RUNNING_ON_MAC); + RenderSystem.matrixMode(GL_PROJECTION); + RenderSystem.loadIdentity(); + RenderSystem.ortho(0.0D, window.getFramebufferWidth() / scaleFactor, + window.getFramebufferHeight() / scaleFactor, 0.0D, 1000.0D, 3000.0D); + RenderSystem.matrixMode(GL_MODELVIEW); + RenderSystem.loadIdentity(); + RenderSystem.translatef(0.0F, 0.0F, -2000.0F); + } +} \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/varia/rendering/TileRenderer.java b/src/main/java/com/unascribed/blockrenderer/client/varia/rendering/TileRenderer.java new file mode 100644 index 0000000..72ea661 --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/varia/rendering/TileRenderer.java @@ -0,0 +1,61 @@ +package com.unascribed.blockrenderer.client.varia.rendering; + +import com.unascribed.blockrenderer.client.vendor.tr.TR; + +import java.nio.ByteBuffer; + +import static java.lang.Math.max; + +public interface TileRenderer { + + /* ===================================================================================================== Api ==== */ + + void orthographic(double left, double right, double bottom, double top, double zNear, double zFar); + + void beginTile(); + + boolean endTile(); + + /* =============================================================================================== Accessors ==== */ + + ByteBuffer getBuffer(); + + int getImageWidth(); + + int getImageHeight(); + + /* ================================================================================================= Utility ==== */ + + default void clearBuffer() { + getBuffer().clear(); + } + + /* ================================================================================================= Factory ==== */ + + int BORDER_SIZE = 4; + int MINIMUM_SIZE = BORDER_SIZE * 2 + 1; + + static TileRenderer forSize(int size, int tileSize) { + return forSize(size, size, tileSize, tileSize); + } + + static TileRenderer forSize(int width, int height, int tileWidth, int tileHeight) { + + /* Ensure Image Sizes are bigger than minimumSize */ + width = max(width, MINIMUM_SIZE); + height = max(height, MINIMUM_SIZE); + + /* Ensure Tile Sizes are bigger than minimumSize */ + tileWidth = max(tileWidth, MINIMUM_SIZE); + tileHeight = max(tileHeight, MINIMUM_SIZE); + + /* Ensure Tile Sizes is not bigger than Image Sizes */ + if (width < tileWidth) tileWidth = width; + if (height < tileHeight) tileHeight = height; + + /* If Tile Sizes are the same as Image Sizes then no border otherwise a border of BORDER_SIZE pixels */ + boolean sameSize = width == tileWidth && height == tileHeight; + return new TR(width, height, tileWidth, tileHeight, sameSize ? 0 : BORDER_SIZE); + } + +} \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/varia/rendering/package-info.java b/src/main/java/com/unascribed/blockrenderer/client/varia/rendering/package-info.java new file mode 100644 index 0000000..ea3051d --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/varia/rendering/package-info.java @@ -0,0 +1,4 @@ +@NonnullDefault +package com.unascribed.blockrenderer.client.varia.rendering; + +import org.lwjgl.system.NonnullDefault; \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/client/vendor/tr/TR.java b/src/main/java/com/unascribed/blockrenderer/client/vendor/tr/TR.java new file mode 100644 index 0000000..3eb8d73 --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/vendor/tr/TR.java @@ -0,0 +1,237 @@ +package com.unascribed.blockrenderer.client.vendor.tr; + +/* + * Copyright (c) 1997-2005 Brian Paul. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Brian Paul or the names of contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any + * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND + * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY + * EXCLUDED. THE COPYRIGHT HOLDERS AND CONTRIBUTORS SHALL NOT BE + * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, + * MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO + * EVENT WILL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY + * LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, + * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND + * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +import com.unascribed.blockrenderer.client.varia.rendering.TileRenderer; +import org.jetbrains.annotations.NotNull; +import org.lwjgl.BufferUtils; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL12; + +import java.nio.ByteBuffer; + +/** + * A reduced port of Brian Paul's tile rendering library, found at http://www.mesa3d.org/brianp/TR.html . + *

+ * Original code Copyright (C) 1997-2005 Brian Paul.
Licensed under BSD-compatible terms with permission of the + * author.
See LICENSE.md for license information. + *

+ *

+ * Reduced to bare minimums by AterAnimAvis
See JOGL#opengl/util/ + * for original source code. + *

+ * + * @author Brian Paul, ryanm, sgothel, ateranimavis + */ +public class TR implements TileRenderer { + + private final ByteBuffer buffer; + + public final int imageWidth; + public final int imageHeight; + + private final int tileBorder; + private final int tileWidth; + private final int tileHeight; + + private final int tileWidthNB; + private final int tileHeightNB; + + private final int columns; + private final int rows; + + private int currentColumn = 0; + private int currentRow = 0; + private int currentTile = -1; + + private int currentTileWidth; + private int currentTileHeight; + + public TR(int width, int height, int tileWidth, int tileHeight, int tileBorder) { + imageWidth = width; + imageHeight = height; + + this.tileWidth = tileWidth; + this.tileHeight = tileHeight; + this.tileBorder = tileBorder; + + tileWidthNB = tileWidth - 2 * tileBorder; + tileHeightNB = tileHeight - 2 * tileBorder; + + columns = (imageWidth + tileWidthNB - 1) / tileWidthNB; + rows = (imageHeight + tileHeightNB - 1) / tileHeightNB; + + buffer = BufferUtils.createByteBuffer(width * height * 4); + } + + private double left = 0; + private double right = 0; + private double bottom = 0; + private double top = 0; + private double near = 0; + private double far = 0; + + private final int[] viewport = new int[4]; + + /** + * Sets the orthographic projection, Must be called before rendering the first tile. + */ + @Override + public void orthographic(double left, double right, double bottom, double top, double zNear, double zFar) { + this.left = left; + this.right = right; + this.bottom = bottom; + this.top = top; + this.near = zNear; + this.far = zFar; + } + + @Override + public void beginTile() { + /* Save user's viewport, will be restored after last tile rendered */ + if (currentTile <= 0) { + GL11.glGetIntegerv(GL11.GL_VIEWPORT, viewport); + currentTile = 0; + } + + /* Which tile (by row and column) we're about to render */ + currentRow = rows - 1 - (currentTile / columns); + currentColumn = currentTile % columns; + + /* Compute actual size of this tile with border */ + int th, tw; + + if (currentRow < rows - 1) { + th = tileHeight; + } else { + th = imageHeight - (rows - 1) * tileHeightNB + 2 * tileBorder; + } + + if (currentColumn < columns - 1) { + tw = tileWidth; + } else { + tw = imageWidth - (columns - 1) * tileWidthNB + 2 * tileBorder; + } + + /* Save tile size, with border */ + currentTileHeight = th; + currentTileWidth = tw; + + /* Apply the viewport */ + GL11.glViewport(0, 0, tw, th); + + /* Save current matrix mode */ + final int matrixMode = GL11.glGetInteger(GL11.GL_MATRIX_MODE); + GL11.glMatrixMode(GL11.GL_PROJECTION); + GL11.glLoadIdentity(); + + /* Compute projection parameters */ + final double l = left + (right - left) * (currentColumn * tileWidthNB - tileBorder) / imageWidth; + final double r = l + (right - left) * tw / imageWidth; + final double b = bottom + (top - bottom) * (currentRow * tileHeightNB - tileBorder) / imageHeight; + final double t = b + (top - bottom) * th / imageHeight; + + /* Apply the projection */ + GL11.glOrtho(l, r, b, t, near, far); + + /* Restore user's matrix mode */ + GL11.glMatrixMode(matrixMode); + } + + @Override + @SuppressWarnings("UnnecessaryLocalVariable") + public boolean endTile() { + /* Be sure OpenGL rendering is finished */ + GL11.glFlush(); + + /* Save current glPixelStore values */ + int prevRowLength = GL11.glGetInteger(GL11.GL_PACK_ROW_LENGTH); + int prevSkipRows = GL11.glGetInteger(GL11.GL_PACK_SKIP_ROWS); + int prevSkipPixels = GL11.glGetInteger(GL11.GL_PACK_SKIP_PIXELS); + int prevAlignment = GL11.glGetInteger(GL11.GL_PACK_ALIGNMENT); + + /* Read Pixels */ + final int srcX = tileBorder; + final int srcY = tileBorder; + final int srcWidth = currentTileWidth - 2 * tileBorder; + final int srcHeight = currentTileHeight - 2 * tileBorder; + final int destX = tileWidthNB * currentColumn; + final int destY = tileHeightNB * currentRow; + + /* Setup pixel store for glReadPixels */ + GL11.glPixelStorei(GL11.GL_PACK_ROW_LENGTH, imageWidth); + GL11.glPixelStorei(GL11.GL_PACK_SKIP_ROWS, destY); + GL11.glPixelStorei(GL11.GL_PACK_SKIP_PIXELS, destX); + GL11.glPixelStorei(GL11.GL_PACK_ALIGNMENT, 1); + + /* Read the tile into the final image */ + GL11.glReadPixels(srcX, srcY, srcWidth, srcHeight, GL12.GL_BGRA, GL11.GL_UNSIGNED_BYTE, buffer); + + /* Restore previous glPixelStore Values */ + GL11.glPixelStorei(GL11.GL_PACK_ROW_LENGTH, prevRowLength); + GL11.glPixelStorei(GL11.GL_PACK_SKIP_ROWS, prevSkipRows); + GL11.glPixelStorei(GL11.GL_PACK_SKIP_PIXELS, prevSkipPixels); + GL11.glPixelStorei(GL11.GL_PACK_ALIGNMENT, prevAlignment); + + /* Increment Tile Counter */ + currentTile++; + + if (currentTile >= rows * columns) { + /* Restore user's viewport */ + GL11.glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); + currentTile = -1; + return false; + } + + return true; + } + + @NotNull + @Override + public ByteBuffer getBuffer() { + return buffer; + } + + @Override + public int getImageWidth() { + return imageWidth; + } + + @Override + public int getImageHeight() { + return imageHeight; + } + +} diff --git a/src/main/java/com/unascribed/blockrenderer/client/vendor/tr/package-info.java b/src/main/java/com/unascribed/blockrenderer/client/vendor/tr/package-info.java new file mode 100644 index 0000000..6a0db9e --- /dev/null +++ b/src/main/java/com/unascribed/blockrenderer/client/vendor/tr/package-info.java @@ -0,0 +1,4 @@ +@NonnullDefault +package com.unascribed.blockrenderer.client.vendor.tr; + +import org.lwjgl.system.NonnullDefault; \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/init/package-info.java b/src/main/java/com/unascribed/blockrenderer/init/package-info.java deleted file mode 100644 index 57afab1..0000000 --- a/src/main/java/com/unascribed/blockrenderer/init/package-info.java +++ /dev/null @@ -1,7 +0,0 @@ -@MethodsReturnNonnullByDefault -@ParametersAreNonnullByDefault -package com.unascribed.blockrenderer.init; - -import com.unascribed.blockrenderer.annotation.MethodsReturnNonnullByDefault; - -import javax.annotation.ParametersAreNonnullByDefault; \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/lib/TileRenderer.java b/src/main/java/com/unascribed/blockrenderer/lib/TileRenderer.java deleted file mode 100644 index 80b0628..0000000 --- a/src/main/java/com/unascribed/blockrenderer/lib/TileRenderer.java +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright 2013 JogAmp Community. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of JogAmp Community. - * - * --------------------- - * - * Based on Brian Paul's tile rendering library, found - * at http://www.mesa3d.org/brianp/TR.html. - * - * Copyright (C) 1997-2005 Brian Paul. - * Licensed under BSD-compatible terms with permission of the author. - * See LICENSE.txt for license information. - */ -package com.unascribed.blockrenderer.lib; - -import org.lwjgl.BufferUtils; -import org.lwjgl.opengl.GL11; -import org.lwjgl.opengl.GL12; - -import java.nio.ByteBuffer; - -/** - * A reduced port of Brian Paul's tile rendering library, found at - * http://www.mesa3d.org/brianp/TR.html . - *

- * Original code Copyright (C) 1997-2005 Brian Paul. Licensed under - * BSD-compatible terms with permission of the author. See LICENSE.txt - * for license information. - *

- *

- * Vastly simplified by AterAnimAvis (Practically a Reimplementation of the original TR Library)
- * See https://github.com/sgothel/jogl/blob/master/src/jogl/classes/com/jogamp/opengl/util/ for original source code. - *

- * - * @author ryanm, sgothel, ateranimavis - */ -public class TileRenderer { - - public final ByteBuffer buffer; - - public final int imageWidth; - public final int imageHeight; - - private final int tileBorder; - private final int tileWidth; - private final int tileHeight; - - private final int tileWidthNB; - private final int tileHeightNB; - - private final int columns; - private final int rows; - - private int currentColumn = 0; - private int currentRow = 0; - private int currentTile = -1; - - private int currentTileWidth; - private int currentTileHeight; - - public TileRenderer(int width, int height, int tileWidth, int tileHeight, int tileBorder) { - this.imageWidth = width; - this.imageHeight = height; - - this.tileWidth = tileWidth; - this.tileHeight = tileHeight; - this.tileBorder = tileBorder; - - tileWidthNB = tileWidth - 2 * tileBorder; - tileHeightNB = tileHeight - 2 * tileBorder; - - columns = (imageWidth + tileWidthNB - 1) / tileWidthNB; - rows = (imageHeight + tileHeightNB - 1) / tileHeightNB; - - buffer = BufferUtils.createByteBuffer(width * height * 4); - } - - public static TileRenderer forSize(int size, int tileSize) { - return forSize(size, size, tileSize, tileSize); - } - - public static TileRenderer forSize(int width, int height, int tileWidth, int tileHeight) { - // If tileSize is the same as imageSize then don't add a border - if (width == tileWidth && height == tileHeight) - return new TileRenderer(width, height, tileWidth, tileHeight, 0); - - return new TileRenderer(width, height, tileWidth, tileHeight, 4); - } - - private boolean perspective = false; - private double left = 0; - private double right = 0; - private double bottom = 0; - private double top = 0; - private double near = 0; - private double far = 0; - - private final int[] viewport = new int[4]; - - /** - * Sets the orthographic projection, Must be called before rendering the first tile. - */ - public void ortho(double left, double right, double bottom, double top, double zNear, double zFar) { - this.perspective = false; - this.left = left; - this.right = right; - this.bottom = bottom; - this.top = top; - this.near = zNear; - this.far = zFar; - } - - /** - * Sets the perspective projection frustum, Must be called before rendering the first tile. - */ - public void frustum(double left, double right, double bottom, double top, double zNear, double zFar) { - this.perspective = true; - this.left = left; - this.right = right; - this.bottom = bottom; - this.top = top; - this.near = zNear; - this.far = zFar; - } - - public void perspective(double fovy, double aspect, double zNear, double zFar) { - double ymax = zNear * Math.tan(fovy * Math.PI / 360); - double xmax = ymax * aspect; - frustum(-xmax, xmax, -ymax, ymax, zNear, zFar); - } - - public void beginTile() { - /* Save user's viewport, will be restored after last tile rendered */ - if (currentTile <= 0) { - GL11.glGetIntegerv(GL11.GL_VIEWPORT, viewport); - currentTile = 0; - } - - /* Which tile (by row and column) we're about to render */ - currentRow = rows - 1 - (currentTile / columns); - currentColumn = currentTile % columns; - - /* Compute actual size of this tile with border */ - int th, tw; - - if (currentRow < rows - 1) th = tileHeight; - else th = imageHeight - (rows - 1) * tileHeightNB + 2 * tileBorder; - - if (currentColumn < columns - 1) tw = tileWidth; - else tw = imageWidth - (columns - 1) * tileWidthNB + 2 * tileBorder; - - /* Save tile size, with border */ - currentTileHeight = th; - currentTileWidth = tw; - - GL11.glViewport(0, 0, tw, th); - - /* Save current matrix mode */ - final int matrixMode = GL11.glGetInteger(GL11.GL_MATRIX_MODE); - GL11.glMatrixMode(GL11.GL_PROJECTION ); - GL11.glLoadIdentity(); - - /* Compute projection parameters */ - final double l = left + (right - left) * (currentColumn * tileWidthNB - tileBorder) / imageWidth; - final double r = l + (right - left) * tw / imageWidth; - final double b = bottom + (top - bottom) * (currentRow * tileHeightNB - tileBorder) / imageHeight; - final double t = b + (top - bottom) * th / imageHeight; - - if (perspective) GL11.glFrustum(l, r, b, t, near, far); - else GL11.glOrtho(l, r, b, t, near, far); - - /* Restore user's matrix mode */ - GL11.glMatrixMode(matrixMode); - } - - public boolean endTile() { - /* Be sure OpenGL rendering is finished */ - GL11.glFlush(); - - /* Save current glPixelStore values */ - int prevRowLength = GL11.glGetInteger(GL11.GL_PACK_ROW_LENGTH); - int prevSkipRows = GL11.glGetInteger(GL11.GL_PACK_SKIP_ROWS); - int prevSkipPixels = GL11.glGetInteger(GL11.GL_PACK_SKIP_PIXELS); - int prevAlignment = GL11.glGetInteger(GL11.GL_PACK_ALIGNMENT); - - /* Read Pixels */ - final int srcX = tileBorder; - final int srcY = tileBorder; - final int srcWidth = currentTileWidth - 2 * tileBorder; - final int srcHeight = currentTileHeight - 2 * tileBorder; - final int destX = tileWidthNB * currentColumn; - final int destY = tileHeightNB * currentRow; - - /* Setup pixel store for glReadPixels */ - GL11.glPixelStorei(GL11.GL_PACK_ROW_LENGTH, imageWidth); - GL11.glPixelStorei(GL11.GL_PACK_SKIP_ROWS, destY); - GL11.glPixelStorei(GL11.GL_PACK_SKIP_PIXELS, destX); - GL11.glPixelStorei(GL11.GL_PACK_ALIGNMENT, 1); - - /* Read the tile into the final image */ - GL11.glReadPixels(srcX, srcY, srcWidth, srcHeight, GL12.GL_BGRA, GL11.GL_UNSIGNED_BYTE, buffer); - - /* Restore previous glPixelStore Values */ - GL11.glPixelStorei(GL11.GL_PACK_ROW_LENGTH, prevRowLength); - GL11.glPixelStorei(GL11.GL_PACK_SKIP_ROWS, prevSkipRows); - GL11.glPixelStorei(GL11.GL_PACK_SKIP_PIXELS, prevSkipPixels); - GL11.glPixelStorei(GL11.GL_PACK_ALIGNMENT, prevAlignment); - - /* Increment Tile Counter */ - currentTile++; - - if (currentTile >= rows * columns) { - /* Restore user's viewport */ - GL11.glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); - currentTile = -1; - return false; - } - - return true; - } - -} diff --git a/src/main/java/com/unascribed/blockrenderer/lib/package-info.java b/src/main/java/com/unascribed/blockrenderer/lib/package-info.java deleted file mode 100644 index eb5f54f..0000000 --- a/src/main/java/com/unascribed/blockrenderer/lib/package-info.java +++ /dev/null @@ -1,7 +0,0 @@ -@MethodsReturnNonnullByDefault -@ParametersAreNonnullByDefault -package com.unascribed.blockrenderer.lib; - -import com.unascribed.blockrenderer.annotation.MethodsReturnNonnullByDefault; - -import javax.annotation.ParametersAreNonnullByDefault; \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/package-info.java b/src/main/java/com/unascribed/blockrenderer/package-info.java index f2687e9..7976913 100644 --- a/src/main/java/com/unascribed/blockrenderer/package-info.java +++ b/src/main/java/com/unascribed/blockrenderer/package-info.java @@ -1,7 +1,4 @@ -@MethodsReturnNonnullByDefault -@ParametersAreNonnullByDefault +@NonnullDefault package com.unascribed.blockrenderer; -import com.unascribed.blockrenderer.annotation.MethodsReturnNonnullByDefault; - -import javax.annotation.ParametersAreNonnullByDefault; \ No newline at end of file +import org.lwjgl.system.NonnullDefault; \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/proxy/CommonProxy.java b/src/main/java/com/unascribed/blockrenderer/proxy/CommonProxy.java index 7592e8e..5d2a7b5 100644 --- a/src/main/java/com/unascribed/blockrenderer/proxy/CommonProxy.java +++ b/src/main/java/com/unascribed/blockrenderer/proxy/CommonProxy.java @@ -1,13 +1,7 @@ package com.unascribed.blockrenderer.proxy; -import com.unascribed.blockrenderer.render.request.IRequest; - public abstract class CommonProxy { public abstract void init(); - public void render(IRequest request) { - // NO-OP - } - } diff --git a/src/main/java/com/unascribed/blockrenderer/proxy/package-info.java b/src/main/java/com/unascribed/blockrenderer/proxy/package-info.java index 5c13dd2..0801d78 100644 --- a/src/main/java/com/unascribed/blockrenderer/proxy/package-info.java +++ b/src/main/java/com/unascribed/blockrenderer/proxy/package-info.java @@ -1,7 +1,4 @@ -@MethodsReturnNonnullByDefault -@ParametersAreNonnullByDefault +@NonnullDefault package com.unascribed.blockrenderer.proxy; -import com.unascribed.blockrenderer.annotation.MethodsReturnNonnullByDefault; - -import javax.annotation.ParametersAreNonnullByDefault; \ No newline at end of file +import org.lwjgl.system.NonnullDefault; \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/render/BulkRenderer.java b/src/main/java/com/unascribed/blockrenderer/render/BulkRenderer.java deleted file mode 100644 index a05ca5b..0000000 --- a/src/main/java/com/unascribed/blockrenderer/render/BulkRenderer.java +++ /dev/null @@ -1,138 +0,0 @@ -package com.unascribed.blockrenderer.render; - -import com.mojang.blaze3d.matrix.MatrixStack; -import com.mojang.blaze3d.systems.RenderSystem; -import com.unascribed.blockrenderer.utils.Rendering; -import net.minecraft.client.MainWindow; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.screen.IngameMenuScreen; -import net.minecraft.client.resources.I18n; -import net.minecraft.util.Util; -import net.minecraft.util.text.TranslationTextComponent; - -import javax.annotation.Nullable; -import java.io.File; -import java.util.List; - -import static com.unascribed.blockrenderer.render.IRenderer.DEFAULT_FOLDER; -import static com.unascribed.blockrenderer.utils.MiscUtils.isEscapePressed; -import static com.unascribed.blockrenderer.utils.StringUtils.*; - -public class BulkRenderer { - - private static final int WAIT = 1500; - - private static final Minecraft client = Minecraft.getInstance(); - private static final MainWindow window = client.getMainWindow(); - - public static void bulkRender(IRenderer renderer, String spec, List renders, int size, boolean useId, boolean addSize) { - if (renders.size() < 1) { - addMessage(new TranslationTextComponent("msg.block_renderer.bulk.noItems", spec)); - return; - } - - client.displayGuiScreen(new IngameMenuScreen(false)); - - int errored = 0; - int rendered = 0; - long lastUpdate = 0; - int total = renders.size(); - - String sizeString = addSize ? size + "x" + size + "_" : ""; - File folder = new File(DEFAULT_FOLDER, dateTime() + "_" + sizeString + sanitize(spec) + "/"); - String title = I18n.format("block_renderer.gui.rendering", total, spec); - - long start = Util.milliTime(); - - renderer.setup(size); - for (T value : renders) { - if (isEscapePressed()) break; - - String fileName = renderer.getFilename(value, useId); - - try { - renderer.render(value); - renderer.saveRaw(folder, fileName); - } catch (Exception e) { - System.err.println("Rendering: " + renderer.getId(value)); - e.printStackTrace(); - errored++; - } - - rendered++; - - if (Util.milliTime() - lastUpdate > 33) { - renderer.teardown(); - - renderLoading(renderer, title, I18n.format("block_renderer.gui.progress", rendered, total, (total - rendered)), value, (float)rendered/ total); - - lastUpdate = Util.milliTime(); - renderer.setup(size); - } - } - - long elapsed = Util.milliTime() - start; - - if (rendered >= total) { - renderLoading(renderer, I18n.format("block_renderer.gui.rendered", total, spec), "", null, 1f); - addMessage(new TranslationTextComponent("msg.block_renderer.bulk.finished", total, spec, asClickable(folder))); - } else { - renderLoading(renderer, I18n.format("block_renderer.gui.renderCancelled"), I18n.format("block_renderer.gui.progress", rendered, total, (total - rendered)), null, (float)rendered/ total); - addMessage(new TranslationTextComponent("msg.block_renderer.bulk.cancelled", rendered, spec, asClickable(folder), total)); - } - - if (errored > 0) { - addMessage(""); - addMessage(new TranslationTextComponent("msg.block_renderer.bulk.errored", errored)); - } - - addMessage(""); - addMessage(new TranslationTextComponent("msg.block_renderer.bulk.time", elapsed / 1000f)); - - renderer.teardown(); - - try { Thread.sleep(WAIT); } catch (InterruptedException ignored) {} - - client.displayGuiScreen(null); - } - - private static void renderLoading(IRenderer renderer, String title, String subtitle, @Nullable T value, float progress) { - client.getFramebuffer().unbindFramebuffer(); - - RenderSystem.pushMatrix(); - MatrixStack stack = new MatrixStack(); - - int displayWidth = window.getScaledWidth(); - int displayHeight = window.getScaledHeight(); - Rendering.setupOverlayRendering(); - - // Draw the dirt background - Rendering.drawBackground(displayWidth, displayHeight); - - // ...and the title - Rendering.drawCenteredString(stack, client.fontRenderer, title, displayWidth / 2, displayHeight / 2 - 24, -1); - - // ...and the progress bar - Rendering.drawRect(stack, displayWidth / 2 - 50, displayHeight / 2 - 1, displayWidth / 2 + 50, displayHeight / 2 + 1, 0xFF001100); - Rendering.drawRect(stack, displayWidth / 2 - 50, displayHeight / 2 - 1, (displayWidth / 2 - 50) + (int) (progress * 100), displayHeight / 2 + 1, 0xFF55FF55); - - RenderSystem.pushMatrix(); - - RenderSystem.scalef(0.5f, 0.5f, 1); - - // ...and the subtitle - Rendering.drawCenteredString(stack, client.fontRenderer, subtitle, displayWidth, displayHeight - 20, -1); - - // ...and the tooltip. - if (value != null) renderer.renderTooltip(stack, value, displayWidth, displayHeight); - - RenderSystem.popMatrix(); - - RenderSystem.popMatrix(); - - window.flipFrame(); - - client.getFramebuffer().bindFramebuffer(false); - } - -} diff --git a/src/main/java/com/unascribed/blockrenderer/render/IRenderer.java b/src/main/java/com/unascribed/blockrenderer/render/IRenderer.java deleted file mode 100644 index bca9854..0000000 --- a/src/main/java/com/unascribed/blockrenderer/render/IRenderer.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.unascribed.blockrenderer.render; - -import com.google.common.io.Files; -import com.mojang.blaze3d.matrix.MatrixStack; -import com.unascribed.blockrenderer.lib.TileRenderer; -import com.unascribed.blockrenderer.utils.ImageUtils; -import net.minecraft.util.ResourceLocation; -import net.minecraft.util.text.ITextComponent; -import net.minecraft.util.text.TranslationTextComponent; - -import javax.annotation.Nullable; -import javax.imageio.ImageIO; -import java.awt.image.BufferedImage; -import java.io.File; - -import static com.unascribed.blockrenderer.utils.FileUtils.getFile; -import static com.unascribed.blockrenderer.utils.StringUtils.getRenderSuccess; -import static com.unascribed.blockrenderer.utils.StringUtils.sanitize; - -public interface IRenderer { - - File DEFAULT_FOLDER = new File("renders"); - - void setup(int size); - - void render(T value); - - void teardown(); - - void renderTooltip(MatrixStack stack, T value, int displayWidth, int displayHeight); - - ResourceLocation getId(T value); - - ITextComponent getName(T value); - - default String getFilename(T value, boolean useId) { - return useId ? sanitize(getId(value)) : sanitize(getName(value)); - } - - @Nullable - TileRenderer getRenderer(); - - @SuppressWarnings("UnstableApiUsage") - default File saveRaw(File folder, String filename) throws Exception { - TileRenderer renderer = getRenderer(); - - if (renderer == null) throw new IllegalStateException("TileRenderer is null"); - - BufferedImage img = ImageUtils.readPixels(renderer); - - File file = getFile(folder, filename); - Files.createParentDirs(file); - - ImageIO.write(img, "PNG", file); - - return file; - } - - default ITextComponent save(T value, File folder, String filename) { - try { - File file = saveRaw(folder, filename); - return getRenderSuccess(folder, file); - } catch (Exception e) { - System.err.println("Rendering: " + getId(value)); - e.printStackTrace(); - return new TranslationTextComponent("msg.block_renderer.render.fail"); - } - } - -} diff --git a/src/main/java/com/unascribed/blockrenderer/render/SingleRenderer.java b/src/main/java/com/unascribed/blockrenderer/render/SingleRenderer.java deleted file mode 100644 index b3decca..0000000 --- a/src/main/java/com/unascribed/blockrenderer/render/SingleRenderer.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.unascribed.blockrenderer.render; - -import static com.unascribed.blockrenderer.render.IRenderer.DEFAULT_FOLDER; -import static com.unascribed.blockrenderer.utils.StringUtils.addMessage; -import static com.unascribed.blockrenderer.utils.StringUtils.dateTime; - -public class SingleRenderer { - - public static void render(IRenderer renderer, T value, int size, boolean useId, boolean addSize) { - String sizeString = addSize ? size + "x" + size + "_" : ""; - String fileName = renderer.getFilename(value, useId); - - renderer.setup(size); - renderer.render(value); - addMessage(renderer.save(value, DEFAULT_FOLDER, dateTime() + "_" + sizeString + fileName)); - renderer.teardown(); - } - -} diff --git a/src/main/java/com/unascribed/blockrenderer/render/impl/ItemStackRenderer.java b/src/main/java/com/unascribed/blockrenderer/render/impl/ItemStackRenderer.java deleted file mode 100644 index 5971829..0000000 --- a/src/main/java/com/unascribed/blockrenderer/render/impl/ItemStackRenderer.java +++ /dev/null @@ -1,145 +0,0 @@ -package com.unascribed.blockrenderer.render.impl; - -import com.mojang.blaze3d.matrix.MatrixStack; -import com.mojang.blaze3d.systems.RenderSystem; -import com.unascribed.blockrenderer.lib.TileRenderer; -import com.unascribed.blockrenderer.render.IRenderer; -import com.unascribed.blockrenderer.utils.Rendering; -import net.minecraft.client.MainWindow; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.FontRenderer; -import net.minecraft.client.renderer.ItemRenderer; -import net.minecraft.client.renderer.RenderHelper; -import net.minecraft.item.ItemStack; -import net.minecraft.util.ResourceLocation; -import net.minecraft.util.Util; -import net.minecraft.util.text.ITextComponent; -import net.minecraft.util.text.ITextProperties; -import net.minecraftforge.registries.ForgeRegistries; -import org.lwjgl.opengl.GL11; - -import javax.annotation.Nullable; -import java.util.List; -import java.util.function.LongSupplier; - -import static com.unascribed.blockrenderer.utils.MathUtils.minimum; -import static com.unascribed.blockrenderer.utils.StringUtils.getTooltipFromItem; - -public class ItemStackRenderer implements IRenderer { - - private static final Minecraft client = Minecraft.getInstance(); - private static final MainWindow window = client.getMainWindow(); - private static final ItemRenderer itemRenderer = client.getItemRenderer(); - - private float oldZLevel; - - private TileRenderer renderer; - - @Override - public void setup(int desiredSize) { - int displayWidth = window.getFramebufferWidth(); - int displayHeight = window.getFramebufferHeight(); - - int size = minimum(displayHeight, displayWidth, desiredSize); - renderer = TileRenderer.forSize(desiredSize, size); - - /* Push Stack */ - RenderSystem.pushMatrix(); - - /* Setup Projection */ - Rendering.setupOverlayRendering(renderer); - - /* Setup Lighting */ - RenderHelper.setupGui3DDiffuseLighting(); - - /* Scale based on desired size */ - float scale = desiredSize / 16f; - RenderSystem.translatef(0, 0, -scale * 100); - RenderSystem.scalef(scale, scale, scale); - - /* Flip culling due to the flipped projection */ - GL11.glCullFace(GL11.GL_FRONT); - - /* Modify zLevel */ - oldZLevel = itemRenderer.zLevel; - itemRenderer.zLevel = -50; - } - - @Override - public void render(ItemStack value) { - /* Clear Pixel Buffer */ - renderer.buffer.clear(); - - /* Force Glint to be the same between renders by changing nano supplier */ - LongSupplier oldSupplier = Util.nanoTimeSupplier; - Util.nanoTimeSupplier = () -> 0L; - - do { - renderer.beginTile(); - RenderSystem.pushMatrix(); - - /* Clear Framebuffer */ - RenderSystem.clearColor(0, 0, 0, 0); - RenderSystem.clear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT, Minecraft.IS_RUNNING_ON_MAC); - - /* Render */ - itemRenderer.renderItemAndEffectIntoGUI(value, 0, 0); - - RenderSystem.popMatrix(); - } while (renderer.endTile()); - - /* Reset nano supplier */ - Util.nanoTimeSupplier = oldSupplier; - } - - @Override - public void teardown() { - /* Reset zLevel */ - itemRenderer.zLevel = oldZLevel; - - /* Reset Culling */ - GL11.glCullFace(GL11.GL_BACK); - - /* Pop Stack */ - RenderSystem.popMatrix(); - } - - @Override - @Nullable - public TileRenderer getRenderer() { - return renderer; - } - - @Override - public ResourceLocation getId(ItemStack value) { - ResourceLocation identifier = ForgeRegistries.ITEMS.getKey(value.getItem()); - - if (identifier == null) return new ResourceLocation("air"); - - return identifier; - } - - @Override - public ITextComponent getName(ItemStack value) { - return value.getDisplayName(); - } - - @Override - public void renderTooltip(MatrixStack stack, ItemStack value, int displayWidth, int displayHeight) { - List list = getTooltipFromItem(value); - // This code is copied from the tooltip renderer, so we can properly center it. - FontRenderer font = value.getItem().getFontRenderer(value); - if (font == null) font = client.fontRenderer; - - int width = 0; - for (ITextProperties s : list) { - int j = font.func_238414_a_(s); - if (j > width) width = j; - } - // End copied code. - - RenderSystem.translatef((displayWidth - width / 2f) - 12, displayHeight + 30, 0); - Rendering.drawHoveringText(stack, list, 0, 0); - } - -} diff --git a/src/main/java/com/unascribed/blockrenderer/render/impl/package-info.java b/src/main/java/com/unascribed/blockrenderer/render/impl/package-info.java deleted file mode 100644 index 7fff82d..0000000 --- a/src/main/java/com/unascribed/blockrenderer/render/impl/package-info.java +++ /dev/null @@ -1,7 +0,0 @@ -@MethodsReturnNonnullByDefault -@ParametersAreNonnullByDefault -package com.unascribed.blockrenderer.render.impl; - -import com.unascribed.blockrenderer.annotation.MethodsReturnNonnullByDefault; - -import javax.annotation.ParametersAreNonnullByDefault; \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/render/package-info.java b/src/main/java/com/unascribed/blockrenderer/render/package-info.java deleted file mode 100644 index 328300a..0000000 --- a/src/main/java/com/unascribed/blockrenderer/render/package-info.java +++ /dev/null @@ -1,7 +0,0 @@ -@MethodsReturnNonnullByDefault -@ParametersAreNonnullByDefault -package com.unascribed.blockrenderer.render; - -import com.unascribed.blockrenderer.annotation.MethodsReturnNonnullByDefault; - -import javax.annotation.ParametersAreNonnullByDefault; \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/render/request/IRequest.java b/src/main/java/com/unascribed/blockrenderer/render/request/IRequest.java deleted file mode 100644 index 7111b29..0000000 --- a/src/main/java/com/unascribed/blockrenderer/render/request/IRequest.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.unascribed.blockrenderer.render.request; - -public interface IRequest { - - void render(); - -} diff --git a/src/main/java/com/unascribed/blockrenderer/render/request/item/BulkItemRequest.java b/src/main/java/com/unascribed/blockrenderer/render/request/item/BulkItemRequest.java deleted file mode 100644 index 02a0a8b..0000000 --- a/src/main/java/com/unascribed/blockrenderer/render/request/item/BulkItemRequest.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.unascribed.blockrenderer.render.request.item; - -import com.google.common.base.Joiner; -import com.unascribed.blockrenderer.render.BulkRenderer; -import com.unascribed.blockrenderer.render.impl.ItemStackRenderer; -import com.unascribed.blockrenderer.render.request.IRequest; -import net.minecraft.item.ItemStack; - -import java.util.List; -import java.util.Set; - -import static com.unascribed.blockrenderer.utils.MiscUtils.collectStacks; -import static com.unascribed.blockrenderer.utils.StringUtils.getNamespaces; - -public class BulkItemRequest implements IRequest { - - private final int size; - private final String namespaceSpec; - private final boolean useId; - private final boolean addSize; - - public BulkItemRequest(int size, String namespaceSpec, boolean useId, boolean addSize) { - this.size = size; - this.namespaceSpec = namespaceSpec; - this.useId = useId; - this.addSize = addSize; - } - - public void render() { - Set namespaces = getNamespaces(namespaceSpec); - List renders = collectStacks(namespaces); - String joined = Joiner.on(", ").join(namespaces); - - BulkRenderer.bulkRender(new ItemStackRenderer(), joined, renders, size, useId, addSize); - } - -} diff --git a/src/main/java/com/unascribed/blockrenderer/render/request/item/ItemRequest.java b/src/main/java/com/unascribed/blockrenderer/render/request/item/ItemRequest.java deleted file mode 100644 index 7ea1280..0000000 --- a/src/main/java/com/unascribed/blockrenderer/render/request/item/ItemRequest.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.unascribed.blockrenderer.render.request.item; - -import com.unascribed.blockrenderer.render.SingleRenderer; -import com.unascribed.blockrenderer.render.impl.ItemStackRenderer; -import com.unascribed.blockrenderer.render.request.IRequest; -import net.minecraft.item.ItemStack; - -public class ItemRequest implements IRequest { - - private final int size; - private final ItemStack stack; - private final boolean useId; - private final boolean addSize; - - public ItemRequest(int size, ItemStack stack, boolean useId, boolean addSize) { - this.size = size; - this.stack = stack; - this.useId = useId; - this.addSize = addSize; - } - - public void render() { - SingleRenderer.render(new ItemStackRenderer(), stack, size, useId, addSize); - } - -} diff --git a/src/main/java/com/unascribed/blockrenderer/render/request/item/package-info.java b/src/main/java/com/unascribed/blockrenderer/render/request/item/package-info.java deleted file mode 100644 index 88a32f0..0000000 --- a/src/main/java/com/unascribed/blockrenderer/render/request/item/package-info.java +++ /dev/null @@ -1,7 +0,0 @@ -@MethodsReturnNonnullByDefault -@ParametersAreNonnullByDefault -package com.unascribed.blockrenderer.render.request.item; - -import com.unascribed.blockrenderer.annotation.MethodsReturnNonnullByDefault; - -import javax.annotation.ParametersAreNonnullByDefault; \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/render/request/package-info.java b/src/main/java/com/unascribed/blockrenderer/render/request/package-info.java deleted file mode 100644 index d5221cc..0000000 --- a/src/main/java/com/unascribed/blockrenderer/render/request/package-info.java +++ /dev/null @@ -1,7 +0,0 @@ -@MethodsReturnNonnullByDefault -@ParametersAreNonnullByDefault -package com.unascribed.blockrenderer.render.request; - -import com.unascribed.blockrenderer.annotation.MethodsReturnNonnullByDefault; - -import javax.annotation.ParametersAreNonnullByDefault; \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/screens/BaseScreen.java b/src/main/java/com/unascribed/blockrenderer/screens/BaseScreen.java deleted file mode 100644 index ab800c0..0000000 --- a/src/main/java/com/unascribed/blockrenderer/screens/BaseScreen.java +++ /dev/null @@ -1,110 +0,0 @@ -package com.unascribed.blockrenderer.screens; - -import com.mojang.blaze3d.matrix.MatrixStack; -import com.unascribed.blockrenderer.screens.widgets.HoverableCheckboxWidget; -import com.unascribed.blockrenderer.screens.widgets.HoverableTinyButtonWidget; -import com.unascribed.blockrenderer.screens.widgets.UpdateableSliderWidget; -import com.unascribed.blockrenderer.screens.widgets.options.ExtendedSliderPercentageOption; -import com.unascribed.blockrenderer.utils.MathUtils; -import net.minecraft.client.GameSettings; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.gui.widget.Widget; -import net.minecraft.client.gui.widget.button.Button; -import net.minecraft.client.gui.widget.button.CheckboxButton; -import net.minecraft.util.math.MathHelper; -import net.minecraft.util.text.ITextComponent; -import net.minecraft.util.text.TranslationTextComponent; -import org.lwjgl.glfw.GLFW; - -import javax.annotation.Nullable; - -public abstract class BaseScreen extends Screen { - - private static final int MIN_SIZE = 16; - private static final int THRESHOLD = 32; - private static final int MAX_SIZE = 2048; - - protected final Screen old; - - protected double size = 512; - - protected UpdateableSliderWidget slider; - protected Button actualSize; - protected Button renderButton; - protected CheckboxButton useId; - protected CheckboxButton addSize; - - public BaseScreen(ITextComponent title, @Nullable Screen old) { - super(title); - this.old = old; - } - - @Override - public void init() { - assert minecraft != null; - boolean enabled = minecraft.world != null; - - addButton(new Button(width/2-100, height/6+120, 98, 20, new TranslationTextComponent("gui.cancel"), button -> minecraft.displayGuiScreen(old))); - - renderButton = addButton(new Button(width/2+2, height/6+120, 98, 20, new TranslationTextComponent("block_renderer.gui.render"), this::onRender), enabled); - - size = MathHelper.clamp(size, MIN_SIZE, MAX_SIZE); - - ExtendedSliderPercentageOption option = new ExtendedSliderPercentageOption("block_renderer.gui.renderSize", MIN_SIZE, MAX_SIZE, 1, (settings) -> size, (settings, value) -> size = round(value), this::getSliderDisplay); - slider = addButton(new UpdateableSliderWidget(minecraft.gameSettings, width/2-100, height/6+80, 200, 20, option), enabled); - - actualSize = addButton(new HoverableTinyButtonWidget(this, width/2+104, height/6+80, new TranslationTextComponent("block_renderer.gui.actualSize"), new TranslationTextComponent("block_renderer.gui.actualSize.tooltip"), button -> slider.update((int) minecraft.getMainWindow().getGuiScaleFactor() * 16)), enabled); - useId = addButton(new HoverableCheckboxWidget(this, width/2-100, height / 6 + 144, 98, 20, new TranslationTextComponent("block_renderer.gui.useId"), new TranslationTextComponent("block_renderer.gui.useId.tooltip"), false), enabled); - addSize = addButton(new HoverableCheckboxWidget(this, width/2+2, height / 6 + 144, 98, 20, new TranslationTextComponent("block_renderer.gui.addSize"), new TranslationTextComponent("block_renderer.gui.addSize.tooltip"), false), enabled); - } - - protected int round(double value) { - return MathUtils.roundAndClamp(value, MIN_SIZE, MAX_SIZE, THRESHOLD); - } - - @Override - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { - if (keyCode == GLFW.GLFW_KEY_ENTER && renderButton.visible) { - onRender(renderButton); - return true; - } - - return super.keyPressed(keyCode, scanCode, modifiers); - } - - @Override - public void render(MatrixStack stack, int mouseX, int mouseY, float partialTicks) { - assert minecraft != null; - - renderBackground(stack); - - super.render(stack, mouseX, mouseY, partialTicks); - - drawCenteredString(stack, minecraft.fontRenderer, title, width/2, height/6, -1); - - for (Widget widget : buttons) - if (widget.isHovered()) - widget.renderToolTip(stack, mouseX, mouseY); - - if (minecraft.world != null) return; - - drawCenteredString(stack, minecraft.fontRenderer, new TranslationTextComponent("block_renderer.gui.noWorld"), width/2, height/6+30, 0xFF5555); - } - - abstract void onRender(Button button); - - public ITextComponent getSliderDisplay(GameSettings settings, ExtendedSliderPercentageOption option) { - int px = round(size); - return option.getDisplayPrefix().copyRaw().appendString(": " + px + "x" + px); - } - - protected T addButton(T button, boolean active) { - addButton(button); - - button.active = active; - button.visible = active; - - return button; - } - -} diff --git a/src/main/java/com/unascribed/blockrenderer/screens/EnterNamespaceScreen.java b/src/main/java/com/unascribed/blockrenderer/screens/EnterNamespaceScreen.java deleted file mode 100644 index 7a56584..0000000 --- a/src/main/java/com/unascribed/blockrenderer/screens/EnterNamespaceScreen.java +++ /dev/null @@ -1,96 +0,0 @@ -package com.unascribed.blockrenderer.screens; - -import com.mojang.blaze3d.matrix.MatrixStack; -import com.unascribed.blockrenderer.BlockRenderer; -import com.unascribed.blockrenderer.render.request.item.BulkItemRequest; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.gui.widget.TextFieldWidget; -import net.minecraft.client.gui.widget.button.Button; -import net.minecraft.util.text.TranslationTextComponent; - -import javax.annotation.Nullable; - -public class EnterNamespaceScreen extends BaseScreen { - - private static final TranslationTextComponent TITLE = new TranslationTextComponent("block_renderer.gui.namespace"); - - private boolean emptySpec = false; - - private final String prefill; - - private TextFieldWidget text; - - public EnterNamespaceScreen(@Nullable Screen old, String prefill) { - super(TITLE, old); - this.prefill = prefill; - } - - @Override - public void init() { - assert minecraft != null; - minecraft.keyboardListener.enableRepeatEvents(true); - - boolean enabled = minecraft.world != null; - - String oldText = (text == null ? prefill : text.getText()); - - text = addButton(new TextFieldWidget(minecraft.fontRenderer, width/2-100, height/6+50, 200, 20, new TranslationTextComponent("block_renderer.gui.namespace")), enabled); - text.setResponder((value) -> emptySpec = value.trim().isEmpty()); - text.setText(oldText); - text.setCanLoseFocus(false); - setFocusedDefault(text); - - super.init(); - - renderButton.visible = !emptySpec; - } - - @Override - public void tick() { - super.tick(); - text.tick(); - renderButton.visible = !emptySpec; - } - - @Override - public void onClose() { - assert minecraft != null; - minecraft.keyboardListener.enableRepeatEvents(false); - } - - @Override - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { - if (text.keyPressed(keyCode, scanCode, modifiers)) return true; - return super.keyPressed(keyCode, scanCode, modifiers); - } - - @Override - public boolean mouseClicked(double mouseX, double mouseY, int p_231044_5_) { - if (text.mouseClicked(mouseX, mouseY, p_231044_5_)) return true; - - return super.mouseClicked(mouseX, mouseY, p_231044_5_); - } - - @Override - public void render(MatrixStack stack, int mouseX, int mouseY, float partialTicks) { - assert minecraft != null; - - super.render(stack, mouseX, mouseY, partialTicks); - - if (!emptySpec) return; - - drawCenteredString(stack, minecraft.fontRenderer, new TranslationTextComponent("block_renderer.gui.emptySpec"), width/2, height/6+30, 0xFF5555); - } - - @Override - void onRender(Button button) { - assert minecraft != null; - - if (!renderButton.visible) return; - - minecraft.displayGuiScreen(old); - if (minecraft.world == null) return; - - BlockRenderer.proxy.render(new BulkItemRequest(round(size), text.getText(), useId.isChecked(), addSize.isChecked())); - } -} diff --git a/src/main/java/com/unascribed/blockrenderer/screens/EnterSizeScreen.java b/src/main/java/com/unascribed/blockrenderer/screens/EnterSizeScreen.java deleted file mode 100644 index 58124ca..0000000 --- a/src/main/java/com/unascribed/blockrenderer/screens/EnterSizeScreen.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.unascribed.blockrenderer.screens; - -import com.unascribed.blockrenderer.BlockRenderer; -import com.unascribed.blockrenderer.render.request.item.ItemRequest; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.gui.widget.button.Button; -import net.minecraft.item.ItemStack; -import net.minecraft.util.text.TranslationTextComponent; - -import javax.annotation.Nullable; - -public class EnterSizeScreen extends BaseScreen { - - private static final TranslationTextComponent TITLE = new TranslationTextComponent("block_renderer.gui.renderItem"); - - private final ItemStack stack; - - public EnterSizeScreen(@Nullable Screen old, ItemStack stack) { - super(TITLE, old); - this.stack = stack; - } - - @Override - public void init() { - super.init(); - slider.y = height / 6 + 50; - actualSize.y = height / 6 + 50; - } - - @Override - void onRender(Button button) { - assert minecraft != null; - - minecraft.displayGuiScreen(old); - if (minecraft.world == null) return; - - BlockRenderer.proxy.render(new ItemRequest(round(size), stack, useId.isChecked(), addSize.isChecked())); - } -} diff --git a/src/main/java/com/unascribed/blockrenderer/screens/package-info.java b/src/main/java/com/unascribed/blockrenderer/screens/package-info.java deleted file mode 100644 index 05e7965..0000000 --- a/src/main/java/com/unascribed/blockrenderer/screens/package-info.java +++ /dev/null @@ -1,7 +0,0 @@ -@MethodsReturnNonnullByDefault -@ParametersAreNonnullByDefault -package com.unascribed.blockrenderer.screens; - -import com.unascribed.blockrenderer.annotation.MethodsReturnNonnullByDefault; - -import javax.annotation.ParametersAreNonnullByDefault; \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/screens/widgets/package-info.java b/src/main/java/com/unascribed/blockrenderer/screens/widgets/package-info.java deleted file mode 100644 index 155fcfd..0000000 --- a/src/main/java/com/unascribed/blockrenderer/screens/widgets/package-info.java +++ /dev/null @@ -1,7 +0,0 @@ -@MethodsReturnNonnullByDefault -@ParametersAreNonnullByDefault -package com.unascribed.blockrenderer.screens.widgets; - -import com.unascribed.blockrenderer.annotation.MethodsReturnNonnullByDefault; - -import javax.annotation.ParametersAreNonnullByDefault; \ No newline at end of file diff --git a/src/main/java/com/unascribed/blockrenderer/utils/FileUtils.java b/src/main/java/com/unascribed/blockrenderer/utils/FileUtils.java deleted file mode 100644 index 1bed901..0000000 --- a/src/main/java/com/unascribed/blockrenderer/utils/FileUtils.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.unascribed.blockrenderer.utils; - -import java.io.File; - -public interface FileUtils { - - static File getFile(File folder, String filename) { - File file = new File(folder, filename+".png"); - - int i = 2; - while (file.exists()) { - file = new File(folder, filename+"_"+i+".png"); - i++; - } - - return file; - } - -} diff --git a/src/main/java/com/unascribed/blockrenderer/utils/ImageUtils.java b/src/main/java/com/unascribed/blockrenderer/utils/ImageUtils.java deleted file mode 100644 index e8befe8..0000000 --- a/src/main/java/com/unascribed/blockrenderer/utils/ImageUtils.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.unascribed.blockrenderer.utils; - -import com.unascribed.blockrenderer.lib.TileRenderer; - -import java.awt.image.BufferedImage; - -public interface ImageUtils { - - static BufferedImage readPixels(TileRenderer renderer) { - int width = renderer.imageWidth; - int height = renderer.imageHeight; - - BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); - - int[] pixels = new int[width*height]; - - renderer.buffer.asIntBuffer().get(pixels); - - img.setRGB(0, 0, width, height, pixels, 0, width); - - return img; - } - -} diff --git a/src/main/java/com/unascribed/blockrenderer/utils/Rendering.java b/src/main/java/com/unascribed/blockrenderer/utils/Rendering.java deleted file mode 100644 index 95978b2..0000000 --- a/src/main/java/com/unascribed/blockrenderer/utils/Rendering.java +++ /dev/null @@ -1,93 +0,0 @@ -package com.unascribed.blockrenderer.utils; - -import com.mojang.blaze3d.matrix.MatrixStack; -import com.mojang.blaze3d.systems.RenderSystem; -import com.unascribed.blockrenderer.lib.TileRenderer; -import net.minecraft.client.MainWindow; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.AbstractGui; -import net.minecraft.client.gui.FontRenderer; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.item.ItemStack; -import net.minecraft.util.text.ITextComponent; -import net.minecraft.util.text.StringTextComponent; -import org.lwjgl.opengl.GL11; - -import java.util.List; - -import static com.unascribed.blockrenderer.Reference.NAME; - -/** - * Static versions of AbstractGui and Screen utility methods. - */ -public interface Rendering { - class DummyScreen extends Screen { - - protected DummyScreen() { - super(new StringTextComponent(NAME + " Dummy Screen")); - } - - @Override - public List getTooltipFromItem(ItemStack p_231151_1_) { - return super.getTooltipFromItem(p_231151_1_); - } - } - - DummyScreen GUI = new DummyScreen(); - - - static void drawCenteredString(MatrixStack stack, FontRenderer fontRendererIn, String text, int x, int y, int color) { - GUI.drawCenteredString(stack, fontRendererIn, text, x, y, color); - } - - static void drawRect(MatrixStack stack, int left, int top, int right, int bottom, int color) { - AbstractGui.fill(stack, left, top, right, bottom, color); - } - - static void drawHoveringText(MatrixStack stack, List textLines, int x, int y) { - GUI.renderTooltip(stack, textLines, x, y); - } - - static void drawHoveringText(Screen owner, MatrixStack stack, List textLines, int x, int y) { - GUI.init(Minecraft.getInstance(), owner.width, owner.height); - GUI.renderTooltip(stack, textLines, x, y); - } - - static void drawBackground(int width, int height) { - GUI.init(Minecraft.getInstance(), width, height); - GUI.renderDirtBackground(0); - } - - static void setupOverlayRendering() { - Minecraft client = Minecraft.getInstance(); - MainWindow window = client.getMainWindow(); - double scaleFactor = window.getGuiScaleFactor(); - - RenderSystem.clear(GL11.GL_DEPTH_BUFFER_BIT, Minecraft.IS_RUNNING_ON_MAC); - RenderSystem.matrixMode(GL11.GL_PROJECTION); - RenderSystem.loadIdentity(); - RenderSystem.ortho(0.0D, window.getFramebufferWidth() / scaleFactor, window.getFramebufferHeight() / scaleFactor, 0.0D, 1000.0D, 3000.0D); - RenderSystem.matrixMode(GL11.GL_MODELVIEW); - RenderSystem.loadIdentity(); - RenderSystem.translatef(0.0F, 0.0F, -2000.0F); - } - - static void setupOverlayRendering(TileRenderer renderer) { - RenderSystem.clear(GL11.GL_DEPTH_BUFFER_BIT, Minecraft.IS_RUNNING_ON_MAC); - - /* Projection */ - RenderSystem.matrixMode(GL11.GL_PROJECTION); - RenderSystem.loadIdentity(); - - /* We flip the bottom and top parameters here so we don't need to process the image just fix a culling issue */ - /* This results in a minor speed up / lower memory usage */ - renderer.ortho(0.0D, renderer.imageWidth, 0.0D, renderer.imageHeight, 1000.0D, 3000.0D); - - /* Model View */ - RenderSystem.matrixMode(GL11.GL_MODELVIEW); - RenderSystem.loadIdentity(); - RenderSystem.translatef(0.0F, 0.0F, -2000.0F); - } - - -} diff --git a/src/main/java/com/unascribed/blockrenderer/utils/package-info.java b/src/main/java/com/unascribed/blockrenderer/utils/package-info.java deleted file mode 100644 index 34096eb..0000000 --- a/src/main/java/com/unascribed/blockrenderer/utils/package-info.java +++ /dev/null @@ -1,7 +0,0 @@ -@MethodsReturnNonnullByDefault -@ParametersAreNonnullByDefault -package com.unascribed.blockrenderer.utils; - -import com.unascribed.blockrenderer.annotation.MethodsReturnNonnullByDefault; - -import javax.annotation.ParametersAreNonnullByDefault; \ No newline at end of file diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index 24589e3..915baf9 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -3,24 +3,23 @@ license = "MIT License" loaderVersion = "[32,33)" issueTrackerURL = "https://github.com/AterAnimAvis/BlockRenderer/issues" [[mods]] -modId = "block_renderer" -version = "${file.jarVersion}" -displayName = "BlockRenderer" -displayURL = "https://unascribed.com" -logoFile = "logo-blockrenderer.png" -credits = "Una, xbony2, modmuss50, AterAnimAvis, Brian Paul (TR Library)" -authors = "Una" -description = "It renders blocks and items." - + modId = "block_renderer" + version = "${file.jarVersion}" + displayName = "BlockRenderer" + displayURL = "https://unascribed.com" + logoFile = "logo-blockrenderer.png" + credits = "Una, xbony2, modmuss50, AterAnimAvis, Brian Paul (TR Library)" + authors = "Una" + description = "It renders blocks and items." [[dependencies.block_renderer]] -modId = "forge" -mandatory = true -versionRange = "[32,33)" -ordering = "NONE" -side = "BOTH" + modId = "forge" + mandatory = true + versionRange = "[32,33)" + ordering = "NONE" + side = "BOTH" [[dependencies.block_renderer]] -modId = "minecraft" -mandatory = true -versionRange = "[1.16.1]" -ordering = "NONE" -side = "BOTH" + modId = "minecraft" + mandatory = true + versionRange = "[1.16.1]" + ordering = "NONE" + side = "BOTH" diff --git a/src/main/resources/assets/block_renderer/lang/en_us.json b/src/main/resources/assets/block_renderer/lang/en_us.json index d9ecc85..256ec8b 100644 --- a/src/main/resources/assets/block_renderer/lang/en_us.json +++ b/src/main/resources/assets/block_renderer/lang/en_us.json @@ -19,8 +19,22 @@ "block_renderer.gui.renderItem":"Render Item", "block_renderer.gui.namespace":"Enter Namespace", + "block_renderer.gui.renderAnimated":"Render Animated Item", + "block_renderer.gui.map":"Render Map", "block_renderer.gui.noWorld":"You must be in a world to render items", + "block_renderer.gui.noMapData":"Couldn't get data for Map", "block_renderer.gui.emptySpec":"You need to enter a Namespace", + "block_renderer.gui.map.decorations.none": "No Decorations", + "block_renderer.gui.map.decorations.default": "Default Decorations", + "block_renderer.gui.map.decorations.all": "All Decorations", + + "block_renderer.gui.choose":"Choose Renderer", + "block_renderer.gui.choose.item":"Item Renderer", + "block_renderer.gui.choose.map":"Map Renderer", + "block_renderer.gui.choose.animated":"Animated Renderer", + "block_renderer.gui.choose.item.tooltip":"Item Renderer", + "block_renderer.gui.choose.map.tooltip":"Map Renderer (Requires Map)", + "block_renderer.gui.choose.animated.tooltip":"Animated Renderer", "block_renderer.gui.render":"Render", "block_renderer.gui.renderSize":"Size", @@ -28,9 +42,18 @@ "block_renderer.gui.useId":"Identifier", "block_renderer.gui.addSize":"Size", "block_renderer.gui.actualSize":"Actual Size", + "block_renderer.gui.loop":"Auto Loop", + "block_renderer.gui.animatedLength": "Animation Length", "block_renderer.gui.useId.tooltip":"Use Identifier for Filename", "block_renderer.gui.addSize.tooltip":"Add Size to Filename", "block_renderer.gui.actualSize.tooltip":"Set to actual size (Based on GUI Scale)", + "block_renderer.gui.loop.tooltip":"Find looping point (Up to 30 Seconds)", + "block_renderer.gui.animatedLength.tooltip": "Animation Length", + + "block_renderer.gui.switch.single": "Single Render", + "block_renderer.gui.switch.single.tooltip": "Switch to Single Render", + "block_renderer.gui.switch.bulk": "Bulk Render", + "block_renderer.gui.switch.bulk.tooltip": "Switch to Bulk Render", "block_renderer.gui.rendering":"Rendering %1$s entries from %2$s", "block_renderer.gui.rendered":"Rendered %1$s entries from %2$s", diff --git a/src/main/resources/assets/block_renderer/textures/gui/widgets.png b/src/main/resources/assets/block_renderer/textures/gui/widgets.png new file mode 100644 index 0000000..7c01583 Binary files /dev/null and b/src/main/resources/assets/block_renderer/textures/gui/widgets.png differ diff --git a/utils.gradle.kts b/utils.gradle.kts new file mode 100644 index 0000000..d71a1d2 --- /dev/null +++ b/utils.gradle.kts @@ -0,0 +1,62 @@ +/* Based on: https://stackoverflow.com/a/40091450 */ +tasks.create("generatePackageInfos") { + group = "utility" + description = "Generates package-info.java for all directories" + + // Never UP-TO-DATE + outputs.upToDateWhen { false } + + doLast { + val sourceDirectory = file(_Paths.get(projectDir.absolutePath, "src", "main", "java")) + + recurseDirectories(listOf(sourceDirectory)) { directory -> + // If file contains java source files + if (directory.list { _, name -> name.endsWith(".java") }!!.isEmpty()) return@recurseDirectories + println("Visiting: $directory") + + val packageInfo = File(directory, "package-info.java") + // And package-info.java doesn't exist + if (packageInfo.exists()) return@recurseDirectories + + // Create package-info.java + println("Creating: $packageInfo") + _Files.newBufferedWriter(packageInfo.toPath()).use { + it.write(generatePackageInfo(getPackageName(sourceDirectory, directory))) + } + } + } +} + +fun generatePackageInfo(packageName: String) = + """|@NonnullDefault + |package $packageName; + | + |import org.lwjgl.system.NonnullDefault; + """.trimMargin("|") + +typealias _Files = java.nio.file.Files +typealias _Paths = java.nio.file.Paths + +tailrec fun recurseDirectories(directories: List, callback: (File) -> Unit) { + val next = mutableListOf() + directories.forEach { directory -> + directory.listFiles()!!.forEach directory@{ + if (!it.isDirectory) return@directory + callback(it) + next += it + } + } + + if (next.isEmpty()) return + + recurseDirectories(next, callback) +} + +fun getPackageName(root: File, current: File): String { + val src = root.absolutePath + val cur = current.absolutePath + + val prefix = cur.indexOf(src) + val result = cur.substring(prefix + src.length).replace("\\", "/") + return result.replace("/", ".").removePrefix(".") +} \ No newline at end of file