Add event for adding framepasses (#10502)

This commit is contained in:
Matt authored and GitHub committed 2025-07-25 10:29:42 -07:00
1 parent 88904a1d09
commit 39f41fcda9
5 files changed
+167

No files matched your search

@@ -18,6 +18,14 @@
CloudStatus cloudstatus = this.minecraft.options.getCloudsType();
if (cloudstatus != CloudStatus.OFF) {
float f2 = this.level.effects().getCloudHeight();
@@ -499,6 +_,7 @@
}
this.addLateDebugPass(framegraphbuilder, vec3, fogparameters);
+ net.minecraftforge.client.event.ForgeEventFactoryClient.onLastFramePassAddition(framegraphbuilder, targets);
profilerfiller.popPush("framegraph");
framegraphbuilder.execute(p_367325_, new FrameGraphBuilder.Inspector() {
@Override
@@ -564,7 +_,11 @@
double d2 = vec3.z();
p_369478_.push("terrain");
@@ -0,0 +1,56 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.client.event;
import com.mojang.blaze3d.framegraph.FrameGraphBuilder;
import com.mojang.blaze3d.framegraph.FramePass;
import net.minecraft.client.renderer.LevelTargetBundle;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.eventbus.api.Event;
import org.jetbrains.annotations.ApiStatus;
import java.util.HashSet;
import java.util.Set;
/**
* Fired after all vanilla frame passes are added into the pass list.
*
* <p>This event is not {@linkplain net.minecraftforge.eventbus.api.Cancelable cancellable}, and does not
* {@linkplain HasResult have a result}.</p>
*
* <p>This event is fired on the {@linkplain net.minecraftforge.common.MinecraftForge#EVENT_BUS main Forge event bus},
* only on the {@linkplain net.minecraftforge.fml.LogicalSide#CLIENT logical client}.
*/
public final class AddFramePassEvent extends Event {
private final FrameGraphBuilder builder;
private final LevelTargetBundle bundle;
private final Set<String> addedNames = new HashSet<>();
@ApiStatus.Internal
public AddFramePassEvent(FrameGraphBuilder builder, LevelTargetBundle bundle) {
this.builder = builder;
this.bundle = bundle;
}
/**
* Adds a frame pass to the end of the pass list.
*
* @param rl Resource location for frame pass name. Use RLs to avoid duplicate names.
* @return Reference to pass to add modder rendering to.
* @throws IllegalArgumentException If the name is a duplicate.
*/
public FramePass createPass(ResourceLocation rl) {
String name = rl.toString();
if (!this.addedNames.add(name)) // false if the set didn't change
throw new IllegalArgumentException("Cannot create a frame pass with a duplicate name: " + name);
return this.builder.addPass(name);
}
public LevelTargetBundle getBundle() {
return bundle;
}
}
@@ -23,6 +23,7 @@ import com.google.common.collect.ImmutableMap;
import com.mojang.blaze3d.audio.Channel;
import com.mojang.blaze3d.platform.NativeImage;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.framegraph.FrameGraphBuilder;
import net.minecraft.client.Camera;
import net.minecraft.client.ClientRecipeBook;
import net.minecraft.client.DeltaTracker;
@@ -51,6 +52,7 @@ import net.minecraft.client.renderer.entity.state.ItemFrameRenderState;
import net.minecraft.client.renderer.entity.state.LivingEntityRenderState;
import net.minecraft.client.renderer.entity.state.PlayerRenderState;
import net.minecraft.client.renderer.special.SpecialModelRenderer;
import net.minecraft.client.renderer.LevelTargetBundle;
import net.minecraft.client.resources.PlayerSkin.Model;
import net.minecraft.client.resources.sounds.SoundInstance;
import net.minecraft.client.sounds.SoundEngine;
@@ -303,4 +305,8 @@ public final class ForgeEventFactoryClient {
// This is on the mod bus because it happens during the initial texture reload, which is while the Forge bus is shut down.
return fireModBus(new ModelEvent.RegisterModelStateDefinitions());
}
public static void onLastFramePassAddition(FrameGraphBuilder builder, LevelTargetBundle bundle) {
post(new AddFramePassEvent(builder, bundle));
}
}
@@ -0,0 +1,96 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.debug.client;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.client.event.AddFramePassEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import net.minecraftforge.gametest.GameTestHolder;
import net.minecraftforge.test.BaseTestMod;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.ShapeRenderer;
import net.minecraft.gametest.framework.GameTest;
import net.minecraft.gametest.framework.GameTestHelper;
import net.minecraft.resources.ResourceLocation;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.framegraph.FramePass;
@Mod(RenderFrameLayerTest.MODID)
@GameTestHolder("forge." + RenderFrameLayerTest.MODID)
public class RenderFrameLayerTest extends BaseTestMod {
public static final String MODID = "render_frame_layer_test";
public RenderFrameLayerTest(FMLJavaModLoadingContext context) {
super(context);
MinecraftForge.EVENT_BUS.addListener(RenderFrameLayerTest::renderTest);
}
private static ResourceLocation rl(String path) {
return ResourceLocation.fromNamespaceAndPath(MODID, path);
}
@GameTest(template = "forge:empty3x3x3")
public static void frame_passes_run(GameTestHelper helper) {
var passOne = helper.boolFlag("passOne");
var passTwo = helper.boolFlag("passOne");
helper.<AddFramePassEvent>addEventListener(event -> {
FramePass pass = event.createPass(rl(MODID + "test_1") );
event.getBundle().main = pass.readsAndWrites(event.getBundle().main);
pass.executes(() -> passOne.set(true));
pass = event.createPass(rl(MODID + "test_2"));
event.getBundle().main = pass.readsAndWrites(event.getBundle().main);
pass.executes(() -> passTwo.set(true));
});
helper.runAfterDelay(2, () -> {
helper.assertTrue(passOne.getBool(), "Pass One was not executed");
helper.assertTrue(passTwo.getBool(), "Pass Two was not executed");
helper.succeed();
});
}
/**
* If this is working, two white line box cubes will be rendered at ground level in a superflat world around (0,0)
*/
@SubscribeEvent
public static void renderTest(AddFramePassEvent event) {
var mainCamera = Minecraft.getInstance().gameRenderer.getMainCamera();
FramePass pass = event.createPass(rl(MODID));
event.getBundle().main = pass.readsAndWrites(event.getBundle().main);
pass.executes(() -> {
PoseStack ps = new PoseStack();
ps.translate(mainCamera.getPosition().multiply(-1,-1,-1));
ps.pushPose();
var buffSource = Minecraft.getInstance().renderBuffers().bufferSource();
var vc = buffSource.getBuffer(RenderType.lines());
ShapeRenderer.renderLineBox(ps, vc, 0, -60, 0, 10, -50, 10, 1f, 1f, 1f, 1f);
buffSource.endBatch();
ps.popPose();
});
pass = event.createPass(rl(MODID+"2"));
event.getBundle().main = pass.readsAndWrites(event.getBundle().main);
pass.executes(() -> {
PoseStack ps = new PoseStack();
ps.translate(mainCamera.getPosition().multiply(-1,-1,-1));
ps.pushPose();
var buffSource = Minecraft.getInstance().renderBuffers().bufferSource();
var vc = buffSource.getBuffer(RenderType.lines());
ShapeRenderer.renderLineBox(ps, vc, 1, -61, 1, 9, -49, 9, 1f, 1f, 1f, 1f);
buffSource.endBatch();
ps.popPose();
});
}
}
@@ -0,0 +1 @@
clientSideOnly=true