From 1a61dc470cf7c4a04f64a08f84d19b081781c27e Mon Sep 17 00:00:00 2001 From: Talia-12 Date: Mon, 27 Nov 2023 19:53:57 +1000 Subject: [PATCH 1/6] copied over Nitero's texture-based pattern rendering implementation to the 1.20 branch and fixed it up to work in this version (https://github.com/FallingColors/HexMod/commit/f5a76ed0cd5724f08b6bda874e044e8732abf0ad) --- .../client/entity/WallScrollRenderer.java | 9 +- .../client/render/HexPatternPoints.java | 15 + .../client/render/PatternTextureManager.java | 307 ++++++++++++++++++ .../BlockEntityAkashicBookshelfRenderer.java | 8 + .../render/be/BlockEntitySlateRenderer.java | 11 +- .../akashic/BlockEntityAkashicBookshelf.java | 3 + .../blocks/circles/BlockEntitySlate.java | 2 + .../command/PatternTexturesCommand.java | 40 +++ .../common/entities/EntityWallScroll.java | 10 +- .../hexcasting/common/lib/HexCommands.java | 2 + Forge/gradle.properties | 2 +- 11 files changed, 401 insertions(+), 8 deletions(-) create mode 100644 Common/src/main/java/at/petrak/hexcasting/client/render/HexPatternPoints.java create mode 100644 Common/src/main/java/at/petrak/hexcasting/client/render/PatternTextureManager.java create mode 100644 Common/src/main/java/at/petrak/hexcasting/common/command/PatternTexturesCommand.java diff --git a/Common/src/main/java/at/petrak/hexcasting/client/entity/WallScrollRenderer.java b/Common/src/main/java/at/petrak/hexcasting/client/entity/WallScrollRenderer.java index 269366d5d..351acbef7 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/entity/WallScrollRenderer.java +++ b/Common/src/main/java/at/petrak/hexcasting/client/entity/WallScrollRenderer.java @@ -1,5 +1,6 @@ package at.petrak.hexcasting.client.entity; +import at.petrak.hexcasting.client.render.PatternTextureManager; import at.petrak.hexcasting.client.render.RenderLib; import at.petrak.hexcasting.common.entities.EntityWallScroll; import com.mojang.blaze3d.systems.RenderSystem; @@ -97,10 +98,14 @@ public void render(EntityWallScroll wallScroll, float yaw, float partialTicks, P vertex(mat, norm, light, verts, dx, dy, dz, 1, 1 - margin, 0, 1, 0); ps.popPose(); + + if (PatternTextureManager.useTextures && wallScroll.points != null) + PatternTextureManager.renderPatternForScroll(wallScroll.points.pointsKey, ps, bufSource, light, wallScroll.points.zappyPoints, wallScroll.blockSize, wallScroll.getShowsStrokeOrder()); } - if (wallScroll.zappyPoints != null) { - var points = wallScroll.zappyPoints; + //TODO: remove old rendering if not needed anymore for comparison + if (!PatternTextureManager.useTextures && wallScroll.points != null) { + var points = wallScroll.points.zappyPoints; ps.pushPose(); ps.mulPose(Axis.YP.rotationDegrees(180f)); diff --git a/Common/src/main/java/at/petrak/hexcasting/client/render/HexPatternPoints.java b/Common/src/main/java/at/petrak/hexcasting/client/render/HexPatternPoints.java new file mode 100644 index 000000000..b033e8de3 --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/client/render/HexPatternPoints.java @@ -0,0 +1,15 @@ +package at.petrak.hexcasting.client.render; + +import net.minecraft.world.phys.Vec2; + +import java.util.List; + +public class HexPatternPoints { + public List zappyPoints = null; + public String pointsKey = null; //TODO: if a string key isnt performant enough override hashcode for points + + public HexPatternPoints(List zappyPoints) { + this.zappyPoints = zappyPoints; + pointsKey = PatternTextureManager.getPointsKey(zappyPoints); + } +} \ No newline at end of file diff --git a/Common/src/main/java/at/petrak/hexcasting/client/render/PatternTextureManager.java b/Common/src/main/java/at/petrak/hexcasting/client/render/PatternTextureManager.java new file mode 100644 index 000000000..e92e3ed10 --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/client/render/PatternTextureManager.java @@ -0,0 +1,307 @@ +package at.petrak.hexcasting.client.render; + +import at.petrak.hexcasting.api.block.HexBlockEntity; +import at.petrak.hexcasting.api.casting.math.HexPattern; +import at.petrak.hexcasting.common.blocks.akashic.BlockAkashicBookshelf; +import at.petrak.hexcasting.common.blocks.akashic.BlockEntityAkashicBookshelf; +import at.petrak.hexcasting.common.blocks.circles.BlockEntitySlate; +import at.petrak.hexcasting.common.blocks.circles.BlockSlate; +import com.mojang.blaze3d.platform.NativeImage; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Axis; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.texture.DynamicTexture; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Tuple; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.AttachFace; +import net.minecraft.world.phys.Vec2; +import org.joml.Matrix3f; +import org.joml.Matrix4f; + +import java.awt.*; +import java.awt.image.BufferedImage; +import java.util.HashMap; +import java.util.List; +import java.util.stream.Collectors; + +public class PatternTextureManager { + + //TODO: remove if not needed anymore for comparison + public static boolean useTextures = true; + public static int repaintIndex = 0; + + public static int resolutionByBlockSize = 512; + public static int paddingByBlockSize = 50; + public static int circleRadiusByBlockSize = 8; + public static int scaleLimit = 16; + + private static HashMap patternTextures = new HashMap<>(); + + public static String getPointsKey(List zappyPoints) + { + return zappyPoints.stream() + .map(p -> String.format("(%f,%f)", p.x, p.y)) + .collect(Collectors.joining(";")); + } + + public static HexPatternPoints generateHexPatternPoints(HexBlockEntity tile, HexPattern pattern, float flowIrregular) + { + var stupidHash = tile.getBlockPos().hashCode(); + var lines1 = pattern.toLines(1, Vec2.ZERO); + var zappyPoints = RenderLib.makeZappy(lines1, RenderLib.findDupIndices(pattern.positions()), + 10, 0.5f, 0f, flowIrregular, 0f, 1f, stupidHash); + return new HexPatternPoints(zappyPoints); + } + + public static void renderPatternForScroll(String pointsKey, PoseStack ps, MultiBufferSource bufSource, int light, List zappyPoints, int blockSize, boolean showStrokeOrder) + { + renderPattern(pointsKey, ps, bufSource, light, zappyPoints, blockSize, showStrokeOrder, false, true, false,false, true,-1); + } + public static void renderPatternForSlate(BlockEntitySlate tile, HexPattern pattern, PoseStack ps, MultiBufferSource buffer, int light, BlockState bs) + { + if(tile.points == null) + tile.points = generateHexPatternPoints(tile, pattern, 0.2f); + + boolean isOnWall = bs.getValue(BlockSlate.ATTACH_FACE) == AttachFace.WALL; + boolean isOnCeiling = bs.getValue(BlockSlate.ATTACH_FACE) == AttachFace.CEILING; + int facing = bs.getValue(BlockSlate.FACING).get2DDataValue(); + + renderPatternForBlockEntity(tile.points, ps, buffer, light, isOnWall, isOnCeiling, true, facing); + } + public static void renderPatternForAkashicBookshelf(BlockEntityAkashicBookshelf tile, HexPattern pattern, PoseStack ps, MultiBufferSource buffer, int light, BlockState bs) + { + if(tile.points == null) + tile.points = generateHexPatternPoints(tile, pattern, 0f); + + int facing = bs.getValue(BlockAkashicBookshelf.FACING).get2DDataValue(); + renderPatternForBlockEntity(tile.points, ps, buffer, light, true, false, false, facing); + } + + public static void renderPatternForBlockEntity(HexPatternPoints points, PoseStack ps, MultiBufferSource buffer, int light, boolean isOnWall, boolean isOnCeiling, boolean isSlate, int facing) + { + var oldShader = RenderSystem.getShader(); + ps.pushPose(); + RenderSystem.setShader(GameRenderer::getPositionTexShader); + renderPattern(points.pointsKey, ps, buffer, light, points.zappyPoints, 1, false, true, isOnWall, isOnCeiling, isSlate, false, facing); + ps.popPose(); + RenderSystem.setShader(() -> oldShader); + } + + public static void renderPattern(String pointsKey, PoseStack ps, MultiBufferSource bufSource, int light, List zappyPoints, int blockSize, boolean showStrokeOrder, boolean useFullSize, boolean isOnWall, boolean isOnCeiling, boolean isSlate, boolean isScroll, int facing) + { + ps.pushPose(); + + PoseStack.Pose last = ps.last(); + Matrix4f mat = last.pose(); + Matrix3f normal = last.normal(); + + float x = blockSize, y = blockSize, z = (-1f / 16f) - 0.01f; + float nx = 0, ny = 0, nz = 0; + + //TODO: refactor this mess of a method + + if(isOnWall) + { + if(isScroll) + { + ps.translate(-blockSize / 2f, -blockSize / 2f, 1f / 32f); + nz = -1; + } + else + { + ps.mulPose(Axis.ZP.rotationDegrees(180)); + + if(isSlate) + { + if(facing == 0) + ps.translate(0,-1,0); + if(facing == 1) + ps.translate(-1,-1,0); + if(facing == 2) + ps.translate(-1,-1,1); + if(facing == 3) + ps.translate(0,-1,1); + } + else + { + z = -0.01f; + if(facing == 0) + ps.translate(0,-1,1); + if(facing == 1) + ps.translate(0,-1,0); + if(facing == 2) + ps.translate(-1,-1,0); + if(facing == 3) + ps.translate(-1,-1,1); + } + + if(facing == 0) + ps.mulPose(Axis.YP.rotationDegrees(180)); + if(facing == 1) + ps.mulPose(Axis.YP.rotationDegrees(270)); + if(facing == 3) + ps.mulPose(Axis.YP.rotationDegrees(90)); + + if(facing == 0 || facing == 2) + nz = -1; + if(facing == 1 || facing == 3) + nx = -1; + ps.translate(0,0,0); + } + } + else //slates on the floor or ceiling + { + if(facing == 0) + ps.translate(0,0,0); + if(facing == 1) + ps.translate(1,0,0); + if(facing == 2) + ps.translate(1,0,1); + if(facing == 3) + ps.translate(0,0,1); + ps.mulPose(Axis.YP.rotationDegrees(facing*-90)); + + if(isOnCeiling) + { + ps.mulPose(Axis.XP.rotationDegrees(-90)); + ps.translate(0,-1,1); + } + else + ps.mulPose(Axis.XP.rotationDegrees(90)); + nz = -1; + } + + int lineWidth = 16; + int outerColor = 0xB4B4BE;//0xff_c8c8d2; + int innerColor = 0x2A2A2A;//0xc8_322b33; + if(isScroll) + { + lineWidth = 20; + outerColor = 0xDEDEDE;//0xff_d2c8c8; + innerColor = 0x343434;//0xc8_322b33; + } + + ResourceLocation texture = getTexture(zappyPoints, pointsKey, blockSize, showStrokeOrder, lineWidth, useFullSize, new Color(innerColor), new Color(outerColor)); + VertexConsumer verts = bufSource.getBuffer(RenderType.entityCutout(texture)); + + vertex(mat, normal, light, verts, 0, 0, z, 0, 0, nx, ny, nz); + vertex(mat, normal, light, verts, 0, y, z, 0, 1, nx, ny, nz); + vertex(mat, normal, light, verts, x, y, z, 1, 1, nx, ny, nz); + vertex(mat, normal, light, verts, x, 0, z, 1, 0, nx, ny, nz); + + ps.popPose(); + } + + private static void vertex(Matrix4f mat, Matrix3f normal, int light, VertexConsumer verts, float x, float y, float z, + float u, float v, float nx, float ny, float nz) { + verts.vertex(mat, x, y, z) + .color(0xffffffff) + .uv(u, v).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(light) + .normal(normal, nx, ny, nz) + .endVertex(); + } + + public static ResourceLocation getTexture(List points, String pointsKey, int blockSize, boolean showsStrokeOrder, int lineWidth, boolean useFullSize, Color innerColor, Color outerColor) { + if (patternTextures.containsKey(pointsKey)) + return patternTextures.get(pointsKey); + return createTexture(points, pointsKey, blockSize, showsStrokeOrder, lineWidth, useFullSize, innerColor, outerColor); + } + + public static ResourceLocation createTexture(List points, String pointsKey, int blockSize, boolean showsStrokeOrder, int lineWidth, boolean useFullSize, Color innerColor, Color outerColor) + { + int resolution = resolutionByBlockSize * blockSize; + int padding = paddingByBlockSize * blockSize; + + double minX = Double.MAX_VALUE, maxX = Double.MIN_VALUE, minY = Double.MAX_VALUE, maxY = Double.MIN_VALUE; + for (Vec2 point : points) + { + minX = Math.min(minX, point.x); + maxX = Math.max(maxX, point.x); + minY = Math.min(minY, point.y); + maxY = Math.max(maxY, point.y); + } + + double rangeX = maxX - minX; + double rangeY = maxY - minY; + + double scale = Math.min((resolution - 2 * padding) / rangeX, (resolution - 2 * padding) / rangeY); + + double limit = blockSize * scaleLimit; + if (!useFullSize && scale > limit) + scale = limit; + + double offsetX = ((resolution - 2 * padding) - rangeX * scale) / 2; + double offsetY = ((resolution - 2 * padding) - rangeY * scale) / 2; + + BufferedImage img = new BufferedImage(resolution, resolution, BufferedImage.TYPE_INT_ARGB); + Graphics2D g2d = img.createGraphics(); + + g2d.setColor(outerColor); + g2d.setStroke(new BasicStroke((blockSize * 5f / 3f) * lineWidth, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); + drawLines(g2d, points, minX, minY, scale, offsetX, offsetY, padding); + + g2d.setColor(innerColor); + g2d.setStroke(new BasicStroke((blockSize * 2f / 3f) * lineWidth, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); + drawLines(g2d, points, minX, minY, scale, offsetX, offsetY, padding); + + + if (showsStrokeOrder) { + g2d.setColor(new Color(0xff_d77b5b)); + Tuple point = getTextureCoordinates(points.get(0), minX, minY, scale, offsetX, offsetY, padding); + int spotRadius = circleRadiusByBlockSize * blockSize; + drawHexagon(g2d, point.getA(), point.getB(), spotRadius); + } + + g2d.dispose(); + + NativeImage nativeImage = new NativeImage(img.getWidth(), img.getHeight(), true); + for (int y = 0; y < img.getHeight(); y++) + for (int x = 0; x < img.getWidth(); x++) + nativeImage.setPixelRGBA(x, y, img.getRGB(x, y)); + + DynamicTexture dynamicTexture = new DynamicTexture(nativeImage); + ResourceLocation resourceLocation = Minecraft.getInstance().getTextureManager().register("hex_pattern_texture_" + points.hashCode() + "_" + repaintIndex + ".png", dynamicTexture); + patternTextures.put(pointsKey, resourceLocation); + return resourceLocation; + } + + private static void drawLines(Graphics2D g2d, List points, double minX, double minY, double scale, double offsetX, double offsetY, int padding) { + for (int i = 0; i < points.size() - 1; i++) { + Tuple pointFrom = getTextureCoordinates(points.get(i), minX, minY, scale, offsetX, offsetY, padding); + Tuple pointTo = getTextureCoordinates(points.get(i+1), minX, minY, scale, offsetX, offsetY, padding); + g2d.drawLine(pointFrom.getA(), pointFrom.getB(), pointTo.getA(), pointTo.getB()); + } + } + + private static Tuple getTextureCoordinates(Vec2 point, double minX, double minY, double scale, double offsetX, double offsetY, int padding) { + int x = (int) ((point.x - minX) * scale + offsetX) + padding; + int y = (int) ((point.y - minY) * scale + offsetY) + padding; + return new Tuple(x, y); + } + + private static void drawHexagon(Graphics2D g2d, int x, int y, int radius) { + int fracOfCircle = 6; + Polygon hexagon = new Polygon(); + + for (int i = 0; i < fracOfCircle; i++) { + double theta = (i / (double) fracOfCircle) * Math.PI * 2; + int hx = (int) (x + Math.cos(theta) * radius); + int hy = (int) (y + Math.sin(theta) * radius); + hexagon.addPoint(hx, hy); + } + + g2d.fill(hexagon); + } + + public static void repaint() { + repaintIndex++; + patternTextures.clear(); + } +} \ No newline at end of file diff --git a/Common/src/main/java/at/petrak/hexcasting/client/render/be/BlockEntityAkashicBookshelfRenderer.java b/Common/src/main/java/at/petrak/hexcasting/client/render/be/BlockEntityAkashicBookshelfRenderer.java index 9efdad59c..e9064fb54 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/render/be/BlockEntityAkashicBookshelfRenderer.java +++ b/Common/src/main/java/at/petrak/hexcasting/client/render/be/BlockEntityAkashicBookshelfRenderer.java @@ -1,6 +1,7 @@ package at.petrak.hexcasting.client.render.be; import at.petrak.hexcasting.api.casting.math.HexPattern; +import at.petrak.hexcasting.client.render.PatternTextureManager; import at.petrak.hexcasting.client.render.RenderLib; import at.petrak.hexcasting.common.blocks.akashic.BlockAkashicBookshelf; import at.petrak.hexcasting.common.blocks.akashic.BlockEntityAkashicBookshelf; @@ -31,6 +32,13 @@ public void render(BlockEntityAkashicBookshelf tile, float pPartialTick, PoseSta var bs = tile.getBlockState(); + if(PatternTextureManager.useTextures) { + PatternTextureManager.renderPatternForAkashicBookshelf(tile, pattern, ps, buffer, light, bs); + return; + } + + //TODO: remove old rendering if not needed anymore for comparison + var oldShader = RenderSystem.getShader(); RenderSystem.setShader(GameRenderer::getPositionColorShader); RenderSystem.enableDepthTest(); diff --git a/Common/src/main/java/at/petrak/hexcasting/client/render/be/BlockEntitySlateRenderer.java b/Common/src/main/java/at/petrak/hexcasting/client/render/be/BlockEntitySlateRenderer.java index d355f3af5..52d13e489 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/render/be/BlockEntitySlateRenderer.java +++ b/Common/src/main/java/at/petrak/hexcasting/client/render/be/BlockEntitySlateRenderer.java @@ -1,5 +1,6 @@ package at.petrak.hexcasting.client.render.be; +import at.petrak.hexcasting.client.render.PatternTextureManager; import at.petrak.hexcasting.client.render.RenderLib; import at.petrak.hexcasting.common.blocks.circles.BlockEntitySlate; import at.petrak.hexcasting.common.blocks.circles.BlockSlate; @@ -24,12 +25,18 @@ public BlockEntitySlateRenderer(BlockEntityRendererProvider.Context ctx) { @Override public void render(BlockEntitySlate tile, float pPartialTick, PoseStack ps, MultiBufferSource buffer, int light, int overlay) { - if (tile.pattern == null) { + if (tile.pattern == null) return; - } var bs = tile.getBlockState(); + if(PatternTextureManager.useTextures && !bs.getValue(BlockSlate.ENERGIZED)) { + PatternTextureManager.renderPatternForSlate(tile, tile.pattern, ps, buffer, light, bs); + return; + } + + //TODO: remove old rendering if not needed anymore for comparison + var oldShader = RenderSystem.getShader(); RenderSystem.setShader(GameRenderer::getPositionColorShader); RenderSystem.enableDepthTest(); diff --git a/Common/src/main/java/at/petrak/hexcasting/common/blocks/akashic/BlockEntityAkashicBookshelf.java b/Common/src/main/java/at/petrak/hexcasting/common/blocks/akashic/BlockEntityAkashicBookshelf.java index fe10b7591..d6e4cd804 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/blocks/akashic/BlockEntityAkashicBookshelf.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/blocks/akashic/BlockEntityAkashicBookshelf.java @@ -4,6 +4,7 @@ import at.petrak.hexcasting.api.casting.iota.Iota; import at.petrak.hexcasting.api.casting.iota.IotaType; import at.petrak.hexcasting.api.casting.math.HexPattern; +import at.petrak.hexcasting.client.render.HexPatternPoints; import at.petrak.hexcasting.common.lib.HexBlockEntities; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; @@ -22,6 +23,8 @@ public class BlockEntityAkashicBookshelf extends HexBlockEntity { // For both these cases we save just the tag of the iota. private CompoundTag iotaTag = null; + public HexPatternPoints points; + public BlockEntityAkashicBookshelf(BlockPos pWorldPosition, BlockState pBlockState) { super(HexBlockEntities.AKASHIC_BOOKSHELF_TILE, pWorldPosition, pBlockState); } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/blocks/circles/BlockEntitySlate.java b/Common/src/main/java/at/petrak/hexcasting/common/blocks/circles/BlockEntitySlate.java index 9a0ec965b..63489e8c0 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/blocks/circles/BlockEntitySlate.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/blocks/circles/BlockEntitySlate.java @@ -2,6 +2,7 @@ import at.petrak.hexcasting.api.block.HexBlockEntity; import at.petrak.hexcasting.api.casting.math.HexPattern; +import at.petrak.hexcasting.client.render.HexPatternPoints; import at.petrak.hexcasting.common.lib.HexBlockEntities; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; @@ -14,6 +15,7 @@ public class BlockEntitySlate extends HexBlockEntity { @Nullable public HexPattern pattern; + public HexPatternPoints points; public BlockEntitySlate(BlockPos pos, BlockState state) { super(HexBlockEntities.SLATE_TILE, pos, state); diff --git a/Common/src/main/java/at/petrak/hexcasting/common/command/PatternTexturesCommand.java b/Common/src/main/java/at/petrak/hexcasting/common/command/PatternTexturesCommand.java new file mode 100644 index 000000000..d72a5c4c4 --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/common/command/PatternTexturesCommand.java @@ -0,0 +1,40 @@ +package at.petrak.hexcasting.common.command; + +import at.petrak.hexcasting.client.render.PatternTextureManager; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; + +public class PatternTexturesCommand +{ + public static void add(LiteralArgumentBuilder cmd) { + cmd.then(Commands.literal("textureToggle") + .requires(dp -> dp.hasPermission(Commands.LEVEL_ADMINS)) + .executes(ctx -> { + PatternTextureManager.useTextures = !PatternTextureManager.useTextures; + return 1; + })); + +// cmd.then(Commands.literal("textureSetColor") +// .requires(dp -> dp.hasPermission(Commands.LEVEL_ADMINS)) +// .then(Commands.argument("r", IntegerArgumentType.integer()) +// .then(Commands.argument("g", IntegerArgumentType.integer()) +// .then(Commands.argument("b", IntegerArgumentType.integer()).executes(ctx -> { +// var r = IntegerArgumentType.getInteger(ctx, "r"); +// var g = IntegerArgumentType.getInteger(ctx, "g"); +// var b = IntegerArgumentType.getInteger(ctx, "b"); +// PatternTextureManager.color = new Color(r,g,b,255); +// PatternTextureManager.repaint(); +// return 1; +// }))))); +// +// cmd.then(Commands.literal("textureSetResolution") +// .requires(dp -> dp.hasPermission(Commands.LEVEL_ADMINS)) +// .then(Commands.argument("integer", IntegerArgumentType.integer()).executes(ctx -> { +// var integer = IntegerArgumentType.getInteger(ctx, "integer"); +// PatternTextureManager.resolutionByBlockSize = integer; +// PatternTextureManager.repaint(); +// return 1; +// }))); + } +} \ No newline at end of file diff --git a/Common/src/main/java/at/petrak/hexcasting/common/entities/EntityWallScroll.java b/Common/src/main/java/at/petrak/hexcasting/common/entities/EntityWallScroll.java index 16a8b31c8..cd9ab651c 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/entities/EntityWallScroll.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/entities/EntityWallScroll.java @@ -3,6 +3,7 @@ import at.petrak.hexcasting.api.casting.math.HexPattern; import at.petrak.hexcasting.api.utils.HexUtils; import at.petrak.hexcasting.api.utils.NBTHelper; +import at.petrak.hexcasting.client.render.HexPatternPoints; import at.petrak.hexcasting.client.render.RenderLib; import at.petrak.hexcasting.common.items.storage.ItemScroll; import at.petrak.hexcasting.common.lib.HexItems; @@ -43,11 +44,13 @@ public class EntityWallScroll extends HangingEntity { EntityDataSerializers.BOOLEAN); public ItemStack scroll; + @Nullable public HexPattern pattern; public boolean isAncient; public int blockSize; // Client-side only! - public List zappyPoints; + @Nullable + public HexPatternPoints points; public EntityWallScroll(EntityType type, Level world) { super(type, world); @@ -75,14 +78,15 @@ public void recalculateDisplay() { var dots = pair.getSecond(); var readOffset = this.getShowsStrokeOrder() ? RenderLib.DEFAULT_READABILITY_OFFSET : 0f; var lastProp = this.getShowsStrokeOrder() ? RenderLib.DEFAULT_LAST_SEGMENT_LEN_PROP : 1f; - this.zappyPoints = RenderLib.makeZappy(dots, RenderLib.findDupIndices(pattern.positions()), 10, 0.4f, + var zappyPoints = RenderLib.makeZappy(dots, RenderLib.findDupIndices(pattern.positions()), 10, 0.4f, 0f, 0f, readOffset, lastProp, this.getId()); + this.points = new HexPatternPoints(zappyPoints); } this.isAncient = NBTHelper.hasString(scroll, ItemScroll.TAG_OP_ID); } else { this.pattern = null; - this.zappyPoints = null; + this.points = null; this.isAncient = false; } } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/lib/HexCommands.java b/Common/src/main/java/at/petrak/hexcasting/common/lib/HexCommands.java index 4e4d44181..0a4aca877 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/lib/HexCommands.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/lib/HexCommands.java @@ -2,6 +2,7 @@ import at.petrak.hexcasting.common.command.BrainsweepCommand; import at.petrak.hexcasting.common.command.ListPerWorldPatternsCommand; +import at.petrak.hexcasting.common.command.PatternTexturesCommand; import at.petrak.hexcasting.common.command.RecalcPatternsCommand; import com.mojang.brigadier.CommandDispatcher; import net.minecraft.commands.CommandSourceStack; @@ -14,6 +15,7 @@ public static void register(CommandDispatcher dispatcher) { BrainsweepCommand.add(mainCmd); ListPerWorldPatternsCommand.add(mainCmd); RecalcPatternsCommand.add(mainCmd); + PatternTexturesCommand.add(mainCmd); dispatcher.register(mainCmd); } diff --git a/Forge/gradle.properties b/Forge/gradle.properties index 3dcf2ae01..6ba5b71f6 100644 --- a/Forge/gradle.properties +++ b/Forge/gradle.properties @@ -1,4 +1,4 @@ -forgeVersion=47.1.43 +forgeVersion=47.2.0 kotlinForForgeVersion=4.3.0 From 07dbfc411780ec7d866da5321daac832e6bebdca Mon Sep 17 00:00:00 2001 From: Talia-12 Date: Tue, 28 Nov 2023 22:52:49 +1000 Subject: [PATCH 2/6] muck around with line widths, colours, and resolution of PatternTextureManager. --- .../client/render/PatternTextureManager.java | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/Common/src/main/java/at/petrak/hexcasting/client/render/PatternTextureManager.java b/Common/src/main/java/at/petrak/hexcasting/client/render/PatternTextureManager.java index e92e3ed10..f0c20e9a8 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/render/PatternTextureManager.java +++ b/Common/src/main/java/at/petrak/hexcasting/client/render/PatternTextureManager.java @@ -1,5 +1,6 @@ package at.petrak.hexcasting.client.render; +import at.petrak.hexcasting.api.HexAPI; import at.petrak.hexcasting.api.block.HexBlockEntity; import at.petrak.hexcasting.api.casting.math.HexPattern; import at.petrak.hexcasting.common.blocks.akashic.BlockAkashicBookshelf; @@ -37,10 +38,10 @@ public class PatternTextureManager { public static boolean useTextures = true; public static int repaintIndex = 0; - public static int resolutionByBlockSize = 512; - public static int paddingByBlockSize = 50; - public static int circleRadiusByBlockSize = 8; - public static int scaleLimit = 16; + public static int resolutionByBlockSize = 512*2; + public static int paddingByBlockSize = 64*2; + public static int circleRadiusByBlockSize = 8*2; + public static int scaleLimit = 16*2; private static HashMap patternTextures = new HashMap<>(); @@ -178,14 +179,14 @@ public static void renderPattern(String pointsKey, PoseStack ps, MultiBufferSour nz = -1; } - int lineWidth = 16; - int outerColor = 0xB4B4BE;//0xff_c8c8d2; - int innerColor = 0x2A2A2A;//0xc8_322b33; + int lineWidth = 20*2; + int outerColor = 0xff_c8c8d2; + int innerColor = 0xc8_322b33; if(isScroll) { - lineWidth = 20; - outerColor = 0xDEDEDE;//0xff_d2c8c8; - innerColor = 0x343434;//0xc8_322b33; + lineWidth = 20*2; + outerColor = 0xff_d2c8c8; + innerColor = 0xc8_322b33; } ResourceLocation texture = getTexture(zappyPoints, pointsKey, blockSize, showStrokeOrder, lineWidth, useFullSize, new Color(innerColor), new Color(outerColor)); @@ -233,6 +234,8 @@ public static ResourceLocation createTexture(List points, String pointsKey double scale = Math.min((resolution - 2 * padding) / rangeX, (resolution - 2 * padding) / rangeY); + HexAPI.LOGGER.warn(scale); + double limit = blockSize * scaleLimit; if (!useFullSize && scale > limit) scale = limit; From 590b7cfa10c5335435403bf87d5a72fa9ad70e99 Mon Sep 17 00:00:00 2001 From: Talia-12 Date: Wed, 29 Nov 2023 16:10:16 +1000 Subject: [PATCH 3/6] successfully got the old* and new render styles looking basically-identical by altering the old renderer to match the new (only bothered for slate since its the only one that will toggle back to the old renderer in normal gameplay, and the scroll renderer is a bit more complicated). --- .../client/render/PatternTextureManager.java | 25 +++--- .../render/be/BlockEntitySlateRenderer.java | 76 +++++++++++-------- 2 files changed, 53 insertions(+), 48 deletions(-) diff --git a/Common/src/main/java/at/petrak/hexcasting/client/render/PatternTextureManager.java b/Common/src/main/java/at/petrak/hexcasting/client/render/PatternTextureManager.java index f0c20e9a8..e21baa3a6 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/render/PatternTextureManager.java +++ b/Common/src/main/java/at/petrak/hexcasting/client/render/PatternTextureManager.java @@ -1,6 +1,5 @@ package at.petrak.hexcasting.client.render; -import at.petrak.hexcasting.api.HexAPI; import at.petrak.hexcasting.api.block.HexBlockEntity; import at.petrak.hexcasting.api.casting.math.HexPattern; import at.petrak.hexcasting.common.blocks.akashic.BlockAkashicBookshelf; @@ -38,12 +37,12 @@ public class PatternTextureManager { public static boolean useTextures = true; public static int repaintIndex = 0; - public static int resolutionByBlockSize = 512*2; - public static int paddingByBlockSize = 64*2; - public static int circleRadiusByBlockSize = 8*2; - public static int scaleLimit = 16*2; + public static int resolutionByBlockSize = 1024; + public static int paddingByBlockSize = 128; + public static int circleRadiusByBlockSize = 16; + public static int scaleLimit = 32; - private static HashMap patternTextures = new HashMap<>(); + private static final HashMap patternTextures = new HashMap<>(); public static String getPointsKey(List zappyPoints) { @@ -179,15 +178,11 @@ public static void renderPattern(String pointsKey, PoseStack ps, MultiBufferSour nz = -1; } - int lineWidth = 20*2; - int outerColor = 0xff_c8c8d2; + int lineWidth = 40; + int outerColor = 0xff_d2c8c8; int innerColor = 0xc8_322b33; if(isScroll) - { - lineWidth = 20*2; - outerColor = 0xff_d2c8c8; - innerColor = 0xc8_322b33; - } + lineWidth = 30; ResourceLocation texture = getTexture(zappyPoints, pointsKey, blockSize, showStrokeOrder, lineWidth, useFullSize, new Color(innerColor), new Color(outerColor)); VertexConsumer verts = bufSource.getBuffer(RenderType.entityCutout(texture)); @@ -234,8 +229,6 @@ public static ResourceLocation createTexture(List points, String pointsKey double scale = Math.min((resolution - 2 * padding) / rangeX, (resolution - 2 * padding) / rangeY); - HexAPI.LOGGER.warn(scale); - double limit = blockSize * scaleLimit; if (!useFullSize && scale > limit) scale = limit; @@ -286,7 +279,7 @@ private static void drawLines(Graphics2D g2d, List points, double minX, do private static Tuple getTextureCoordinates(Vec2 point, double minX, double minY, double scale, double offsetX, double offsetY, int padding) { int x = (int) ((point.x - minX) * scale + offsetX) + padding; int y = (int) ((point.y - minY) * scale + offsetY) + padding; - return new Tuple(x, y); + return new Tuple<>(x, y); } private static void drawHexagon(Graphics2D g2d, int x, int y, int radius) { diff --git a/Common/src/main/java/at/petrak/hexcasting/client/render/be/BlockEntitySlateRenderer.java b/Common/src/main/java/at/petrak/hexcasting/client/render/be/BlockEntitySlateRenderer.java index 52d13e489..b9550dbbd 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/render/be/BlockEntitySlateRenderer.java +++ b/Common/src/main/java/at/petrak/hexcasting/client/render/be/BlockEntitySlateRenderer.java @@ -14,8 +14,8 @@ import net.minecraft.util.Mth; import net.minecraft.world.level.block.state.properties.AttachFace; import net.minecraft.world.phys.Vec2; -import org.joml.AxisAngle4f; -import org.joml.Quaternionf; + +import java.util.ArrayList; public class BlockEntitySlateRenderer implements BlockEntityRenderer { public BlockEntitySlateRenderer(BlockEntityRendererProvider.Context ctx) { @@ -56,49 +56,61 @@ public void render(BlockEntitySlate tile, float pPartialTick, PoseStack ps, ps.mulPose(Axis.ZP.rotation(neg * Mth.HALF_PI * quarters)); } + // Resolution is the number of sub-voxels in the block for rendering purposes, 16 is the default + // padding is the space to leave on the edges free of pattern + var resolution = 16; + var padding = resolution * PatternTextureManager.paddingByBlockSize / PatternTextureManager.resolutionByBlockSize; + // and now Z is out? ps.translate(0, 0, -0.5); - ps.scale(1 / 16f, 1 / 16f, 1 / 16f); + ps.scale(1f / resolution, 1f / resolution, 1f / resolution); ps.translate(0, 0, 1.01); - // yoink code from the pattern greeble - // Do two passes: one with a random size to find a good COM and one with the real calculation - var com1 = tile.pattern.getCenter(1); + var isLit = bs.getValue(BlockSlate.ENERGIZED); + var variance = isLit ? 2.5f : 0.5f; + var speed = isLit ? 0.1f : 0f; + var lines1 = tile.pattern.toLines(1, Vec2.ZERO); + var stupidHash = tile.getBlockPos().hashCode(); + var zappyPatternSpace = RenderLib.makeZappy(lines1, RenderLib.findDupIndices(tile.pattern.positions()), + 10, variance, speed, 0.2f, 0f, 1f, stupidHash); + + double minX = Double.MAX_VALUE, maxX = Double.MIN_VALUE, minY = Double.MAX_VALUE, maxY = Double.MIN_VALUE; + for (Vec2 point : zappyPatternSpace) + { + minX = Math.min(minX, point.x); + maxX = Math.max(maxX, point.x); + minY = Math.min(minY, point.y); + maxY = Math.max(maxY, point.y); + } + + double rangeX = maxX - minX; + double rangeY = maxY - minY; - var maxDx = -1f; - var maxDy = -1f; - for (var dot : lines1) { - var dx = Mth.abs(dot.x - com1.x); - if (dx > maxDx) { - maxDx = dx; - } - var dy = Mth.abs(dot.y - com1.y); - if (dy > maxDy) { - maxDy = dy; - } + double scale = Math.min((resolution - 2 * padding) / rangeX, (resolution - 2 * padding) / rangeY); + + double offsetX = ((- 2 * padding) - rangeX * scale) / 2; + double offsetY = ((- 2 * padding) - rangeY * scale) / 2; + + var zappyRenderSpace = new ArrayList(); + + for (Vec2 point : zappyPatternSpace) { + zappyRenderSpace.add(new Vec2( + (float) (((point.x - minX) * scale + offsetX) + padding), + (float) (((point.y - minY) * scale + offsetY) + padding) + )); } - var scale = Math.min(3.8f, Math.min(16 / 2.5f / maxDx, 16 / 2.5f / maxDy)); - var com2 = tile.pattern.getCenter(scale); - var lines2 = tile.pattern.toLines(scale, com2.negated()); // For some reason it is mirrored left to right and i can't seem to posestack-fu it into shape - for (int i = 0; i < lines2.size(); i++) { - var v = lines2.get(i); - lines2.set(i, new Vec2(-v.x, v.y)); + for (int i = 0; i < zappyRenderSpace.size(); i++) { + var v = zappyRenderSpace.get(i); + zappyRenderSpace.set(i, new Vec2(-v.x, v.y)); } - var isLit = bs.getValue(BlockSlate.ENERGIZED); - var variance = isLit ? 2.5f : 0.5f; - var speed = isLit ? 0.1f : 0f; - var stupidHash = tile.getBlockPos().hashCode(); - var zappy = RenderLib.makeZappy(lines2, RenderLib.findDupIndices(tile.pattern.positions()), - 10, variance, speed, 0.2f, 0f, 1f, stupidHash); - int outer = isLit ? 0xff_64c8ff : 0xff_d2c8c8; int inner = isLit ? RenderLib.screenCol(outer) : 0xc8_322b33; - RenderLib.drawLineSeq(ps.last().pose(), zappy, 1f, 0f, outer, outer); - RenderLib.drawLineSeq(ps.last().pose(), zappy, 0.4f, 0.01f, inner, inner); + RenderLib.drawLineSeq(ps.last().pose(), zappyRenderSpace, 1f, 0f, outer, outer); + RenderLib.drawLineSeq(ps.last().pose(), zappyRenderSpace, 0.4f, 0.01f, inner, inner); ps.popPose(); RenderSystem.setShader(() -> oldShader); From c2c7724cef850357c83d81671d079e861431a169 Mon Sep 17 00:00:00 2001 From: object-Object Date: Tue, 5 Dec 2023 02:24:19 -0500 Subject: [PATCH 4/6] Render texture in background so we don't freeze the client for half a second every time someone places a scroll --- .../client/render/PatternTextureManager.java | 42 +++++++++++++++---- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/Common/src/main/java/at/petrak/hexcasting/client/render/PatternTextureManager.java b/Common/src/main/java/at/petrak/hexcasting/client/render/PatternTextureManager.java index e21baa3a6..f9357ed2e 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/render/PatternTextureManager.java +++ b/Common/src/main/java/at/petrak/hexcasting/client/render/PatternTextureManager.java @@ -27,8 +27,8 @@ import java.awt.*; import java.awt.image.BufferedImage; -import java.util.HashMap; import java.util.List; +import java.util.concurrent.*; import java.util.stream.Collectors; public class PatternTextureManager { @@ -40,9 +40,13 @@ public class PatternTextureManager { public static int resolutionByBlockSize = 1024; public static int paddingByBlockSize = 128; public static int circleRadiusByBlockSize = 16; + public static int fastRenderScaleFactor = 8; // e.g. this is 8, resolution is 1024, so render at 1024/8 = 128 public static int scaleLimit = 32; - private static final HashMap patternTextures = new HashMap<>(); + private static final ConcurrentMap patternTextures = new ConcurrentHashMap<>(); + + // basically newCachedThreadPool, but with a max pool size + private static final ExecutorService executor = new ThreadPoolExecutor(0, 16, 60L, TimeUnit.SECONDS, new SynchronousQueue<>()); public static String getPointsKey(List zappyPoints) { @@ -178,7 +182,7 @@ public static void renderPattern(String pointsKey, PoseStack ps, MultiBufferSour nz = -1; } - int lineWidth = 40; + float lineWidth = 40; int outerColor = 0xff_d2c8c8; int innerColor = 0xc8_322b33; if(isScroll) @@ -204,17 +208,34 @@ private static void vertex(Matrix4f mat, Matrix3f normal, int light, VertexConsu .endVertex(); } - public static ResourceLocation getTexture(List points, String pointsKey, int blockSize, boolean showsStrokeOrder, int lineWidth, boolean useFullSize, Color innerColor, Color outerColor) { + public static ResourceLocation getTexture(List points, String pointsKey, int blockSize, boolean showsStrokeOrder, float lineWidth, boolean useFullSize, Color innerColor, Color outerColor) { if (patternTextures.containsKey(pointsKey)) return patternTextures.get(pointsKey); - return createTexture(points, pointsKey, blockSize, showsStrokeOrder, lineWidth, useFullSize, innerColor, outerColor); + + // render a higher-resolution texture in a background thread so it eventually becomes all nice nice and pretty + executor.submit(() -> { + var slowTexture = createTexture(points, blockSize, showsStrokeOrder, lineWidth, useFullSize, innerColor, outerColor, false); + + // TextureManager#register doesn't look very thread-safe, so move back to the main thread after the slow part is done + Minecraft.getInstance().execute(() -> registerTexture(points, pointsKey, slowTexture)); + }); + + // quickly create and cache a low-resolution texture so the client has something to look at + var fastTexture = createTexture(points, blockSize, showsStrokeOrder, lineWidth, useFullSize, innerColor, outerColor, true); + return registerTexture(points, pointsKey, fastTexture); } - public static ResourceLocation createTexture(List points, String pointsKey, int blockSize, boolean showsStrokeOrder, int lineWidth, boolean useFullSize, Color innerColor, Color outerColor) + private static DynamicTexture createTexture(List points, int blockSize, boolean showsStrokeOrder, float lineWidth, boolean useFullSize, Color innerColor, Color outerColor, boolean fastRender) { int resolution = resolutionByBlockSize * blockSize; int padding = paddingByBlockSize * blockSize; + if (fastRender) { + resolution /= fastRenderScaleFactor; + padding /= fastRenderScaleFactor; + lineWidth /= (float)fastRenderScaleFactor; + } + double minX = Double.MAX_VALUE, maxX = Double.MIN_VALUE, minY = Double.MAX_VALUE, maxY = Double.MIN_VALUE; for (Vec2 point : points) { @@ -238,6 +259,7 @@ public static ResourceLocation createTexture(List points, String pointsKey BufferedImage img = new BufferedImage(resolution, resolution, BufferedImage.TYPE_INT_ARGB); Graphics2D g2d = img.createGraphics(); + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.setColor(outerColor); g2d.setStroke(new BasicStroke((blockSize * 5f / 3f) * lineWidth, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); @@ -262,8 +284,12 @@ public static ResourceLocation createTexture(List points, String pointsKey for (int x = 0; x < img.getWidth(); x++) nativeImage.setPixelRGBA(x, y, img.getRGB(x, y)); - DynamicTexture dynamicTexture = new DynamicTexture(nativeImage); - ResourceLocation resourceLocation = Minecraft.getInstance().getTextureManager().register("hex_pattern_texture_" + points.hashCode() + "_" + repaintIndex + ".png", dynamicTexture); + return new DynamicTexture(nativeImage); + } + + private static ResourceLocation registerTexture(List points, String pointsKey, DynamicTexture dynamicTexture) { + String name = "hex_pattern_texture_" + points.hashCode() + "_" + repaintIndex + ".png"; + ResourceLocation resourceLocation = Minecraft.getInstance().getTextureManager().register(name, dynamicTexture); patternTextures.put(pointsKey, resourceLocation); return resourceLocation; } From b36155d7e3292dcd302f728492a69f874488997a Mon Sep 17 00:00:00 2001 From: Talia-12 Date: Tue, 5 Dec 2023 18:22:32 +1000 Subject: [PATCH 5/6] control resolution with command, and eventually probably with config option. --- .../client/render/PatternTextureManager.java | 27 ++++++++++---- .../command/PatternTexturesCommand.java | 36 ++++++++----------- 2 files changed, 34 insertions(+), 29 deletions(-) diff --git a/Common/src/main/java/at/petrak/hexcasting/client/render/PatternTextureManager.java b/Common/src/main/java/at/petrak/hexcasting/client/render/PatternTextureManager.java index e21baa3a6..afec858fc 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/render/PatternTextureManager.java +++ b/Common/src/main/java/at/petrak/hexcasting/client/render/PatternTextureManager.java @@ -36,11 +36,24 @@ public class PatternTextureManager { //TODO: remove if not needed anymore for comparison public static boolean useTextures = true; public static int repaintIndex = 0; - - public static int resolutionByBlockSize = 1024; - public static int paddingByBlockSize = 128; - public static int circleRadiusByBlockSize = 16; - public static int scaleLimit = 32; + public static int resolutionScaler = 4; + + public static int resolutionByBlockSize = 128 * resolutionScaler; + public static int paddingByBlockSize = 16 * resolutionScaler; + public static int circleRadiusByBlockSize = 2 * resolutionScaler; + public static int scaleLimit = 4 * resolutionScaler; + public static int scrollLineWidth = 6 * resolutionScaler; + public static int otherLineWidth = 5 * resolutionScaler; + + public static void setResolutionScaler(int resolutionScaler) { + PatternTextureManager.resolutionScaler = resolutionScaler; + resolutionByBlockSize = 256 * resolutionScaler; + paddingByBlockSize = 32 * resolutionScaler; + circleRadiusByBlockSize = 4 * resolutionScaler; + scaleLimit = 8 * resolutionScaler; + scrollLineWidth = 7 * resolutionScaler; + otherLineWidth = 10 * resolutionScaler; + } private static final HashMap patternTextures = new HashMap<>(); @@ -178,11 +191,11 @@ public static void renderPattern(String pointsKey, PoseStack ps, MultiBufferSour nz = -1; } - int lineWidth = 40; + int lineWidth = otherLineWidth; int outerColor = 0xff_d2c8c8; int innerColor = 0xc8_322b33; if(isScroll) - lineWidth = 30; + lineWidth = scrollLineWidth; ResourceLocation texture = getTexture(zappyPoints, pointsKey, blockSize, showStrokeOrder, lineWidth, useFullSize, new Color(innerColor), new Color(outerColor)); VertexConsumer verts = bufSource.getBuffer(RenderType.entityCutout(texture)); diff --git a/Common/src/main/java/at/petrak/hexcasting/common/command/PatternTexturesCommand.java b/Common/src/main/java/at/petrak/hexcasting/common/command/PatternTexturesCommand.java index d72a5c4c4..e653759ae 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/command/PatternTexturesCommand.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/command/PatternTexturesCommand.java @@ -1,6 +1,7 @@ package at.petrak.hexcasting.common.command; import at.petrak.hexcasting.client.render.PatternTextureManager; +import com.mojang.brigadier.arguments.IntegerArgumentType; import com.mojang.brigadier.builder.LiteralArgumentBuilder; import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.Commands; @@ -14,27 +15,18 @@ public static void add(LiteralArgumentBuilder cmd) { PatternTextureManager.useTextures = !PatternTextureManager.useTextures; return 1; })); - -// cmd.then(Commands.literal("textureSetColor") -// .requires(dp -> dp.hasPermission(Commands.LEVEL_ADMINS)) -// .then(Commands.argument("r", IntegerArgumentType.integer()) -// .then(Commands.argument("g", IntegerArgumentType.integer()) -// .then(Commands.argument("b", IntegerArgumentType.integer()).executes(ctx -> { -// var r = IntegerArgumentType.getInteger(ctx, "r"); -// var g = IntegerArgumentType.getInteger(ctx, "g"); -// var b = IntegerArgumentType.getInteger(ctx, "b"); -// PatternTextureManager.color = new Color(r,g,b,255); -// PatternTextureManager.repaint(); -// return 1; -// }))))); -// -// cmd.then(Commands.literal("textureSetResolution") -// .requires(dp -> dp.hasPermission(Commands.LEVEL_ADMINS)) -// .then(Commands.argument("integer", IntegerArgumentType.integer()).executes(ctx -> { -// var integer = IntegerArgumentType.getInteger(ctx, "integer"); -// PatternTextureManager.resolutionByBlockSize = integer; -// PatternTextureManager.repaint(); -// return 1; -// }))); + cmd.then(Commands.literal("textureRepaint") + .requires(dp -> dp.hasPermission(Commands.LEVEL_ADMINS)) + .executes(ctx -> { + PatternTextureManager.repaint(); + return 1; + })); + cmd.then(Commands.literal("textureSetResolutionScaler") + .requires(dp -> dp.hasPermission(Commands.LEVEL_ADMINS)) + .then(Commands.argument("integer", IntegerArgumentType.integer()).executes(ctx -> { + PatternTextureManager.setResolutionScaler(IntegerArgumentType.getInteger(ctx, "integer")); + PatternTextureManager.repaint(); + return 1; + }))); } } \ No newline at end of file From 7b2e47ca2cd7f690ad0ebaea8e572ec7789aba70 Mon Sep 17 00:00:00 2001 From: Talia-12 Date: Mon, 11 Dec 2023 16:24:53 +1000 Subject: [PATCH 6/6] stop active patterns on tiles jumping around all other the place, fix crash when too many patterns added to render queue at once, try and fix flickering issue. --- .../client/render/PatternTextureManager.java | 42 ++++++++++++------- .../render/be/BlockEntitySlateRenderer.java | 11 +++-- 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/Common/src/main/java/at/petrak/hexcasting/client/render/PatternTextureManager.java b/Common/src/main/java/at/petrak/hexcasting/client/render/PatternTextureManager.java index 3f33bd9a4..c28116900 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/render/PatternTextureManager.java +++ b/Common/src/main/java/at/petrak/hexcasting/client/render/PatternTextureManager.java @@ -44,22 +44,22 @@ public class PatternTextureManager { public static int paddingByBlockSize = 16 * resolutionScaler; public static int circleRadiusByBlockSize = 2 * resolutionScaler; public static int scaleLimit = 4 * resolutionScaler; - public static int scrollLineWidth = 6 * resolutionScaler; - public static int otherLineWidth = 5 * resolutionScaler; + public static int scrollLineWidth = 3 * resolutionScaler; + public static int otherLineWidth = 4 * resolutionScaler; public static void setResolutionScaler(int resolutionScaler) { PatternTextureManager.resolutionScaler = resolutionScaler; - resolutionByBlockSize = 256 * resolutionScaler; - paddingByBlockSize = 32 * resolutionScaler; - circleRadiusByBlockSize = 4 * resolutionScaler; - scaleLimit = 8 * resolutionScaler; - scrollLineWidth = 7 * resolutionScaler; - otherLineWidth = 10 * resolutionScaler; + resolutionByBlockSize = 128 * resolutionScaler; + paddingByBlockSize = 16 * resolutionScaler; + circleRadiusByBlockSize = 2 * resolutionScaler; + scaleLimit = 4 * resolutionScaler; + scrollLineWidth = 3 * resolutionScaler; + otherLineWidth = 4 * resolutionScaler; } private static final ConcurrentMap patternTexturesToAdd = new ConcurrentHashMap<>(); // basically newCachedThreadPool, but with a max pool size - private static final ExecutorService executor = new ThreadPoolExecutor(0, 16, 60L, TimeUnit.SECONDS, new SynchronousQueue<>()); + private static final ExecutorService executor = new ThreadPoolExecutor(0, 16, 60L, TimeUnit.SECONDS, new LinkedBlockingDeque<>()); private static final HashMap patternTextures = new HashMap<>(); @@ -225,20 +225,28 @@ private static void vertex(Matrix4f mat, Matrix3f normal, int light, VertexConsu } public static ResourceLocation getTexture(List points, String pointsKey, int blockSize, boolean showsStrokeOrder, float lineWidth, boolean useFullSize, Color innerColor, Color outerColor) { - if (patternTexturesToAdd.containsKey(pointsKey)) - return patternTexturesToAdd.get(pointsKey); + if (patternTexturesToAdd.containsKey(pointsKey)) { + var patternTexture = patternTexturesToAdd.remove(pointsKey); + var oldPatternTexture = patternTextures.put(pointsKey, patternTexture); + if (oldPatternTexture != null) + Minecraft.getInstance().getTextureManager().getTexture(oldPatternTexture).close(); + + return patternTexture; + } + if (patternTextures.containsKey(pointsKey)) + return patternTextures.get(pointsKey); // render a higher-resolution texture in a background thread so it eventually becomes all nice nice and pretty executor.submit(() -> { var slowTexture = createTexture(points, blockSize, showsStrokeOrder, lineWidth, useFullSize, innerColor, outerColor, false); // TextureManager#register doesn't look very thread-safe, so move back to the main thread after the slow part is done - Minecraft.getInstance().execute(() -> registerTexture(points, pointsKey, slowTexture)); + Minecraft.getInstance().execute(() -> registerTexture(points, pointsKey, slowTexture, true)); }); // quickly create and cache a low-resolution texture so the client has something to look at var fastTexture = createTexture(points, blockSize, showsStrokeOrder, lineWidth, useFullSize, innerColor, outerColor, true); - return registerTexture(points, pointsKey, fastTexture); + return registerTexture(points, pointsKey, fastTexture, false); } private static DynamicTexture createTexture(List points, int blockSize, boolean showsStrokeOrder, float lineWidth, boolean useFullSize, Color innerColor, Color outerColor, boolean fastRender) @@ -303,8 +311,11 @@ private static DynamicTexture createTexture(List points, int blockSize, bo return new DynamicTexture(nativeImage); } - private static ResourceLocation registerTexture(List points, String pointsKey, DynamicTexture dynamicTexture) { - String name = "hex_pattern_texture_" + points.hashCode() + "_" + repaintIndex + ".png"; + private static ResourceLocation registerTexture(List points, String pointsKey, DynamicTexture dynamicTexture, boolean isSlow) { + // isSlow used to register different textures for the low-resolution, fastly rendered version of each texture + // and the high-resolution, slowly rendered version (this means the slow doesn't replace the fast in the texture manager, + // which causes occasional visual stuttering for a frame). + String name = "hex_pattern_texture_" + points.hashCode() + "_" + repaintIndex + "_" + (isSlow ? "slow" : "fast") + ".png"; ResourceLocation resourceLocation = Minecraft.getInstance().getTextureManager().register(name, dynamicTexture); patternTexturesToAdd.put(pointsKey, resourceLocation); return resourceLocation; @@ -341,5 +352,6 @@ private static void drawHexagon(Graphics2D g2d, int x, int y, int radius) { public static void repaint() { repaintIndex++; patternTexturesToAdd.clear(); + patternTextures.clear(); } } \ No newline at end of file diff --git a/Common/src/main/java/at/petrak/hexcasting/client/render/be/BlockEntitySlateRenderer.java b/Common/src/main/java/at/petrak/hexcasting/client/render/be/BlockEntitySlateRenderer.java index b9550dbbd..37a40babc 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/render/be/BlockEntitySlateRenderer.java +++ b/Common/src/main/java/at/petrak/hexcasting/client/render/be/BlockEntitySlateRenderer.java @@ -72,9 +72,14 @@ public void render(BlockEntitySlate tile, float pPartialTick, PoseStack ps, var lines1 = tile.pattern.toLines(1, Vec2.ZERO); var stupidHash = tile.getBlockPos().hashCode(); - var zappyPatternSpace = RenderLib.makeZappy(lines1, RenderLib.findDupIndices(tile.pattern.positions()), + var zappyPattern = RenderLib.makeZappy(lines1, RenderLib.findDupIndices(tile.pattern.positions()), 10, variance, speed, 0.2f, 0f, 1f, stupidHash); + // always do space calculations with the static version of the pattern + // so that it doesn't jump around resizing itself. + var zappyPatternSpace = RenderLib.makeZappy(lines1, RenderLib.findDupIndices(tile.pattern.positions()), + 10, 0.5f, 0f, 0.2f, 0f, 1f, stupidHash); + double minX = Double.MAX_VALUE, maxX = Double.MIN_VALUE, minY = Double.MAX_VALUE, maxY = Double.MIN_VALUE; for (Vec2 point : zappyPatternSpace) { @@ -94,7 +99,7 @@ public void render(BlockEntitySlate tile, float pPartialTick, PoseStack ps, var zappyRenderSpace = new ArrayList(); - for (Vec2 point : zappyPatternSpace) { + for (Vec2 point : zappyPattern) { zappyRenderSpace.add(new Vec2( (float) (((point.x - minX) * scale + offsetX) + padding), (float) (((point.y - minY) * scale + offsetY) + padding) @@ -115,4 +120,4 @@ public void render(BlockEntitySlate tile, float pPartialTick, PoseStack ps, ps.popPose(); RenderSystem.setShader(() -> oldShader); } -} +} \ No newline at end of file