Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add rendering for fluids to in-world structure previews #17

Open
wants to merge 1 commit into
base: 1.21
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Add rendering for fluids in in-world structure previews
Other minor (associated) changes:
- Add new structure to testmod that contains water for testing
- Add config to lavender to allow changing opacity of preview
  I found it was a tad difficult to see the water,
  as it's now doublely transparent
  (water is transparent + the preview is transparent),
  so instead I made it adjustable
  - Config is done using owo-config, as it's already included
  - Added english translation for config option.
    (I don't know german, so can't do that)

Signed-off-by: solonovamax <solonovamax@12oclockpoint.com>
solonovamax committed Jul 25, 2024
commit c9e818ab6a327a5433132d5be57189c04068317d
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
@@ -52,7 +52,7 @@ dependencies {
// Fabric API. This is technically optional, but you probably want it anyway.
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"

modImplementation "io.wispforest:owo-lib:${project.owo_version}"
annotationProcessor modImplementation("io.wispforest:owo-lib:${project.owo_version}")
include "io.wispforest:owo-sentinel:${project.owo_version}"

// modLocalRuntime "me.shedaniel:RoughlyEnoughItems-fabric:${project.rei_version}"
3 changes: 3 additions & 0 deletions src/main/java/io/wispforest/lavender/Lavender.java
Original file line number Diff line number Diff line change
@@ -21,6 +21,7 @@
import net.minecraft.util.Identifier;
import net.minecraft.world.PersistentState;
import org.slf4j.Logger;
import io.wispforest.lavender.LavenderConfig;

import java.util.UUID;

@@ -32,6 +33,8 @@ public class Lavender implements ModInitializer {

public static final Identifier WORLD_ID_CHANNEL = Lavender.id("world_id_channel");

public static final LavenderConfig CONFIG = LavenderConfig.createAndLoad();

@Override
public void onInitialize() {
Registry.register(Registries.ITEM, id("dynamic_book"), LavenderBookItem.DYNAMIC_BOOK);
12 changes: 12 additions & 0 deletions src/main/java/io/wispforest/lavender/LavenderConfigModel.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.wispforest.lavender;

import io.wispforest.owo.config.annotation.Config;
import io.wispforest.owo.config.annotation.Modmenu;
import io.wispforest.owo.config.annotation.RangeConstraint;

@Modmenu(modId = Lavender.MOD_ID)
@Config(name = "lavender", wrapperName = "LavenderConfig")
public class LavenderConfigModel {
@RangeConstraint(min = 0.0, max = 1.0)
public float structurePreviewAlpha = 0.5f;
}
Original file line number Diff line number Diff line change
@@ -11,22 +11,31 @@
import io.wispforest.owo.ui.component.Components;
import io.wispforest.owo.ui.container.Containers;
import io.wispforest.owo.ui.container.FlowLayout;
import io.wispforest.owo.ui.core.*;
import io.wispforest.owo.ui.core.Easing;
import io.wispforest.owo.ui.core.HorizontalAlignment;
import io.wispforest.owo.ui.core.Insets;
import io.wispforest.owo.ui.core.Positioning;
import io.wispforest.owo.ui.core.Sizing;
import io.wispforest.owo.ui.event.WindowResizeCallback;
import io.wispforest.owo.ui.hud.Hud;
import io.wispforest.owo.ui.util.Delta;
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext;
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;
import net.fabricmc.fabric.api.event.player.UseBlockCallback;
import net.minecraft.block.BlockState;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gl.Framebuffer;
import net.minecraft.client.gl.SimpleFramebuffer;
import net.minecraft.client.render.LightmapTextureManager;
import net.minecraft.client.render.OverlayTexture;
import net.minecraft.client.render.OverlayVertexConsumer;
import net.minecraft.client.render.RenderLayer;
import net.minecraft.client.render.RenderLayers;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.model.ModelLoader;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.sound.SoundCategory;
import net.minecraft.fluid.FluidState;
import net.minecraft.sound.SoundEvents;
import net.minecraft.text.Text;
import net.minecraft.util.ActionResult;
@@ -36,6 +45,7 @@
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3i;
import net.minecraft.world.BlockRenderView;
import org.apache.commons.lang3.mutable.MutableBoolean;
import org.jetbrains.annotations.Nullable;
import org.lwjgl.opengl.GL30C;
@@ -51,7 +61,7 @@ public class StructureOverlayRenderer {

var framebuffer = new SimpleFramebuffer(window.getFramebufferWidth(), window.getFramebufferHeight(), true, MinecraftClient.IS_SYSTEM_MAC);
((LavenderFramebufferExtension)framebuffer).lavender$setBlitProgram(() -> {
LavenderClient.BLIT_ALPHA_PROGRAM.setAlpha(.5f);
LavenderClient.BLIT_ALPHA_PROGRAM.setAlpha(Lavender.CONFIG.structurePreviewAlpha());
return LavenderClient.BLIT_ALPHA_PROGRAM.program();
});
framebuffer.setClearColor(0f, 0f, 0f, 0f);
@@ -157,6 +167,7 @@ public static void initialize() {
var entry = ACTIVE_OVERLAYS.get(anchor);
var structure = entry.fetchStructure();
if (structure == null) return true;
var renderView = structure.asBlockRenderView();

// --- overlay rendering ---

@@ -172,24 +183,36 @@ public static void initialize() {
matrices.translate(anchor.getX(), anchor.getY(), anchor.getZ());

structure.forEachPredicate((pos, predicate) -> {
var state = context.world().getBlockState(testPos.set(anchor).move(pos)).rotate(StructureTemplate.inverse(entry.rotation));
var state = context.world()
.getBlockState(testPos.set(anchor).move(pos))
.rotate(StructureTemplate.inverse(entry.rotation));
var result = predicate.test(state);

if (result == BlockStatePredicate.Result.STATE_MATCH) {
if (result == BlockStatePredicate.Result.STATE_MATCH)
return;
} else if (!state.isAir() && result == BlockStatePredicate.Result.NO_MATCH) {
hasInvalidBlock.setTrue();

matrices.push();
matrices.translate(pos.getX(), pos.getY(), pos.getZ());
client.getBlockRenderManager().renderDamage(state, testPos, context.world(), matrices, overlayConsumer);
matrices.pop();
}
else if (entry.visibleLayer != -1 && pos.getY() != entry.visibleLayer)
return;
else if (!state.isAir() && result == BlockStatePredicate.Result.NO_MATCH)
renderBlockBreaking(context, pos, state, hasInvalidBlock, matrices, client, testPos, overlayConsumer);

if (entry.visibleLayer != -1 && pos.getY() != entry.visibleLayer) return;
renderOverlayBlock(matrices, CONSUMERS, pos, predicate, entry.rotation);
}, entry.rotation);
CONSUMERS.draw(); // render blocks before fluids

GlStateManager._depthMask(false); // Disable depth mask for rendering fluids
var matrixStack = RenderSystem.getModelViewStack().pushMatrix();
matrixStack.mul(matrices.peek().getPositionMatrix());
RenderSystem.applyModelViewMatrix();
structure.forEachPredicate((pos, predicate) -> {
if (entry.visibleLayer != -1 && pos.getY() != entry.visibleLayer)
return;

renderOverlayFluid(renderView, matrices, CONSUMERS, pos, predicate, entry.rotation);
}, entry.rotation);
CONSUMERS.draw(); // render fluids
RenderSystem.getModelViewStack().popMatrix();
RenderSystem.applyModelViewMatrix();
GlStateManager._depthMask(true);

matrices.pop();
}
@@ -234,11 +257,23 @@ public static void initialize() {
var structure = PENDING_OVERLAY.fetchStructure();
if (structure != null) {
if (client.player.raycast(5, client.getRenderTickCounter().getTickDelta(false), false) instanceof BlockHitResult target) {
var renderView = structure.asBlockRenderView();
var targetPos = target.getBlockPos().add(getPendingOffset(structure));
if (!client.player.isSneaking()) targetPos = targetPos.offset(target.getSide());

matrices.translate(targetPos.getX(), targetPos.getY(), targetPos.getZ());
structure.forEachPredicate((pos, predicate) -> renderOverlayBlock(matrices, CONSUMERS, pos, predicate, PENDING_OVERLAY.rotation), PENDING_OVERLAY.rotation);
CONSUMERS.draw(); // render blocks before fluids

GlStateManager._depthMask(false); // Disable depth mask for rendering fluids
var matrixStack = RenderSystem.getModelViewStack().pushMatrix();
matrixStack.mul(matrices.peek().getPositionMatrix());
RenderSystem.applyModelViewMatrix();
structure.forEachPredicate((pos, predicate) -> renderOverlayFluid(renderView, matrices, CONSUMERS, pos, predicate, PENDING_OVERLAY.rotation), PENDING_OVERLAY.rotation);
CONSUMERS.draw(); // render fluids
RenderSystem.getModelViewStack().popMatrix();
RenderSystem.applyModelViewMatrix();
GlStateManager._depthMask(true);
}
} else {
PENDING_OVERLAY = null;
@@ -294,7 +329,34 @@ private static Vec3i getPendingOffset(StructureTemplate structure) {
// @formatter:on
}

private static void renderOverlayBlock(MatrixStack matrices, VertexConsumerProvider consumers, BlockPos offsetInStructure, BlockStatePredicate block, BlockRotation rotation) {
private static void renderBlockBreaking(WorldRenderContext context, BlockPos pos, BlockState state, MutableBoolean hasInvalidBlock,
MatrixStack matrices, MinecraftClient client, BlockPos.Mutable testPos,
OverlayVertexConsumer overlayConsumer) {
hasInvalidBlock.setTrue();

matrices.push();
matrices.translate(pos.getX(), pos.getY(), pos.getZ());
client.getBlockRenderManager().renderDamage(state, testPos, context.world(), matrices, overlayConsumer);
matrices.pop();
}

private static void renderOverlayFluid(BlockRenderView renderView, MatrixStack matrices, VertexConsumerProvider consumers,
BlockPos offsetInStructure, BlockStatePredicate block, BlockRotation rotation) {
BlockState state = block.preview().rotate(rotation);
FluidState fluidState = state.getFluidState();

if (!fluidState.isEmpty()) {
RenderLayer renderLayer = RenderLayers.getFluidLayer(fluidState);
VertexConsumer consumer = consumers.getBuffer(renderLayer);
MinecraftClient.getInstance()
.getBlockRenderManager()
.renderFluid(offsetInStructure, renderView, consumer, state, fluidState);
}
}

private static void renderOverlayBlock(MatrixStack matrices, VertexConsumerProvider consumers, BlockPos offsetInStructure,
BlockStatePredicate block, BlockRotation rotation) {

matrices.push();
matrices.translate(offsetInStructure.getX(), offsetInStructure.getY(), offsetInStructure.getZ());

@@ -309,6 +371,7 @@ private static void renderOverlayBlock(MatrixStack matrices, VertexConsumerProvi
LightmapTextureManager.MAX_BLOCK_LIGHT_COORDINATE,
OverlayTexture.DEFAULT_UV
);

matrices.pop();
}

6 changes: 4 additions & 2 deletions src/main/resources/assets/lavender/lang/en_us.json
Original file line number Diff line number Diff line change
@@ -68,5 +68,7 @@
],

"text.lavender.book.bookmark.add": "Add Bookmark",
"text.lavender.book.bookmark.remove_hint": {"text": "Shift-click to remove", "color": "dark_gray"}
}
"text.lavender.book.bookmark.remove_hint": {"text": "Shift-click to remove", "color": "dark_gray"},

"text.config.lavender.option.structurePreviewAlpha": "Structure Preview Alpha"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"keys": {
"p": "minecraft:prismarine",
",": "minecraft:water",
"anchor": "minecraft:conduit"
},
"layers": [
[
" p ",
" p ",
"ppppp",
" p ",
" p "
],
[
" p ",
" ,,, ",
"p,,,p",
" ,,, ",
" p "
],
[
"ppppp",
"p,,,p",
"p,#,p",
"p,,,p",
"ppppp"
],
[
" p ",
" ,,, ",
"p,,,p",
" ,,, ",
" p "
],
[
" p ",
" p ",
"ppppp",
" p ",
" p "
]
]
}