Skip to content

Commit

Permalink
add new leaf culling impl, frametime FPS graph, overhaul hostile enti…
Browse files Browse the repository at this point in the history
…ty distance culling
  • Loading branch information
nthxny committed Feb 25, 2024
1 parent 5069cee commit 4c8c8c8
Show file tree
Hide file tree
Showing 12 changed files with 269 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import com.google.common.collect.ImmutableList;
import com.mojang.blaze3d.pipeline.RenderTarget;
import me.jellysquid.mods.sodium.client.SodiumClientMod;
import me.jellysquid.mods.sodium.client.compat.modernui.MuiGuiScaleHook;
import me.jellysquid.mods.sodium.client.gl.arena.staging.MappedStagingBuffer;
import me.jellysquid.mods.sodium.client.gl.device.RenderDevice;
Expand Down Expand Up @@ -255,6 +254,18 @@ public static OptionPage performance() {
.build()
);

groups.add(OptionGroup.createBuilder()
.add(OptionImpl.createBuilder(SodiumGameOptions.LeafCullingQuality.class, sodiumOpts)
.setName(Component.translatable("xenon.extras.options.leaf_culling.name"))
.setTooltip(Component.translatable("xenon.extras.options.leaf_culling.tooltip"))
.setControl(option -> new CyclingControl<>(option, SodiumGameOptions.LeafCullingQuality.class))
.setBinding((opts, value) -> opts.performance.leafCullingQuality = value, opts -> opts.performance.leafCullingQuality)
.setImpact(OptionImpact.MEDIUM)
.setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD)
.build()
).build()
);

