diff --git a/gradle.properties b/gradle.properties index f1f7d01..988e521 100644 --- a/gradle.properties +++ b/gradle.properties @@ -34,7 +34,7 @@ mod_name=Power Tool # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=GPL-3.0 # The mod version. See https://semver.org/ -mod_version=1.4.40 +mod_version=1.4.41 # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html diff --git a/src/main/java/org/teacon/powertool/block/entity/BezierCurveBlockEntity.java b/src/main/java/org/teacon/powertool/block/entity/BezierCurveBlockEntity.java index c485af2..a066469 100644 --- a/src/main/java/org/teacon/powertool/block/entity/BezierCurveBlockEntity.java +++ b/src/main/java/org/teacon/powertool/block/entity/BezierCurveBlockEntity.java @@ -34,6 +34,8 @@ public class BezierCurveBlockEntity extends BlockEntity implements IClientUpdate public int uScale = 1; public int vScale = 1; public int color = -1; + public boolean clampMode = false; + public boolean worldCoordinate = false; public ResourceLocation texture = VanillaUtils.MISSING_TEXTURE; public List controlPoints = new ArrayList<>(); public BezierCurve3f bezierCurve; @@ -72,6 +74,8 @@ public void read(CompoundTag tag) { if(tag.contains("uScale")) uScale = tag.getInt("uScale"); if(tag.contains("vScale")) vScale = tag.getInt("vScale"); if(tag.contains("texture")) texture = Objects.requireNonNullElse(ResourceLocation.tryParse(tag.getString("texture")),VanillaUtils.MISSING_TEXTURE); + if(tag.contains("clampMode")) clampMode = tag.getBoolean("clampMode"); + if(tag.contains("worldCoordinate")) worldCoordinate = tag.getBoolean("worldCoordinate"); if(tag.contains("controlPointSize")){ var size = tag.getInt("controlPointSize"); controlPoints = new ArrayList<>(); @@ -93,6 +97,8 @@ public CompoundTag write(CompoundTag tag) { tag.putInt("uScale", uScale); tag.putInt("vScale", vScale); tag.putString("texture", texture.toString()); + tag.putBoolean("clampMode", clampMode); + tag.putBoolean("worldCoordinate", worldCoordinate); for(int i = 0; i < controlPoints.size(); i++){ tag.putFloat("controlPoint"+i+"x", controlPoints.get(i).x()); tag.putFloat("controlPoint"+i+"y", controlPoints.get(i).y()); diff --git a/src/main/java/org/teacon/powertool/client/gui/BezierCurveBlockScreen.java b/src/main/java/org/teacon/powertool/client/gui/BezierCurveBlockScreen.java index 3fef435..d0935cc 100644 --- a/src/main/java/org/teacon/powertool/client/gui/BezierCurveBlockScreen.java +++ b/src/main/java/org/teacon/powertool/client/gui/BezierCurveBlockScreen.java @@ -3,6 +3,8 @@ import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.components.Checkbox; +import net.minecraft.client.gui.components.Tooltip; import net.minecraft.client.gui.screens.Screen; import net.minecraft.network.chat.CommonComponents; import net.minecraft.network.chat.Component; @@ -31,6 +33,8 @@ public class BezierCurveBlockScreen extends Screen { protected ObjectInputBox vScaleInput; protected ObjectInputBox colorInput; protected ObjectInputBox textureInput; + protected Checkbox useClampMode; + protected Checkbox useWorldCoordinate; public BezierCurveBlockScreen(BezierCurveBlockEntity te) { @@ -42,42 +46,54 @@ public BezierCurveBlockScreen(BezierCurveBlockEntity te) { protected void init() { super.init(); var startY = (int)(height*0.05); - + var startX = (int)(width*0.2); this.addRenderableWidget(new Button.Builder(CommonComponents.GUI_DONE, btn -> this.onDone()) - .pos((int) (this.width*0.2), (int) Math.max(startY*2+20+25*7,this.height*0.8 + startY)) - .size((int) (width*0.2), 20).build()); + .pos(startX, (int) Math.max(startY*2+20+25*9,this.height*0.8 + startY)) + .size(startX, 20).build()); - this.stepInput = new ObjectInputBox<>(font, (int) (width*0.2),startY*2+20, (int) (width*0.25),20,Component.translatable("powertool.gui.bezier_curve.step"),ObjectInputBox.INT_VALIDATOR.and(str -> { + this.stepInput = new ObjectInputBox<>(font, startX,startY*2+20, (int) (width*0.25),20,Component.translatable("powertool.gui.bezier_curve.step"),ObjectInputBox.INT_VALIDATOR.and(str -> { var i = Integer.parseInt(str); return i>=2 && i < 2000; }),ObjectInputBox.INT_RESPONDER); this.stepInput.setMaxLength(14); this.stepInput.setValue(String.valueOf(Math.max(te.steps,2))); this.addRenderableWidget(this.stepInput); - this.sideCountInput = new ObjectInputBox<>(font,(int) (width*0.2),startY*2+20+25,(int) (width*0.25),20,Component.translatable("powertool.gui.bezier_curve.sides"),ObjectInputBox.INT_VALIDATOR.and(str -> Integer.parseInt(str) >= 3),ObjectInputBox.INT_RESPONDER); + this.sideCountInput = new ObjectInputBox<>(font,startX,startY*2+20+25,(int) (width*0.25),20,Component.translatable("powertool.gui.bezier_curve.sides"),ObjectInputBox.INT_VALIDATOR.and(str -> Integer.parseInt(str) >= 3),ObjectInputBox.INT_RESPONDER); this.sideCountInput.setMaxLength(14); this.sideCountInput.setValue(String.valueOf(Math.max(te.sideCount,3))); this.addRenderableWidget(this.sideCountInput); - this.radiusInput = new ObjectInputBox<>(font,(int) (width*0.2),startY*2+20+25*2,(int) (width*0.25),20,Component.translatable("powertool.gui.bezier_curve.radius"),ObjectInputBox.FLOAT_VALIDATOR,ObjectInputBox.FLOAT_RESPONDER); + this.radiusInput = new ObjectInputBox<>(font,startX,startY*2+20+25*2,(int) (width*0.25),20,Component.translatable("powertool.gui.bezier_curve.radius"),ObjectInputBox.FLOAT_VALIDATOR,ObjectInputBox.FLOAT_RESPONDER); this.radiusInput.setMaxLength(14); this.radiusInput.setValue(String.valueOf(te.radius)); this.addRenderableWidget(this.radiusInput); - this.textureInput = new ObjectInputBox<>(font,(int) (width*0.2),startY*2+20+25*3,(int) (width*0.25),20,Component.translatable("powertool.gui.bezier_curve.texture"),ObjectInputBox.TEXTURE_VALIDATOR,ObjectInputBox.TEXTURE_RESPONDER); + this.textureInput = new ObjectInputBox<>(font,startX,startY*2+20+25*3,(int) (width*0.25),20,Component.translatable("powertool.gui.bezier_curve.texture"),ObjectInputBox.TEXTURE_VALIDATOR,ObjectInputBox.TEXTURE_RESPONDER); this.textureInput.setMaxLength(1000); this.textureInput.setValue(te.texture.toString()); this.addRenderableWidget(this.textureInput); - this.uScaleInput = new ObjectInputBox<>(font,(int) (width*0.2),startY*2+20+25*4,(int) (width*0.25),20,Component.translatable("powertool.gui.bezier_curve.uScale"),ObjectInputBox.INT_VALIDATOR,ObjectInputBox.INT_RESPONDER); + this.uScaleInput = new ObjectInputBox<>(font,startX,startY*2+20+25*4,(int) (width*0.25),20,Component.translatable("powertool.gui.bezier_curve.uScale"),ObjectInputBox.INT_VALIDATOR,ObjectInputBox.INT_RESPONDER); this.uScaleInput.setMaxLength(14); this.uScaleInput.setValue(String.valueOf(te.uScale)); this.addRenderableWidget(this.uScaleInput); - this.vScaleInput = new ObjectInputBox<>(font,(int) (width*0.2),startY*2+20+25*5,(int) (width*0.25),20,Component.translatable("powertool.gui.bezier_curve.vScale"),ObjectInputBox.INT_VALIDATOR,ObjectInputBox.INT_RESPONDER); + this.vScaleInput = new ObjectInputBox<>(font,startX,startY*2+20+25*5,(int) (width*0.25),20,Component.translatable("powertool.gui.bezier_curve.vScale"),ObjectInputBox.INT_VALIDATOR,ObjectInputBox.INT_RESPONDER); this.vScaleInput.setMaxLength(14); this.vScaleInput.setValue(String.valueOf(te.vScale)); this.addRenderableWidget(this.vScaleInput); - this.colorInput = new ObjectInputBox<>(font,(int) (width*0.2),startY*2+20+25*6,(int) (width*0.25),20,Component.translatable("powertool.gui.bezier_curve.color"),ObjectInputBox.RGB_COLOR_VALIDATOR,ObjectInputBox.RGB_COLOR_RESPONDER); + this.colorInput = new ObjectInputBox<>(font,startX,startY*2+20+25*6,(int) (width*0.25),20,Component.translatable("powertool.gui.bezier_curve.color"),ObjectInputBox.RGB_COLOR_VALIDATOR,ObjectInputBox.RGB_COLOR_RESPONDER); this.colorInput.setMaxLength(14); this.colorInput.setValue(VanillaUtils.hexColorFromInt(te.color)); this.addRenderableWidget(this.colorInput); + this.useClampMode = Checkbox.builder(Component.translatable("powertool.gui.bezier_curve.use_clamp_mode"),font) + .tooltip(Tooltip.create(Component.translatable("powertool.gui.bezier_curve.use_clamp_mode.tooltip"))) + .pos(startX,startY*2+20+25*7) + .selected(te.clampMode) + .build(); + this.addRenderableWidget(this.useClampMode); + this.useWorldCoordinate = Checkbox.builder(Component.translatable("powertool.gui.bezier_curve.use_world_coordinate"),font) + .tooltip(Tooltip.create(Component.translatable("powertool.gui.bezier_curve.use_world_coordinate.tooltip"))) + .pos(startX,startY*2+20+25*8) + .selected(te.worldCoordinate) + .build(); + this.addRenderableWidget(this.useWorldCoordinate); this.append = Button.builder(Component.literal("+"),(b) -> { if(this.vector3fList != null) vector3fList.appendEntry(); }).size(20,20).pos((int) (width*0.95-25),startY+20).build(); @@ -102,6 +118,8 @@ public void removed() { te.uScale = Objects.requireNonNullElse(uScaleInput.get(),1); te.vScale = Objects.requireNonNullElse(vScaleInput.get(),1); te.color = Objects.requireNonNullElse(colorInput.get(),-1); + te.clampMode = useClampMode.selected(); + te.worldCoordinate = useWorldCoordinate.selected(); var points = vector3fList.entries().stream().map(Vector3fList.Entry::getResult).toList(); te.setControlPoints(points); PacketDistributor.sendToServer(UpdateBlockEntityData.create(te)); @@ -115,7 +133,7 @@ public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partia var startY = (int)(height*0.05); guiGraphics.drawString(font,s1,(int)(width*0.55)+5,startY+20+5,-1); guiGraphics.drawString(font,s2,(int)(width*0.55)+5, (int) (startY+20+height*0.8)+5,-1); - if(te.bezierCurve != null) guiGraphics.drawString(font,"length: "+te.bezierCurve.getLength(),(int) (width*0.2),startY*2+20+25*7,-1); + if(te.bezierCurve != null) guiGraphics.drawString(font,"length: "+te.bezierCurve.getLength(),(int) (width*0.2),startY*2+20+25*9,-1); } @Override diff --git a/src/main/java/org/teacon/powertool/client/renders/BezierCurveBlockRenderer.java b/src/main/java/org/teacon/powertool/client/renders/BezierCurveBlockRenderer.java index 362caba..8cf2627 100644 --- a/src/main/java/org/teacon/powertool/client/renders/BezierCurveBlockRenderer.java +++ b/src/main/java/org/teacon/powertool/client/renders/BezierCurveBlockRenderer.java @@ -3,6 +3,7 @@ import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.datafixers.util.Pair; +import net.minecraft.world.level.ChunkPos; import org.teacon.powertool.client.eyelib.render.sections.BlockEntitySectionGeometryRenderer; import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraft.client.Minecraft; @@ -40,10 +41,20 @@ public AABB getRenderBoundingBox(BezierCurveBlockEntity blockEntity) { public void renderSectionGeometry(BezierCurveBlockEntity te, AddSectionGeometryEvent.SectionRenderingContext context, PoseStack poseStack, BlockPos pos, BlockPos regionOrigin, int packedLight, MultiBufferSource bufferSource) { var model = te.line; if(model == null) return; + var line = model.line; + var clampMode = te.clampMode; + var steps = te.steps; + var sideCount = te.sideCount; var vertexList = model.vertexAndNormalQuadsList(); - if(vertexList.size() < (te.steps-1)*te.sideCount*4) return; + var level = Minecraft.getInstance().level; + var selfPos = te.getBlockPos(); + var useWorldCoordinate = te.worldCoordinate; + BlockPos centerPos = null; + if(level != null) centerPos = level.getChunkAt(selfPos).getPos().getMiddleBlockPosition(0); + if(vertexList.size() < (steps-1)*sideCount*4) return; poseStack = context.getPoseStack(); poseStack.pushPose(); + if(useWorldCoordinate) poseStack.translate(-selfPos.getX(), -selfPos.getY(), -selfPos.getZ()); @SuppressWarnings("deprecation") var texture = Minecraft.getInstance().getModelManager().getAtlas(TextureAtlas.LOCATION_BLOCKS).getSprite(te.texture); var pose = poseStack.last(); @@ -53,10 +64,11 @@ public void renderSectionGeometry(BezierCurveBlockEntity te, AddSectionGeometryE var color = te.color; var u = 0f; var v = 0f; - for(var i = 0; i < te.steps-1; ++i) { + for(var i = 0; i < steps-1; ++i) { v = 0f; - for(var j = 0; j < te.sideCount; ++j) { - var ptr = j*4+i*te.sideCount*4; + if(centerPos != null && clampMode && !insideRenderChunk(centerPos,line.get(i), useWorldCoordinate ? 0 : selfPos.getX(), useWorldCoordinate ? 0 : selfPos.getZ())) continue; + for(var j = 0; j < sideCount; ++j) { + var ptr = j*4+i*sideCount*4; putVertex(buffer,pose,vertexList.get(ptr),texture.getU(u),texture.getV(v), color, packedLight); putVertex(buffer,pose,vertexList.get(ptr+1),texture.getU(u+uScale),texture.getV(v), color, packedLight); putVertex(buffer,pose,vertexList.get(ptr+2),texture.getU(u+uScale),texture.getV(v+vScale), color, packedLight); @@ -74,6 +86,10 @@ public void renderSectionGeometry(BezierCurveBlockEntity te, AddSectionGeometryE poseStack.popPose(); } + public static boolean insideRenderChunk(BlockPos chunkCenter,Vector3f renderPos,int offsetX,int offsetZ){ + return Math.abs(chunkCenter.getX()-renderPos.x-offsetX) < 10f && Math.abs(chunkCenter.getZ()-renderPos.z-offsetZ) < 10f; + } + public static void putVertex(VertexConsumer buffer, PoseStack.Pose pose, Pair vertexAndNormal, float u, float v, int color, int light){ var vertex = vertexAndNormal.getFirst(); var normal = vertexAndNormal.getSecond(); diff --git a/src/main/java/org/teacon/powertool/utils/math/Line3f.java b/src/main/java/org/teacon/powertool/utils/math/Line3f.java index 82f797f..bd33400 100644 --- a/src/main/java/org/teacon/powertool/utils/math/Line3f.java +++ b/src/main/java/org/teacon/powertool/utils/math/Line3f.java @@ -18,7 +18,8 @@ public class Line3f { public final Vector3f start; public final Vector3f end; public final List line; - private List> vertexesAndNormals; + private volatile List> vertexesAndNormals; + private final Object lock = new Object(); /** * constructor of a line can be rendered in world. @@ -43,23 +44,28 @@ public Line3f(int sideCount, double radius, List line){ nodes.add(new LineNode3f(line.getLast(), previous,null, sideCount,radius)); } - //是的这真有可能多线程访问[xkball] - public synchronized List> vertexAndNormalQuadsList(){ + //是的这真有多线程访问[xkball] + public List> vertexAndNormalQuadsList(){ if(vertexesAndNormals == null){ - vertexesAndNormals = new ArrayList<>(); - for(var i = 0; i < (nodes.size() - 1); i++){ - var cur = nodes.get(i); - var next = nodes.get(i + 1); - var sideCount = cur.sideCount; - for(int j = 0; j < sideCount; j++){ - vertexesAndNormals.add(Pair.of(cur.points.get(j),cur.normals.get(j))); - vertexesAndNormals.add(Pair.of(next.points.get(j),next.normals.get(j))); - var jNext = (j+1)%sideCount; - vertexesAndNormals.add(Pair.of(next.points.get(jNext),next.normals.get(jNext))); - vertexesAndNormals.add(Pair.of(cur.points.get(jNext),cur.normals.get(jNext))); + synchronized (lock){ + if(vertexesAndNormals == null){ + var temp = new ArrayList>(); + for(var i = 0; i < (nodes.size() - 1); i++){ + var cur = nodes.get(i); + var next = nodes.get(i + 1); + var sideCount = cur.sideCount; + for(int j = 0; j < sideCount; j++){ + temp.add(Pair.of(cur.points.get(j),cur.normals.get(j))); + temp.add(Pair.of(next.points.get(j),next.normals.get(j))); + var jNext = (j+1)%sideCount; + temp.add(Pair.of(next.points.get(jNext),next.normals.get(jNext))); + temp.add(Pair.of(cur.points.get(jNext),cur.normals.get(jNext))); + } + } + vertexesAndNormals = Collections.unmodifiableList(temp); } } - vertexesAndNormals = Collections.unmodifiableList(vertexesAndNormals); + } return vertexesAndNormals; } diff --git a/src/main/resources/assets/powertool/lang/en_us.json b/src/main/resources/assets/powertool/lang/en_us.json index 55585f3..f6f3ac4 100644 --- a/src/main/resources/assets/powertool/lang/en_us.json +++ b/src/main/resources/assets/powertool/lang/en_us.json @@ -170,5 +170,9 @@ "powertool.gui.bezier_curve.color": "Color(ARGB)", "powertool.gui.bezier_curve.control_points": "Control Points: ", "powertool.gui.bezier_curve.control_points_warn": "For performance reasons, it is recommended that the number of control points be less than four.", + "powertool.gui.bezier_curve.use_clamp_mode": "Use Clamp Mode", + "powertool.gui.bezier_curve.use_clamp_mode.tooltip": "Will not render vertexes far from chunk center.", + "powertool.gui.bezier_curve.use_world_coordinate": "Use World Coordinate", + "powertool.gui.bezier_curve.use_world_coordinate.tooltip": "Determines whether control points represent relative or absolute(world) coordinates.", "powertool.gui.examine_holo_glass.warn": "Calculated independently relative to the left side." } \ No newline at end of file diff --git a/src/main/resources/assets/powertool/lang/zh_cn.json b/src/main/resources/assets/powertool/lang/zh_cn.json index 80a68b5..bdc816a 100644 --- a/src/main/resources/assets/powertool/lang/zh_cn.json +++ b/src/main/resources/assets/powertool/lang/zh_cn.json @@ -171,5 +171,9 @@ "powertool.gui.bezier_curve.color": "颜色(ARGB)", "powertool.gui.bezier_curve.control_points": "控制点: ", "powertool.gui.bezier_curve.control_points_warn": "出于性能考虑,建议控制点个数在四个以下", + "powertool.gui.bezier_curve.use_clamp_mode": "使用限制渲染模式", + "powertool.gui.bezier_curve.use_clamp_mode.tooltip": "将不会渲染远离区块中心的顶点.", + "powertool.gui.bezier_curve.use_world_coordinate": "使用世界坐标", + "powertool.gui.bezier_curve.use_world_coordinate.tooltip": "决定控制点代表相对坐标还是绝对(世界)坐标.", "powertool.gui.examine_holo_glass.warn": "相对左侧独立计算." } \ No newline at end of file