groups.add(OptionGroup.createBuilder()
.add(OptionImpl.createBuilder(boolean.class, sodiumOpts)
.setName(Component.translatable("sodium.options.use_block_face_culling.name"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public static class PerformanceSettings {

public boolean animateOnlyVisibleTextures = true;
public boolean useEntityCulling = true;
public LeafCullingQuality leafCullingQuality = LeafCullingQuality.SOLID_AGGRESSIVE;
public boolean useFogOcclusion = true;
public boolean useBlockFaceCulling = true;
public boolean useCompactVertexFormat = true;
Expand Down Expand Up @@ -96,6 +97,28 @@ public boolean isFancy(GraphicsStatus graphicsMode) {
}
}

public enum LeafCullingQuality implements TextProvider {
NONE("options.leaf_culling.none"),
HOLLOW("options.leaf_culling.hollow"),
SOLID("options.leaf_culling.solid"),
SOLID_AGGRESSIVE("options.leaf_culling.solid_aggressive");

private final Component name;

LeafCullingQuality(String name) {
this.name = Component.translatable(name);
}

@Override
public Component getLocalizedName() {
return this.name;
}

public boolean isSolid() {
return this == SOLID || this == SOLID_AGGRESSIVE;
}
}

private static final Gson GSON = new GsonBuilder()
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
.setPrettyPrinting()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
package me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline;

import it.unimi.dsi.fastutil.objects.Object2ByteLinkedOpenHashMap;
import me.jellysquid.mods.sodium.client.SodiumClientMod;
import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.block.LeavesBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.shapes.BooleanOp;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
import org.embeddedt.embeddium.extras.leafculling.LeafCulling;

public class BlockOcclusionCache {
private static final byte UNCACHED_VALUE = (byte) 127;
Expand All @@ -34,7 +38,28 @@ public boolean shouldDrawSide(BlockState selfState, BlockGetter view, BlockPos p

BlockState adjState = view.getBlockState(adjPos);

if (selfState.skipRendering(adjState, facing) || (adjState.hidesNeighborFace(view, pos, selfState, facing.getOpposite()) && selfState.supportsExternalFaceHiding())) {
var skipRendering = selfState.skipRendering(adjState, facing);
var hideNeighbor = adjState.hidesNeighborFace(view, pos, selfState, facing.getOpposite());

if (selfState.getBlock() instanceof LeavesBlock )
{
if (SodiumClientMod.options().performance.leafCullingQuality == SodiumGameOptions.LeafCullingQuality.HOLLOW)
skipRendering = LeafCulling.shouldCullSide(view, pos, facing, 2);

if (adjState.getBlock() instanceof LeavesBlock && SodiumClientMod.options().performance.leafCullingQuality.isSolid())
{
var cullSelf = LeafCulling.surroundedByLeaves(view, pos);
var cullOther = LeafCulling.surroundedByLeaves(view, adjPos);

if (!cullSelf && cullOther)
return false;

if (cullSelf && cullOther)
return false;
}
}

if (skipRendering || (hideNeighbor && selfState.supportsExternalFaceHiding())) {
return false;
} else if (adjState.canOcclude()) {
VoxelShape selfShape = selfState.getFaceOcclusionShape(view, pos, facing);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,4 +108,8 @@ public ModelData modelData() {
public RenderType renderLayer() {
return this.renderLayer;
}

public void setRenderLayer(RenderType layer) {
this.renderLayer = layer;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

import com.mojang.blaze3d.vertex.PoseStack;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import me.jellysquid.mods.sodium.client.SodiumClientMod;
import me.jellysquid.mods.sodium.client.compat.ccl.SinkingVertexBuilder;
import me.jellysquid.mods.sodium.client.compat.forge.ForgeBlockRenderer;
import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions;
import me.jellysquid.mods.sodium.client.model.color.ColorProvider;
import me.jellysquid.mods.sodium.client.model.color.ColorProviderRegistry;
import me.jellysquid.mods.sodium.client.model.light.LightMode;
Expand All @@ -30,11 +32,13 @@
import net.minecraft.core.Direction;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.block.LeavesBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.SingleThreadedRandomSource;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.common.ForgeConfig;
import org.embeddedt.embeddium.api.BlockRendererRegistry;
import org.embeddedt.embeddium.extras.leafculling.LeafCulling;

import java.util.Arrays;
import java.util.List;
Expand Down Expand Up @@ -120,6 +124,27 @@ public void renderModel(BlockRenderContext ctx, ChunkBuildBuffers buffers) {
}

for (Direction face : DirectionUtil.ALL_DIRECTIONS) {

// custom leaf block rendering
if (ctx.state().getBlock() instanceof LeavesBlock
&& SodiumClientMod.options().performance.leafCullingQuality.isSolid()
&& LeafCulling.surroundedByLeaves(ctx.localSlice(), ctx.pos()))
{
var renderLayer = ctx.renderLayer();
ctx.setRenderLayer(RenderType.solid());

List<BakedQuad> quads = this.getGeometry(ctx, face);
var leafmaterial = DefaultMaterials.forRenderLayer(ctx.renderLayer());
var leafmeshBuilder = buffers.get(leafmaterial);

if (!quads.isEmpty() && this.isFaceVisible(ctx, face)) {
this.renderQuadList(ctx, leafmaterial, lighter, colorizer, renderOffset, leafmeshBuilder, quads, face);
}

ctx.setRenderLayer(renderLayer);
continue;
}

List<BakedQuad> quads = this.getGeometry(ctx, face);

if (!quads.isEmpty() && this.isFaceVisible(ctx, face)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
import net.minecraft.client.renderer.culling.Frustum;
import net.minecraft.client.renderer.entity.EntityRenderDispatcher;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.monster.Monster;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
Expand All @@ -17,13 +20,15 @@ public class EntityDispatcherMixin {
public <E extends Entity> void inject$shouldRender(E entity, Frustum clippingHelper, double cameraX, double cameraY, double cameraZ, CallbackInfoReturnable<Boolean> cir) {
if (!ExtrasConfig.entityDistanceCullingCache) return;

var isHostile = entity instanceof Monster;

if (!((IWhitelistCheck) entity.getType()).embPlus$isAllowed() && !ExtrasTools.isEntityWithinDistance(
entity,
cameraX,
cameraY,
cameraZ,
ExtrasConfig.entityCullingDistanceYCache,
ExtrasConfig.entityCullingDistanceXCache
isHostile ? ExtrasConfig.hostileDistanceYCache : ExtrasConfig.entityCullingDistanceYCache,
isHostile ? ExtrasConfig.hostileDistanceXCache : ExtrasConfig.entityCullingDistanceXCache
)) {
cir.setReturnValue(false);
}
Expand Down
19 changes: 16 additions & 3 deletions src/main/java/org/embeddedt/embeddium/extras/ExtrasConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import me.jellysquid.mods.sodium.mixin.extras.borderless.accessors.MainWindowAccessor;
import net.minecraft.client.Minecraft;
import net.minecraft.client.Options;
import net.minecraft.util.Mth;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.common.ForgeConfigSpec.*;
Expand Down Expand Up @@ -79,6 +80,7 @@ public class ExtrasConfig {
public static final IntValue tileEntityCullingDistanceX;
public static final IntValue tileEntityCullingDistanceY;
public static final BooleanValue entityDistanceCulling;
public static final IntValue hostileEntityModifier;
public static final IntValue entityCullingDistanceX;
public static final IntValue entityCullingDistanceY;
public static final ConfigValue<List<? extends String>> entityWhitelist; // QUICK CHECK
Expand All @@ -89,6 +91,8 @@ public class ExtrasConfig {
public static volatile boolean entityDistanceCullingCache;
public static volatile int entityCullingDistanceXCache;
public static volatile int entityCullingDistanceYCache;
public static volatile int hostileDistanceXCache;
public static volatile int hostileDistanceYCache;

// OTHERS
public static final EnumValue<AttachMode> borderlessAttachModeF11;
Expand Down Expand Up @@ -125,7 +129,7 @@ public class ExtrasConfig {

fpsDisplayMode = BUILDER
.comment("Configure FPS Display mode", "Complete mode gives you min FPS count and average count")
.defineEnum("fpsDisplay", FPSDisplayMode.ADVANCED);
.defineEnum("fpsDisplay", FPSDisplayMode.FRAMETIME);

fpsDisplayGravity = BUILDER
.comment("Configure FPS Display gravity", "Places counter on specified corner of your screen")
Expand Down Expand Up @@ -255,8 +259,9 @@ public class ExtrasConfig {
// xenonextras -> performance -> distanceCulling -> entities
BUILDER.push("entities");
entityDistanceCulling = BUILDER
.comment("Toggles distance culling for entities", "Maybe you use another mod for that :(")
.comment("Toggles distance culling for entities")
.define("enable", true);

entityCullingDistanceX = BUILDER
.comment("Configure horizontal max distance before cull entities", "Value is squared, default was 64^2 (or 64x64)")
.defineInRange("cullingMaxDistanceX", 4096, 0, Integer.MAX_VALUE);
Expand All @@ -265,6 +270,10 @@ public class ExtrasConfig {
.comment("Configure vertical max distance before cull entities", "Value is raw")
.defineInRange("cullingMaxDistanceY", 32, 0, 512);

hostileEntityModifier = BUILDER
.comment("Configure modifier applied to hostile entities", "Value is raw, 50% - 200%")
.defineInRange("hostileEntityModifier", 100, 25, 200);

entityWhitelist = BUILDER
.comment("List of all Entities to be ignored by distance culling", "Uses ResourceLocation to identify it", "Example 1: \"minecraft:bat\" - Ignores bats only", "Example 2: \"alexsmobs:*\" - ignores all entities for alexmobs mod")
.defineListAllowEmpty(Collections.singletonList("whitelist"), Arrays.asList(DEFAULT_ENTITIES_WHITELIST), (s) -> s.toString().contains(":"));
Expand Down Expand Up @@ -340,6 +349,10 @@ public static void updateCache(ModConfigEvent ignored) {
entityCullingDistanceXCache = entityCullingDistanceX.get();
entityCullingDistanceYCache = entityCullingDistanceY.get();

var x = Mth.sqrt(entityCullingDistanceXCache) * (hostileEntityModifier.get() / 100f);
hostileDistanceXCache = (int) (x * x);
hostileDistanceYCache = (int) (entityCullingDistanceYCache * (hostileEntityModifier.get() / 100f));

SodiumClientMod.logger().warn("Cache updated successfully");
}

Expand Down Expand Up @@ -367,7 +380,7 @@ public enum AttachMode {

/* CONFIG VALUES */
public enum FPSDisplayMode {
OFF, SIMPLE, ADVANCED;
OFF, SIMPLE, ADVANCED, FRAMETIME;

public boolean off() {
return this == OFF;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ public static void setFPSOptions(List<OptionGroup> groups, SodiumOptionsStorage
.setControl((option) -> new CyclingControl<>(option, ExtrasConfig.FPSDisplayMode.class, new Component[]{
Component.translatable("xenon.extras.options.common.off"),
Component.translatable("xenon.extras.options.common.simple"),
Component.translatable("xenon.extras.options.common.advanced")
Component.translatable("xenon.extras.options.common.advanced"),
Component.translatable("xenon.extras.options.common.frametime")
}))
.setBinding(
(opts, value) -> ExtrasConfig.fpsDisplayMode.set(value),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.network.chat.Component;
import net.minecraft.util.FrameTimer;
import net.minecraft.util.Mth;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.RenderGuiEvent;
import net.minecraftforge.client.event.RenderGuiOverlayEvent;
Expand Down Expand Up @@ -62,7 +64,7 @@ private static void renderFPSChar(Minecraft mc, GuiGraphics graphics, Font font,
// FPS
switch (mode) {
case SIMPLE -> DISPLAY.append(calculateFPS$getColor(mc)).add(fix(fps)).add(" ").add(MSG_FPS.getString()).add(ChatFormatting.RESET);
case ADVANCED -> {
case FRAMETIME, ADVANCED -> {
DISPLAY.append(calculateFPS$getColor(mc)).add(fix(fps)).add(ChatFormatting.RESET);
DISPLAY.append(calculateMinFPS$getColor(mc)).add(MSG_MIN).add(" ").add(fix(minFPS)).add(ChatFormatting.RESET);
DISPLAY.append(calculateAvgFPS$getColor(mc)).add(MSG_AVG).add(" ").add(fix(avgFPS)).add(ChatFormatting.RESET);
Expand Down Expand Up @@ -103,10 +105,61 @@ private static void renderFPSChar(Minecraft mc, GuiGraphics graphics, Font font,
}

graphics.drawString(font, displayString, posX, posY, 0xffffffff, true);

if (mode == ExtrasConfig.FPSDisplayMode.FRAMETIME)
drawChart(graphics, Minecraft.getInstance().getFrameTimer(), 0, (int) (graphics.guiWidth() / 5.5f), (int) (posY + font.lineHeight + 1));

DISPLAY.release();
graphics.pose().popPose();
}


private static void drawChart(GuiGraphics graphics, FrameTimer timer, int x, int width, int height) {
var mc = Minecraft.getInstance();

int logStart = timer.getLogStart();
int logEnd = timer.getLogEnd();
long[] along = timer.getLog();
int xPos = x;
int widthDiff = Math.max(0, along.length - width);
int wrapped = timer.wrapIndex(logStart + widthDiff);

int guiHeight = height;//graphics.guiHeight();

while(wrapped != logEnd) {
int barHeight = timer.scaleSampleTo(along[wrapped], 30, 60) / 4;
int heightMax = 30;
int color = getSampleColor(Mth.clamp(barHeight, 0, heightMax), 0, heightMax / 2, heightMax);
graphics.fill(RenderType.guiOverlay(), xPos, guiHeight, xPos + 1, guiHeight + barHeight, color);

++xPos;
wrapped = timer.wrapIndex(wrapped + 1);
}

}

private static int getSampleColor(int height, int heightMin, int heightMid, int heightMax) {
return height < heightMid
? colorLerp(1712789271, -1140870125, (float)height / (float)heightMid)
: colorLerp(-1140870125, -1140908238, (float)(height - heightMid) / (float)(heightMax - heightMid));
}

private static int colorLerp(int col1, int col2, float factor) {
int i = col1 >> 24 & 255;
int j = col1 >> 16 & 255;
int k = col1 >> 8 & 255;
int l = col1 & 255;
int m = col2 >> 24 & 255;
int n = col2 >> 16 & 255;
int o = col2 >> 8 & 255;
int p = col2 & 255;
int q = Mth.clamp((int)Mth.lerp(factor, (float)i, (float)m), 0, 255);
int r = Mth.clamp((int)Mth.lerp(factor, (float)j, (float)n), 0, 255);
int s = Mth.clamp((int)Mth.lerp(factor, (float)k, (float)o), 0, 255);
int t = Mth.clamp((int)Mth.lerp(factor, (float)l, (float)p), 0, 255);
return q << 24 | r << 16 | s << 8 | t;
}

private static ChatFormatting calculateFPS$getColor(Minecraft mc) {
fps = mc.getFps();
return ExtrasTools.colorByLow(fps);
Expand Down
Loading

0 comments on commit 4c8c8c8

Please sign in to comment.