portal guns second pass
make more apis public for boogaloo
This commit is contained in:
1 parent
c7cb48edfb
commit
be9b18c4f5
25 files changed
+730
-197
No files matched your search
+40
-1
@@ -8,6 +8,10 @@ import java.util.Deque;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.WeakHashMap;
|
import java.util.WeakHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Predicate;
|
||||||
import net.minecraft.core.Holder;
|
import net.minecraft.core.Holder;
|
||||||
import net.minecraft.client.multiplayer.ClientLevel;
|
import net.minecraft.client.multiplayer.ClientLevel;
|
||||||
import net.minecraft.world.effect.MobEffect;
|
import net.minecraft.world.effect.MobEffect;
|
||||||
@@ -17,6 +21,9 @@ import net.minecraft.world.entity.LivingEntity;
|
|||||||
public final class ContractionAfterimages {
|
public final class ContractionAfterimages {
|
||||||
public static final int MAX_SAMPLES = 10;
|
public static final int MAX_SAMPLES = 10;
|
||||||
public static final int SAMPLE_LIFETIME_TICKS = 13;
|
public static final int SAMPLE_LIFETIME_TICKS = 13;
|
||||||
|
public static final int DEFAULT_COLOR = 0xFFD35A;
|
||||||
|
private static final List<Predicate<LivingEntity>> ACTIVATORS = new CopyOnWriteArrayList<>();
|
||||||
|
private static final List<Function<LivingEntity, Integer>> COLOR_PROVIDERS = new CopyOnWriteArrayList<>();
|
||||||
|
|
||||||
private static final Map<LivingEntity, Deque<Sample>> HISTORY = new WeakHashMap<>();
|
private static final Map<LivingEntity, Deque<Sample>> HISTORY = new WeakHashMap<>();
|
||||||
|
|
||||||
@@ -51,13 +58,45 @@ public final class ContractionAfterimages {
|
|||||||
return HISTORY.get(entity);
|
return HISTORY.get(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void addActivator(Predicate<LivingEntity> activator) {
|
||||||
|
ACTIVATORS.add(activator);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addColorProvider(Function<LivingEntity, Integer> provider) {
|
||||||
|
COLOR_PROVIDERS.add(provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int colorFor(Entity entity) {
|
||||||
|
if (!(entity instanceof LivingEntity living)) {
|
||||||
|
return DEFAULT_COLOR;
|
||||||
|
}
|
||||||
|
for (Function<LivingEntity, Integer> provider : COLOR_PROVIDERS) {
|
||||||
|
Integer color = provider.apply(living);
|
||||||
|
if (color != null) {
|
||||||
|
return color & 0xFFFFFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return DEFAULT_COLOR;
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean isActive(LivingEntity living) {
|
public static boolean isActive(LivingEntity living) {
|
||||||
Holder<MobEffect> holder = RoyalEffectHooks.contractedHolder();
|
Holder<MobEffect> holder = RoyalEffectHooks.contractedHolder();
|
||||||
boolean contracted = holder != null && living.hasEffect(holder);
|
boolean contracted = holder != null && living.hasEffect(holder);
|
||||||
boolean tuned = living instanceof net.minecraft.world.entity.player.Player player
|
boolean tuned = living instanceof net.minecraft.world.entity.player.Player player
|
||||||
&& TemporalTunerItem.isAvailable(player)
|
&& TemporalTunerItem.isAvailable(player)
|
||||||
&& TimeDilationApi.getRate(living) > 1.0D;
|
&& TimeDilationApi.getRate(living) > 1.0D;
|
||||||
return !living.isInvisible() && (contracted || tuned);
|
if (living.isInvisible()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (contracted || tuned) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for (Predicate<LivingEntity> activator : ACTIVATORS) {
|
||||||
|
if (activator.test(living)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static float fade(Sample sample, int now) {
|
public static float fade(Sample sample, int now) {
|
||||||
|
|||||||
+6
-6
@@ -10,12 +10,14 @@ import java.util.UUID;
|
|||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.multiplayer.ClientLevel;
|
import net.minecraft.client.multiplayer.ClientLevel;
|
||||||
import net.minecraft.client.renderer.LevelRenderer;
|
import net.minecraft.client.renderer.LevelRenderer;
|
||||||
|
import net.minecraft.client.renderer.RenderBuffers;
|
||||||
import net.minecraft.client.renderer.chunk.RenderRegionCache;
|
import net.minecraft.client.renderer.chunk.RenderRegionCache;
|
||||||
import net.minecraft.client.renderer.chunk.SectionRenderDispatcher;
|
import net.minecraft.client.renderer.chunk.SectionRenderDispatcher;
|
||||||
|
|
||||||
public final class PortalGunPortalRendererPool {
|
public final class PortalGunPortalRendererPool {
|
||||||
private static final int MAX_RENDERERS = 8;
|
private static final int MAX_RENDERERS = 8;
|
||||||
private static final long PORTAL_SECTION_BUDGET_NANOS = 4_166_666L;
|
private static final long PORTAL_SECTION_BUDGET_NANOS = 4_166_666L;
|
||||||
|
private static final RenderBuffers PORTAL_RENDER_BUFFERS = new RenderBuffers(2);
|
||||||
private static final LinkedHashMap<UUID, PortalRenderer> RENDERERS = new LinkedHashMap<>(8, 0.75F, true);
|
private static final LinkedHashMap<UUID, PortalRenderer> RENDERERS = new LinkedHashMap<>(8, 0.75F, true);
|
||||||
private static final Set<LevelRenderer> PROXY_RENDERERS = java.util.Collections.newSetFromMap(new IdentityHashMap<>());
|
private static final Set<LevelRenderer> PROXY_RENDERERS = java.util.Collections.newSetFromMap(new IdentityHashMap<>());
|
||||||
private static final ThreadLocal<Long> SECTION_BUDGET_DEADLINE = ThreadLocal.withInitial(() -> 0L);
|
private static final ThreadLocal<Long> SECTION_BUDGET_DEADLINE = ThreadLocal.withInitial(() -> 0L);
|
||||||
@@ -37,7 +39,7 @@ public final class PortalGunPortalRendererPool {
|
|||||||
minecraft,
|
minecraft,
|
||||||
minecraft.getEntityRenderDispatcher(),
|
minecraft.getEntityRenderDispatcher(),
|
||||||
minecraft.getBlockEntityRenderDispatcher(),
|
minecraft.getBlockEntityRenderDispatcher(),
|
||||||
minecraft.renderBuffers()
|
PORTAL_RENDER_BUFFERS
|
||||||
);
|
);
|
||||||
PROXY_RENDERERS.add(renderer);
|
PROXY_RENDERERS.add(renderer);
|
||||||
renderer.setLevel(minecraft.level);
|
renderer.setLevel(minecraft.level);
|
||||||
@@ -56,13 +58,11 @@ public final class PortalGunPortalRendererPool {
|
|||||||
return PROXY_RENDERERS.contains(renderer);
|
return PROXY_RENDERERS.contains(renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void beginFrame() {
|
public static net.minecraft.client.renderer.MultiBufferSource.BufferSource bufferSource() {
|
||||||
SECTION_BUDGET_DEADLINE.set(System.nanoTime() + PORTAL_SECTION_BUDGET_NANOS);
|
return PORTAL_RENDER_BUFFERS.bufferSource();
|
||||||
SCHEDULED_SECTION_REBUILDS.set(0);
|
|
||||||
SKIP_SET_NOT_DIRTY.set(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void beginSceneBudget() {
|
public static void beginFrame() {
|
||||||
SECTION_BUDGET_DEADLINE.set(System.nanoTime() + PORTAL_SECTION_BUDGET_NANOS);
|
SECTION_BUDGET_DEADLINE.set(System.nanoTime() + PORTAL_SECTION_BUDGET_NANOS);
|
||||||
SCHEDULED_SECTION_REBUILDS.set(0);
|
SCHEDULED_SECTION_REBUILDS.set(0);
|
||||||
SKIP_SET_NOT_DIRTY.set(false);
|
SKIP_SET_NOT_DIRTY.set(false);
|
||||||
|
|||||||
+4
-21
@@ -35,6 +35,9 @@ public final class PortalGunPortalViewAreaManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Scope enter(Minecraft minecraft, LevelRenderer renderer, UUID destinationId, Vec3 cameraPos, net.minecraft.client.Camera portalCamera) {
|
public static Scope enter(Minecraft minecraft, LevelRenderer renderer, UUID destinationId, Vec3 cameraPos, net.minecraft.client.Camera portalCamera) {
|
||||||
|
if (SodiumCompat.isLoaded()) {
|
||||||
|
return new SodiumScope(SodiumCompat.beginPortalView());
|
||||||
|
}
|
||||||
LevelRendererPortalViewAreaAccessor accessor = (LevelRendererPortalViewAreaAccessor) renderer;
|
LevelRendererPortalViewAreaAccessor accessor = (LevelRendererPortalViewAreaAccessor) renderer;
|
||||||
int viewDistance = minecraft.options.getEffectiveRenderDistance();
|
int viewDistance = minecraft.options.getEffectiveRenderDistance();
|
||||||
if (ownerLevel != minecraft.level || ownerViewDistance != viewDistance) {
|
if (ownerLevel != minecraft.level || ownerViewDistance != viewDistance) {
|
||||||
@@ -42,7 +45,6 @@ public final class PortalGunPortalViewAreaManager {
|
|||||||
ownerLevel = minecraft.level;
|
ownerLevel = minecraft.level;
|
||||||
ownerViewDistance = viewDistance;
|
ownerViewDistance = viewDistance;
|
||||||
}
|
}
|
||||||
Scope sodiumScope = SodiumCompat.isLoaded() ? new SodiumScope(SodiumCompat.beginPortalView(portalCamera)) : null;
|
|
||||||
ViewKey viewKey = new ViewKey(renderer, destinationId);
|
ViewKey viewKey = new ViewKey(renderer, destinationId);
|
||||||
ViewState state = VIEW_AREAS.get(viewKey);
|
ViewState state = VIEW_AREAS.get(viewKey);
|
||||||
if (state == null) {
|
if (state == null) {
|
||||||
@@ -80,7 +82,7 @@ public final class PortalGunPortalViewAreaManager {
|
|||||||
accessor.antarchy$setLastCameraSectionX(sectionX);
|
accessor.antarchy$setLastCameraSectionX(sectionX);
|
||||||
accessor.antarchy$setLastCameraSectionY(sectionY);
|
accessor.antarchy$setLastCameraSectionY(sectionY);
|
||||||
accessor.antarchy$setLastCameraSectionZ(sectionZ);
|
accessor.antarchy$setLastCameraSectionZ(sectionZ);
|
||||||
return sodiumScope == null ? scope : new CombinedScope(scope, sodiumScope);
|
return scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean routeSectionCompiled(SectionRenderDispatcher.RenderSection section) {
|
public static boolean routeSectionCompiled(SectionRenderDispatcher.RenderSection section) {
|
||||||
@@ -231,25 +233,6 @@ public final class PortalGunPortalViewAreaManager {
|
|||||||
void close();
|
void close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class CombinedScope implements Scope {
|
|
||||||
private final Scope viewAreaScope;
|
|
||||||
private final Scope sodiumScope;
|
|
||||||
|
|
||||||
private CombinedScope(Scope viewAreaScope, Scope sodiumScope) {
|
|
||||||
this.viewAreaScope = viewAreaScope;
|
|
||||||
this.sodiumScope = sodiumScope;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() {
|
|
||||||
try {
|
|
||||||
viewAreaScope.close();
|
|
||||||
} finally {
|
|
||||||
sodiumScope.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class SodiumScope implements Scope {
|
private static final class SodiumScope implements Scope {
|
||||||
private final SodiumCompat.TerrainScope terrainScope;
|
private final SodiumCompat.TerrainScope terrainScope;
|
||||||
|
|
||||||
|
|||||||
+173
-77
@@ -22,6 +22,7 @@ import com.mojang.blaze3d.vertex.MeshData;
|
|||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
import com.mojang.blaze3d.vertex.Tesselator;
|
import com.mojang.blaze3d.vertex.Tesselator;
|
||||||
import com.mojang.blaze3d.vertex.VertexFormat;
|
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||||
|
import com.mojang.blaze3d.vertex.VertexSorting;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@@ -43,7 +44,9 @@ import net.minecraft.world.entity.Entity;
|
|||||||
import net.minecraft.world.phys.AABB;
|
import net.minecraft.world.phys.AABB;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
import org.joml.Matrix4f;
|
import org.joml.Matrix4f;
|
||||||
|
import org.joml.Matrix4fStack;
|
||||||
import org.joml.Vector4f;
|
import org.joml.Vector4f;
|
||||||
|
import org.lwjgl.opengl.GL11;
|
||||||
import org.joml.Quaternionf;
|
import org.joml.Quaternionf;
|
||||||
|
|
||||||
public final class PortalGunPortalViewRenderer {
|
public final class PortalGunPortalViewRenderer {
|
||||||
@@ -58,7 +61,6 @@ public final class PortalGunPortalViewRenderer {
|
|||||||
private static final ResourceLocation BLUE_OVERLAY = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/vfx/portal_gun_portal_blue.png");
|
private static final ResourceLocation BLUE_OVERLAY = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/vfx/portal_gun_portal_blue.png");
|
||||||
private static final ResourceLocation ORANGE_OVERLAY = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/vfx/portal_gun_portal_orange.png");
|
private static final ResourceLocation ORANGE_OVERLAY = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/vfx/portal_gun_portal_orange.png");
|
||||||
private static final TextureTarget[] PORTAL_TARGETS = new TextureTarget[MAX_RECURSION_DEPTH + 1];
|
private static final TextureTarget[] PORTAL_TARGETS = new TextureTarget[MAX_RECURSION_DEPTH + 1];
|
||||||
private static TextureTarget depthBackup;
|
|
||||||
private static ShaderInstance portalViewShader;
|
private static ShaderInstance portalViewShader;
|
||||||
private static boolean renderingPortalView;
|
private static boolean renderingPortalView;
|
||||||
private static boolean loggedRendererActivation;
|
private static boolean loggedRendererActivation;
|
||||||
@@ -87,6 +89,7 @@ public final class PortalGunPortalViewRenderer {
|
|||||||
|
|
||||||
public static void releaseTargets() {
|
public static void releaseTargets() {
|
||||||
PortalSceneRenderTrace.reset();
|
PortalSceneRenderTrace.reset();
|
||||||
|
PortalGunPortalVisibilityQueries.clear();
|
||||||
for (int i = 0; i < PORTAL_TARGETS.length; i++) {
|
for (int i = 0; i < PORTAL_TARGETS.length; i++) {
|
||||||
TextureTarget target = PORTAL_TARGETS[i];
|
TextureTarget target = PORTAL_TARGETS[i];
|
||||||
if (target != null) {
|
if (target != null) {
|
||||||
@@ -96,10 +99,6 @@ public final class PortalGunPortalViewRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
java.util.Arrays.fill(TARGET_ALLOCATION_FAILURES, null);
|
java.util.Arrays.fill(TARGET_ALLOCATION_FAILURES, null);
|
||||||
if (depthBackup != null) {
|
|
||||||
depthBackup.destroyBuffers();
|
|
||||||
depthBackup = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void render(Camera camera, Matrix4f poseMatrix, Matrix4f projectionMatrix, DeltaTracker tickCounter) {
|
public static void render(Camera camera, Matrix4f poseMatrix, Matrix4f projectionMatrix, DeltaTracker tickCounter) {
|
||||||
@@ -125,7 +124,7 @@ public final class PortalGunPortalViewRenderer {
|
|||||||
Vec3 cameraPos = camera.getPosition();
|
Vec3 cameraPos = camera.getPosition();
|
||||||
Vec3 rootLook = new Vec3(camera.getLookVector()).normalize();
|
Vec3 rootLook = new Vec3(camera.getLookVector()).normalize();
|
||||||
Vec3 rootUp = new Vec3(camera.getUpVector()).normalize();
|
Vec3 rootUp = new Vec3(camera.getUpVector()).normalize();
|
||||||
Matrix4f rootViewMatrix = new Matrix4f().rotation(PortalGunTransformUtil.orientationQuaternion(rootLook, rootUp).conjugate(new Quaternionf()));
|
Matrix4f rootViewMatrix = new Matrix4f(poseMatrix);
|
||||||
List<PortalGunPortalEntity> portals = collectVisiblePortals(minecraft, cameraPos);
|
List<PortalGunPortalEntity> portals = collectVisiblePortals(minecraft, cameraPos);
|
||||||
if (portals.isEmpty()) {
|
if (portals.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
@@ -135,10 +134,6 @@ public final class PortalGunPortalViewRenderer {
|
|||||||
loggedMissingPortalViewShader = true;
|
loggedMissingPortalViewShader = true;
|
||||||
Antarchy.LOGGER.error("Portal gun destination view shader is unavailable; skipping destination render");
|
Antarchy.LOGGER.error("Portal gun destination view shader is unavailable; skipping destination render");
|
||||||
}
|
}
|
||||||
minecraft.getMainRenderTarget().bindWrite(true);
|
|
||||||
for (PortalGunPortalEntity portal : portals) {
|
|
||||||
drawPortalOverlay(minecraft, cameraPos, rootViewMatrix, portal);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Vec3 effectiveCameraPos = cameraPos;
|
Vec3 effectiveCameraPos = cameraPos;
|
||||||
@@ -168,16 +163,8 @@ public final class PortalGunPortalViewRenderer {
|
|||||||
return linked != null && linked.isAlive();
|
return linked != null && linked.isAlive();
|
||||||
})
|
})
|
||||||
.sorted((left, right) -> Integer.compare(rootScreenClips.get(right).area(), rootScreenClips.get(left).area()))
|
.sorted((left, right) -> Integer.compare(rootScreenClips.get(right).area(), rootScreenClips.get(left).area()))
|
||||||
|
.limit(MAX_PORTAL_VIEWS_PER_FRAME)
|
||||||
.toList();
|
.toList();
|
||||||
Set<PortalGunPortalEntity> selectedPortalSet = Collections.newSetFromMap(new IdentityHashMap<>());
|
|
||||||
selectedPortalSet.addAll(selectedPortals);
|
|
||||||
List<PortalGunPortalEntity> renderOrder = new ArrayList<>(portals.size());
|
|
||||||
renderOrder.addAll(selectedPortals);
|
|
||||||
for (PortalGunPortalEntity portal : portals) {
|
|
||||||
if (!selectedPortalSet.contains(portal)) {
|
|
||||||
renderOrder.add(portal);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
long linkedPortalCount = renderablePortals.stream()
|
long linkedPortalCount = renderablePortals.stream()
|
||||||
.filter(portal -> portal.getLinkedPortal() != null && portal.getLinkedPortal().isAlive())
|
.filter(portal -> portal.getLinkedPortal() != null && portal.getLinkedPortal().isAlive())
|
||||||
.count();
|
.count();
|
||||||
@@ -210,47 +197,43 @@ public final class PortalGunPortalViewRenderer {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (selectedPortals.isEmpty()) {
|
if (selectedPortals.isEmpty()) {
|
||||||
minecraft.getMainRenderTarget().bindWrite(true);
|
|
||||||
for (PortalGunPortalEntity portal : portals) {
|
|
||||||
drawPortalOverlay(minecraft, cameraPos, rootViewMatrix, portal);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
RenderContext rootContext = new RenderContext(effectiveCameraPos, rootLook, rootUp, rootViewMatrix);
|
RenderContext rootContext = new RenderContext(effectiveCameraPos, rootLook, rootUp, rootViewMatrix);
|
||||||
PortalViewBudget viewBudget = new PortalViewBudget(MAX_PORTAL_VIEWS_PER_FRAME);
|
boolean directStencil = PortalStencilTarget.supportsDirect(minecraft.getMainRenderTarget());
|
||||||
|
PortalViewBudget fallbackBudget = directStencil ? null : new PortalViewBudget(MAX_PORTAL_VIEWS_PER_FRAME);
|
||||||
renderingPortalView = true;
|
renderingPortalView = true;
|
||||||
boolean projectionBackedUp = false;
|
boolean projectionBackedUp = false;
|
||||||
try {
|
try {
|
||||||
RenderSystem.backupProjectionMatrix();
|
RenderSystem.backupProjectionMatrix();
|
||||||
projectionBackedUp = true;
|
projectionBackedUp = true;
|
||||||
for (PortalGunPortalEntity portal : renderOrder) {
|
for (PortalGunPortalEntity portal : selectedPortals) {
|
||||||
if (!selectedPortalSet.contains(portal)) {
|
|
||||||
minecraft.getMainRenderTarget().bindWrite(true);
|
|
||||||
drawPortalOverlay(minecraft, cameraPos, rootViewMatrix, portal);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
PortalGunPortalEntity linkedPortal = portal.getLinkedPortal();
|
PortalGunPortalEntity linkedPortal = portal.getLinkedPortal();
|
||||||
if (linkedPortal == null || !linkedPortal.isAlive()) {
|
if (linkedPortal == null || !linkedPortal.isAlive()) {
|
||||||
minecraft.getMainRenderTarget().bindWrite(true);
|
|
||||||
drawPortalOverlay(minecraft, cameraPos, rootViewMatrix, portal);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
boolean rendered;
|
boolean rendered;
|
||||||
try {
|
try {
|
||||||
rendered = renderPortalSurfaceDirect(minecraft, cameraEntity, tickCounter, rootContext, rootProjectionMatrix, portal, linkedPortal, rootScreenClips.get(portal));
|
if (directStencil) {
|
||||||
|
rendered = renderPortalSurfaceDirect(minecraft, cameraEntity, tickCounter, rootContext, rootProjectionMatrix, portal, linkedPortal, rootScreenClips.get(portal));
|
||||||
|
} else {
|
||||||
|
int textureId = renderPortalSurface(minecraft, cameraEntity, tickCounter, fallbackBudget, rootContext,
|
||||||
|
rootProjectionMatrix, portal, linkedPortal, 0, rootScreenClips.get(portal));
|
||||||
|
minecraft.gameRenderer.resetProjectionMatrix(rootProjectionMatrix);
|
||||||
|
minecraft.getMainRenderTarget().bindWrite(true);
|
||||||
|
rendered = textureId >= 0 && drawPortalQuad(cameraPos, rootViewMatrix, rootProjectionMatrix,
|
||||||
|
minecraft.getMainRenderTarget().width, minecraft.getMainRenderTarget().height,
|
||||||
|
portal, partialTick, textureId, rootScreenClips.get(portal));
|
||||||
|
}
|
||||||
} catch (RuntimeException exception) {
|
} catch (RuntimeException exception) {
|
||||||
logRenderFailure(minecraft, exception);
|
logRenderFailure(minecraft, exception);
|
||||||
RenderSystem.restoreProjectionMatrix();
|
RenderSystem.restoreProjectionMatrix();
|
||||||
projectionBackedUp = false;
|
projectionBackedUp = false;
|
||||||
RenderSystem.backupProjectionMatrix();
|
RenderSystem.backupProjectionMatrix();
|
||||||
projectionBackedUp = true;
|
projectionBackedUp = true;
|
||||||
minecraft.getMainRenderTarget().bindWrite(true);
|
|
||||||
drawPortalOverlay(minecraft, cameraPos, rootViewMatrix, portal);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!rendered) {
|
if (!rendered) {
|
||||||
minecraft.getMainRenderTarget().bindWrite(true);
|
|
||||||
drawPortalOverlay(minecraft, cameraPos, rootViewMatrix, portal);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
RenderSystem.restoreProjectionMatrix();
|
RenderSystem.restoreProjectionMatrix();
|
||||||
@@ -258,14 +241,8 @@ public final class PortalGunPortalViewRenderer {
|
|||||||
RenderSystem.backupProjectionMatrix();
|
RenderSystem.backupProjectionMatrix();
|
||||||
projectionBackedUp = true;
|
projectionBackedUp = true;
|
||||||
minecraft.getMainRenderTarget().bindWrite(true);
|
minecraft.getMainRenderTarget().bindWrite(true);
|
||||||
ScreenClip clip = rootScreenClips.get(portal);
|
|
||||||
String portalPairKey = portal.getUUID() + "->" + linkedPortal.getUUID();
|
String portalPairKey = portal.getUUID() + "->" + linkedPortal.getUUID();
|
||||||
boolean composited;
|
if (loggedPortalViewComposites.add(portalPairKey)) {
|
||||||
try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(portalPairKey, "direct-framebuffer", "target=" + targetWidth + "x" + targetHeight)) {
|
|
||||||
composited = true;
|
|
||||||
drawAnimatedPortalOverlay(minecraft, cameraPos, rootViewMatrix, portal);
|
|
||||||
}
|
|
||||||
if (composited && loggedPortalViewComposites.add(portalPairKey)) {
|
|
||||||
Antarchy.LOGGER.info("Portal gun destination view rendered directly source={} destination={} target={}x{}", portal.getId(), linkedPortal.getId(), targetWidth, targetHeight);
|
Antarchy.LOGGER.info("Portal gun destination view rendered directly source={} destination={} target={}x{}", portal.getId(), linkedPortal.getId(), targetWidth, targetHeight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -386,14 +363,10 @@ public final class PortalGunPortalViewRenderer {
|
|||||||
}
|
}
|
||||||
int width = target.width;
|
int width = target.width;
|
||||||
int height = target.height;
|
int height = target.height;
|
||||||
if (depthBackup == null) {
|
|
||||||
depthBackup = new TextureTarget(width, height, true, Minecraft.ON_OSX);
|
|
||||||
} else if (depthBackup.width != width || depthBackup.height != height) {
|
|
||||||
depthBackup.resize(width, height, Minecraft.ON_OSX);
|
|
||||||
}
|
|
||||||
RenderContext transformedContext = transformContext(currentContext, sourcePortal, destinationPortal);
|
RenderContext transformedContext = transformContext(currentContext, sourcePortal, destinationPortal);
|
||||||
float partialTick = tickCounter.getGameTimeDeltaPartialTick(true);
|
float partialTick = tickCounter.getGameTimeDeltaPartialTick(true);
|
||||||
Matrix4f clippedProjection = applyPortalClipPlane(baseProjectionMatrix, transformedContext, destinationPortal);
|
Matrix4f clippedProjection = applyPortalClipPlane(baseProjectionMatrix, transformedContext, destinationPortal);
|
||||||
|
Matrix4f apertureCullProjection = cropProjectionToScreenClip(clippedProjection, clip, width, height);
|
||||||
PortalCamera portalCamera = new PortalCamera();
|
PortalCamera portalCamera = new PortalCamera();
|
||||||
portalCamera.setup(minecraft.level, cameraEntity, partialTick, transformedContext.cameraPos(), transformedContext.look(), transformedContext.up());
|
portalCamera.setup(minecraft.level, cameraEntity, partialTick, transformedContext.cameraPos(), transformedContext.look(), transformedContext.up());
|
||||||
String portalPairKey = sourcePortal.getUUID() + "->" + destinationPortal.getUUID();
|
String portalPairKey = sourcePortal.getUUID() + "->" + destinationPortal.getUUID();
|
||||||
@@ -407,6 +380,8 @@ public final class PortalGunPortalViewRenderer {
|
|||||||
RenderTarget previousTransparencyTarget = transparencyTarget == null ? null : transparencyTarget.antarchy$getScreenTarget();
|
RenderTarget previousTransparencyTarget = transparencyTarget == null ? null : transparencyTarget.antarchy$getScreenTarget();
|
||||||
PortalStencilTarget.Scope stencilScope = null;
|
PortalStencilTarget.Scope stencilScope = null;
|
||||||
boolean contextPushed = false;
|
boolean contextPushed = false;
|
||||||
|
boolean renderDestination = PortalGunPortalVisibilityQueries.shouldRender(sourcePortal.getUUID(), destinationPortal.getUUID());
|
||||||
|
PortalSceneRenderTrace.event(portalPairKey, "destination-render-decision", "render=" + renderDestination + " clip=" + clip.width() + "x" + clip.height());
|
||||||
try {
|
try {
|
||||||
if (entityEffectTarget != null) {
|
if (entityEffectTarget != null) {
|
||||||
entityEffectTarget.antarchy$setScreenTarget(target);
|
entityEffectTarget.antarchy$setScreenTarget(target);
|
||||||
@@ -417,22 +392,33 @@ public final class PortalGunPortalViewRenderer {
|
|||||||
minecraft.gameRenderer.resetProjectionMatrix(clippedProjection);
|
minecraft.gameRenderer.resetProjectionMatrix(clippedProjection);
|
||||||
int maskTexture = minecraft.getTextureManager().getTexture(BLUE_OVERLAY).getId();
|
int maskTexture = minecraft.getTextureManager().getTexture(BLUE_OVERLAY).getId();
|
||||||
try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(portalPairKey, "direct-stencil-mask", "clip=" + clip.width() + "x" + clip.height())) {
|
try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(portalPairKey, "direct-stencil-mask", "clip=" + clip.width() + "x" + clip.height())) {
|
||||||
stencilScope = PortalStencilTarget.beginDirect(target, depthBackup,
|
stencilScope = PortalStencilTarget.beginDirect(target, () -> {
|
||||||
() -> drawPortalQuad(currentContext.cameraPos(), currentContext.viewMatrix(), baseProjectionMatrix, width, height, sourcePortal, partialTick, maskTexture, clip));
|
boolean queryStarted = PortalGunPortalVisibilityQueries.begin(sourcePortal.getUUID(), destinationPortal.getUUID());
|
||||||
|
try {
|
||||||
|
drawPortalQuad(currentContext.cameraPos(), currentContext.viewMatrix(), baseProjectionMatrix, width, height, sourcePortal, partialTick, maskTexture, clip);
|
||||||
|
} finally {
|
||||||
|
PortalGunPortalVisibilityQueries.end(sourcePortal.getUUID(), destinationPortal.getUUID(), queryStarted);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
() -> clearDepthInPortalStencil(minecraft),
|
||||||
|
() -> restorePortalApertureDepth(minecraft, currentContext.cameraPos(), currentContext.viewMatrix(), baseProjectionMatrix, sourcePortal, partialTick));
|
||||||
|
}
|
||||||
|
if (!renderDestination) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
RenderSystem.enableScissor(clip.x(), clip.y(), clip.width(), clip.height());
|
RenderSystem.enableScissor(clip.x(), clip.y(), clip.width(), clip.height());
|
||||||
PortalGunPortalRenderState.pushPortalView(new PortalGunPortalRenderState.PortalRenderContext(
|
PortalGunPortalRenderState.pushPortalView(new PortalGunPortalRenderState.PortalRenderContext(
|
||||||
sourcePortal.getWorldPortalShape(), destinationPortal.getWorldPortalShape(), transformedContext.cameraPos(),
|
sourcePortal.getWorldPortalShape(), destinationPortal.getWorldPortalShape(), transformedContext.cameraPos(),
|
||||||
transformedContext.look(), transformedContext.up(), transformedContext.viewMatrix(), clippedProjection,
|
transformedContext.look(), transformedContext.up(), transformedContext.viewMatrix(), clippedProjection,
|
||||||
0, true, destinationPortal.getUUID()));
|
0, false, destinationPortal.getUUID()));
|
||||||
contextPushed = true;
|
contextPushed = true;
|
||||||
proxyRenderer.prepareCullFrustum(portalCamera.getPosition(), transformedContext.viewMatrix(), clippedProjection);
|
proxyRenderer.prepareCullFrustum(portalCamera.getPosition(), transformedContext.viewMatrix(), apertureCullProjection);
|
||||||
PortalGunPortalViewAreaManager.Scope areaScope = PortalGunPortalViewAreaManager.enter(
|
PortalGunPortalViewAreaManager.Scope areaScope = PortalGunPortalViewAreaManager.enter(
|
||||||
minecraft, proxyRenderer, destinationPortal.getUUID(), transformedContext.cameraPos(), portalCamera);
|
minecraft, proxyRenderer, destinationPortal.getUUID(), transformedContext.cameraPos(), portalCamera);
|
||||||
try {
|
try {
|
||||||
try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(portalPairKey, "direct-manual-scene", "target=" + width + "x" + height)) {
|
try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(portalPairKey, "direct-manual-scene", "target=" + width + "x" + height)) {
|
||||||
PortalGunProxySceneRenderer.render(minecraft, proxyRenderer, portalCamera, partialTick,
|
PortalGunProxySceneRenderer.render(minecraft, proxyRenderer, portalCamera, partialTick,
|
||||||
transformedContext.viewMatrix(), clippedProjection, portalPairKey);
|
transformedContext.viewMatrix(), clippedProjection, apertureCullProjection, portalPairKey);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
areaScope.close();
|
areaScope.close();
|
||||||
@@ -448,7 +434,7 @@ public final class PortalGunPortalViewRenderer {
|
|||||||
stencilScope.close();
|
stencilScope.close();
|
||||||
}
|
}
|
||||||
if (contextPushed) {
|
if (contextPushed) {
|
||||||
PortalGunPortalRenderState.popPortalView(true);
|
PortalGunPortalRenderState.popPortalView(false);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (transparencyTarget != null) {
|
if (transparencyTarget != null) {
|
||||||
@@ -495,6 +481,7 @@ public final class PortalGunPortalViewRenderer {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
Matrix4f clippedProjectionMatrix = applyPortalClipPlane(baseProjectionMatrix, transformedContext, destinationPortal);
|
Matrix4f clippedProjectionMatrix = applyPortalClipPlane(baseProjectionMatrix, transformedContext, destinationPortal);
|
||||||
|
Matrix4f apertureCullProjection = cropProjectionToScreenClip(clippedProjectionMatrix, clip, target.width, target.height);
|
||||||
boolean renderAll = true;
|
boolean renderAll = true;
|
||||||
PortalCamera portalCamera = new PortalCamera();
|
PortalCamera portalCamera = new PortalCamera();
|
||||||
portalCamera.setup(minecraft.level, cameraEntity, tickCounter.getGameTimeDeltaPartialTick(true), transformedContext.cameraPos(), transformedContext.look(), transformedContext.up());
|
portalCamera.setup(minecraft.level, cameraEntity, tickCounter.getGameTimeDeltaPartialTick(true), transformedContext.cameraPos(), transformedContext.look(), transformedContext.up());
|
||||||
@@ -550,14 +537,14 @@ public final class PortalGunPortalViewRenderer {
|
|||||||
PortalGunPortalRenderState.pushPortalView(portalRenderContext);
|
PortalGunPortalRenderState.pushPortalView(portalRenderContext);
|
||||||
portalRenderStatePushed = true;
|
portalRenderStatePushed = true;
|
||||||
try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(portalPairKey, "prepare-portal-view", "camera=" + transformedContext.cameraPos())) {
|
try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(portalPairKey, "prepare-portal-view", "camera=" + transformedContext.cameraPos())) {
|
||||||
proxyRenderer.prepareCullFrustum(portalCamera.getPosition(), transformedContext.viewMatrix(), clippedProjectionMatrix);
|
proxyRenderer.prepareCullFrustum(portalCamera.getPosition(), transformedContext.viewMatrix(), apertureCullProjection);
|
||||||
}
|
}
|
||||||
try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(portalPairKey, "activate-view-area", "destination=" + destinationPortal.getUUID())) {
|
try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(portalPairKey, "activate-view-area", "destination=" + destinationPortal.getUUID())) {
|
||||||
PortalGunPortalViewAreaManager.Scope scope = PortalGunPortalViewAreaManager.enter(minecraft, proxyRenderer, destinationPortal.getUUID(), transformedContext.cameraPos(), portalCamera);
|
PortalGunPortalViewAreaManager.Scope scope = PortalGunPortalViewAreaManager.enter(minecraft, proxyRenderer, destinationPortal.getUUID(), transformedContext.cameraPos(), portalCamera);
|
||||||
ignored.close();
|
ignored.close();
|
||||||
try {
|
try {
|
||||||
try (PortalSceneRenderTrace.Phase sceneTrace = PortalSceneRenderTrace.begin(portalPairKey, "manual-scene-subpass", "target=" + target.width + "x" + target.height)) {
|
try (PortalSceneRenderTrace.Phase sceneTrace = PortalSceneRenderTrace.begin(portalPairKey, "manual-scene-subpass", "target=" + target.width + "x" + target.height)) {
|
||||||
PortalGunProxySceneRenderer.render(minecraft, proxyRenderer, portalCamera, partialTick, transformedContext.viewMatrix(), clippedProjectionMatrix, portalPairKey);
|
PortalGunProxySceneRenderer.render(minecraft, proxyRenderer, portalCamera, partialTick, transformedContext.viewMatrix(), clippedProjectionMatrix, apertureCullProjection, portalPairKey);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
try (PortalSceneRenderTrace.Phase releaseTrace = PortalSceneRenderTrace.begin(portalPairKey, "release-view-area", "destination=" + destinationPortal.getUUID())) {
|
try (PortalSceneRenderTrace.Phase releaseTrace = PortalSceneRenderTrace.begin(portalPairKey, "release-view-area", "destination=" + destinationPortal.getUUID())) {
|
||||||
@@ -749,6 +736,20 @@ public final class PortalGunPortalViewRenderer {
|
|||||||
return new ScreenClip(scissorX, scissorY, scissorWidth, scissorHeight);
|
return new ScreenClip(scissorX, scissorY, scissorWidth, scissorHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Matrix4f cropProjectionToScreenClip(Matrix4f projectionMatrix, ScreenClip clip, int width, int height) {
|
||||||
|
float left = (float) (clip.x() * 2.0D / width - 1.0D);
|
||||||
|
float right = (float) ((clip.x() + clip.width()) * 2.0D / width - 1.0D);
|
||||||
|
float bottom = (float) (clip.y() * 2.0D / height - 1.0D);
|
||||||
|
float top = (float) ((clip.y() + clip.height()) * 2.0D / height - 1.0D);
|
||||||
|
float widthNdc = Math.max(1.0E-5F, right - left);
|
||||||
|
float heightNdc = Math.max(1.0E-5F, top - bottom);
|
||||||
|
float scaleX = 2.0F / widthNdc;
|
||||||
|
float scaleY = 2.0F / heightNdc;
|
||||||
|
float offsetX = -(right + left) / widthNdc;
|
||||||
|
float offsetY = -(top + bottom) / heightNdc;
|
||||||
|
return new Matrix4f().translate(offsetX, offsetY, 0.0F).scale(scaleX, scaleY, 1.0F).mul(projectionMatrix);
|
||||||
|
}
|
||||||
|
|
||||||
private static List<Vector4f> clipPolygon(List<Vector4f> vertices, boolean nearPlane) {
|
private static List<Vector4f> clipPolygon(List<Vector4f> vertices, boolean nearPlane) {
|
||||||
if (vertices.isEmpty()) {
|
if (vertices.isEmpty()) {
|
||||||
return vertices;
|
return vertices;
|
||||||
@@ -793,18 +794,9 @@ public final class PortalGunPortalViewRenderer {
|
|||||||
if (clip == null || width <= 0 || height <= 0) {
|
if (clip == null || width <= 0 || height <= 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
PortalGunWorldPortalShape shape = portal.getWorldPortalShape().scaleAperture(portal.getPortalVisualScale(partialTick));
|
PortalGunWorldPortalShape shape = portal.getWorldPortalShape().scaleAperture(portal.getPortalVisualScale(partialTick) * PORTAL_APERTURE_SCALE);
|
||||||
Matrix4f combined = new Matrix4f(projectionMatrix).mul(viewMatrix);
|
Matrix4f combined = new Matrix4f(projectionMatrix).mul(viewMatrix);
|
||||||
double apertureInset = (1.0D - PORTAL_APERTURE_SCALE) * 0.5D;
|
List<Vector4f> polygon = projectPortalPolygon(combined, cameraPos, shape);
|
||||||
double apertureStart = apertureInset;
|
|
||||||
double apertureEnd = 1.0D - apertureInset;
|
|
||||||
List<Vector4f> polygon = new ArrayList<>(4);
|
|
||||||
polygon.add(projectPortalVertex(combined, cameraPos, shape, apertureStart, apertureStart));
|
|
||||||
polygon.add(projectPortalVertex(combined, cameraPos, shape, apertureEnd, apertureStart));
|
|
||||||
polygon.add(projectPortalVertex(combined, cameraPos, shape, apertureEnd, apertureEnd));
|
|
||||||
polygon.add(projectPortalVertex(combined, cameraPos, shape, apertureStart, apertureEnd));
|
|
||||||
polygon = clipPolygon(polygon, false);
|
|
||||||
polygon = clipPolygon(polygon, true);
|
|
||||||
if (polygon.size() < 3) {
|
if (polygon.size() < 3) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -818,29 +810,133 @@ public final class PortalGunPortalViewRenderer {
|
|||||||
if (mesh == null) {
|
if (mesh == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
Matrix4fStack modelViewStack = RenderSystem.getModelViewStack();
|
||||||
|
Matrix4f previousProjection = new Matrix4f(RenderSystem.getProjectionMatrix());
|
||||||
|
VertexSorting previousSorting = RenderSystem.getVertexSorting();
|
||||||
|
modelViewStack.pushMatrix();
|
||||||
try {
|
try {
|
||||||
RenderSystem.disableBlend();
|
RenderSystem.disableBlend();
|
||||||
RenderSystem.depthMask(false);
|
RenderSystem.depthMask(false);
|
||||||
RenderSystem.enableDepthTest();
|
RenderSystem.enableDepthTest();
|
||||||
RenderSystem.disableCull();
|
RenderSystem.disableCull();
|
||||||
|
modelViewStack.identity();
|
||||||
|
RenderSystem.applyModelViewMatrix();
|
||||||
|
RenderSystem.setProjectionMatrix(new Matrix4f(), previousSorting);
|
||||||
portalViewShader.setSampler("Sampler0", textureId);
|
portalViewShader.setSampler("Sampler0", textureId);
|
||||||
RenderSystem.setShader(() -> portalViewShader);
|
RenderSystem.setShader(() -> portalViewShader);
|
||||||
RenderSystem.setShaderTexture(0, textureId);
|
RenderSystem.setShaderTexture(0, textureId);
|
||||||
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
|
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
|
||||||
BufferUploader.drawWithShader(mesh);
|
BufferUploader.drawWithShader(mesh);
|
||||||
} finally {
|
} finally {
|
||||||
|
RenderSystem.setProjectionMatrix(previousProjection, previousSorting);
|
||||||
|
modelViewStack.popMatrix();
|
||||||
|
RenderSystem.applyModelViewMatrix();
|
||||||
restorePortalDrawState();
|
restorePortalDrawState();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Vector4f projectPortalVertex(Matrix4f combined, Vec3 cameraPos, PortalGunWorldPortalShape shape, double u, double v) {
|
private static void clearDepthInPortalStencil(Minecraft minecraft) {
|
||||||
Vec3 worldPosition = shape.center()
|
int previousDepthFunction = GL11.glGetInteger(GL11.GL_DEPTH_FUNC);
|
||||||
.add(shape.right().scale((u * 2.0D - 1.0D) * shape.halfWidth()))
|
RenderSystem.enableDepthTest();
|
||||||
.add(shape.up().scale((v * 2.0D - 1.0D) * shape.halfHeight()))
|
RenderSystem.depthMask(true);
|
||||||
.add(shape.normal().scale(SURFACE_OFFSET));
|
RenderSystem.colorMask(false, false, false, false);
|
||||||
Vec3 relative = worldPosition.subtract(cameraPos);
|
GL11.glDepthFunc(GL11.GL_ALWAYS);
|
||||||
return new Vector4f((float) relative.x, (float) relative.y, (float) relative.z, 1.0F).mul(combined);
|
BufferBuilder buffer = Tesselator.getInstance().begin(VertexFormat.Mode.TRIANGLES, DefaultVertexFormat.POSITION);
|
||||||
|
buffer.addVertex(-1.0F, -1.0F, 1.0F);
|
||||||
|
buffer.addVertex(3.0F, -1.0F, 1.0F);
|
||||||
|
buffer.addVertex(-1.0F, 3.0F, 1.0F);
|
||||||
|
MeshData mesh = buffer.build();
|
||||||
|
try {
|
||||||
|
drawClipSpaceMesh(minecraft, mesh);
|
||||||
|
} finally {
|
||||||
|
GL11.glDepthFunc(previousDepthFunction);
|
||||||
|
RenderSystem.colorMask(true, true, true, true);
|
||||||
|
RenderSystem.depthMask(true);
|
||||||
|
RenderSystem.enableDepthTest();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void restorePortalApertureDepth(Minecraft minecraft, Vec3 cameraPos, Matrix4f viewMatrix, Matrix4f projectionMatrix,
|
||||||
|
PortalGunPortalEntity portal, float partialTick) {
|
||||||
|
PortalGunWorldPortalShape shape = portal.getWorldPortalShape().scaleAperture(portal.getPortalVisualScale(partialTick) * PORTAL_APERTURE_SCALE);
|
||||||
|
Matrix4f combined = new Matrix4f(projectionMatrix).mul(viewMatrix);
|
||||||
|
List<Vector4f> polygon = projectPortalPolygon(combined, cameraPos, shape);
|
||||||
|
if (polygon.size() < 3) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
BufferBuilder buffer = Tesselator.getInstance().begin(VertexFormat.Mode.TRIANGLES, DefaultVertexFormat.POSITION);
|
||||||
|
for (int index = 1; index + 1 < polygon.size(); index++) {
|
||||||
|
addDepthVertex(buffer, polygon.get(0));
|
||||||
|
addDepthVertex(buffer, polygon.get(index));
|
||||||
|
addDepthVertex(buffer, polygon.get(index + 1));
|
||||||
|
}
|
||||||
|
MeshData mesh = buffer.build();
|
||||||
|
int previousDepthFunction = GL11.glGetInteger(GL11.GL_DEPTH_FUNC);
|
||||||
|
RenderSystem.enableDepthTest();
|
||||||
|
RenderSystem.depthMask(true);
|
||||||
|
RenderSystem.colorMask(false, false, false, false);
|
||||||
|
GL11.glDepthFunc(GL11.GL_ALWAYS);
|
||||||
|
try {
|
||||||
|
drawClipSpaceMesh(minecraft, mesh);
|
||||||
|
} finally {
|
||||||
|
GL11.glDepthFunc(previousDepthFunction);
|
||||||
|
RenderSystem.colorMask(true, true, true, true);
|
||||||
|
RenderSystem.depthMask(true);
|
||||||
|
RenderSystem.enableDepthTest();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void addDepthVertex(BufferBuilder buffer, Vector4f clipPosition) {
|
||||||
|
float inverseW = 1.0F / clipPosition.w();
|
||||||
|
buffer.addVertex(clipPosition.x() * inverseW, clipPosition.y() * inverseW, clipPosition.z() * inverseW);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void drawClipSpaceMesh(Minecraft minecraft, MeshData mesh) {
|
||||||
|
if (mesh == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Matrix4fStack modelViewStack = RenderSystem.getModelViewStack();
|
||||||
|
boolean cullEnabled = GL11.glIsEnabled(GL11.GL_CULL_FACE);
|
||||||
|
boolean blendEnabled = GL11.glIsEnabled(GL11.GL_BLEND);
|
||||||
|
Matrix4f previousProjection = new Matrix4f(RenderSystem.getProjectionMatrix());
|
||||||
|
VertexSorting previousSorting = RenderSystem.getVertexSorting();
|
||||||
|
modelViewStack.pushMatrix();
|
||||||
|
try {
|
||||||
|
RenderSystem.disableCull();
|
||||||
|
RenderSystem.disableBlend();
|
||||||
|
modelViewStack.identity();
|
||||||
|
RenderSystem.applyModelViewMatrix();
|
||||||
|
RenderSystem.setProjectionMatrix(new Matrix4f(), previousSorting);
|
||||||
|
RenderSystem.setShader(GameRenderer::getPositionShader);
|
||||||
|
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
|
||||||
|
BufferUploader.drawWithShader(mesh);
|
||||||
|
} finally {
|
||||||
|
RenderSystem.setProjectionMatrix(previousProjection, previousSorting);
|
||||||
|
modelViewStack.popMatrix();
|
||||||
|
RenderSystem.applyModelViewMatrix();
|
||||||
|
if (cullEnabled) {
|
||||||
|
RenderSystem.enableCull();
|
||||||
|
} else {
|
||||||
|
RenderSystem.disableCull();
|
||||||
|
}
|
||||||
|
if (blendEnabled) {
|
||||||
|
RenderSystem.enableBlend();
|
||||||
|
} else {
|
||||||
|
RenderSystem.disableBlend();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Vector4f> projectPortalPolygon(Matrix4f combined, Vec3 cameraPos, PortalGunWorldPortalShape shape) {
|
||||||
|
Vec3[] corners = shape.getCorners(SURFACE_OFFSET);
|
||||||
|
List<Vector4f> polygon = new ArrayList<>(corners.length);
|
||||||
|
for (Vec3 corner : corners) {
|
||||||
|
Vec3 relative = corner.subtract(cameraPos);
|
||||||
|
polygon.add(new Vector4f((float) relative.x, (float) relative.y, (float) relative.z, 1.0F).mul(combined));
|
||||||
|
}
|
||||||
|
polygon = clipPolygon(polygon, false);
|
||||||
|
return clipPolygon(polygon, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void addPortalViewVertex(BufferBuilder buffer, Vector4f clipPosition) {
|
private static void addPortalViewVertex(BufferBuilder buffer, Vector4f clipPosition) {
|
||||||
@@ -852,10 +948,10 @@ public final class PortalGunPortalViewRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void renderPortalTransitionEntities(Minecraft minecraft, Vec3 cameraPos, float partialTick, PortalGunPortalEntity sourcePortal, PortalGunPortalEntity destinationPortal) {
|
private static void renderPortalTransitionEntities(Minecraft minecraft, Vec3 cameraPos, float partialTick, PortalGunPortalEntity sourcePortal, PortalGunPortalEntity destinationPortal) {
|
||||||
if (minecraft.level == null || minecraft.getEntityRenderDispatcher() == null || minecraft.renderBuffers() == null) {
|
if (minecraft.level == null || minecraft.getEntityRenderDispatcher() == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
MultiBufferSource.BufferSource bufferSource = minecraft.renderBuffers().bufferSource();
|
MultiBufferSource.BufferSource bufferSource = PortalGunPortalRendererPool.bufferSource();
|
||||||
PoseStack poseStack = new PoseStack();
|
PoseStack poseStack = new PoseStack();
|
||||||
AABB transitionBounds = sourcePortal.getWorldPortalShape().getBoundsForCulling();
|
AABB transitionBounds = sourcePortal.getWorldPortalShape().getBoundsForCulling();
|
||||||
List<Entity> renderEntities = minecraft.level.getEntities(
|
List<Entity> renderEntities = minecraft.level.getEntities(
|
||||||
|
|||||||
+93
@@ -0,0 +1,93 @@
|
|||||||
|
package com.craisinlord.antarchy.content.client.renderer;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
import org.lwjgl.opengl.GL15;
|
||||||
|
|
||||||
|
public final class PortalGunPortalVisibilityQueries {
|
||||||
|
private static final int MAX_ENTRIES = 128;
|
||||||
|
private static final LinkedHashMap<Pair, QueryState> QUERIES = new LinkedHashMap<>(16, 0.75F, true);
|
||||||
|
|
||||||
|
private PortalGunPortalVisibilityQueries() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean shouldRender(UUID source, UUID destination) {
|
||||||
|
QueryState state = QUERIES.get(new Pair(source, destination));
|
||||||
|
if (state == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (state.inFlight && GL15.glGetQueryObjecti(state.query, GL15.GL_QUERY_RESULT_AVAILABLE) != 0) {
|
||||||
|
state.visible = GL15.glGetQueryObjecti(state.query, GL15.GL_QUERY_RESULT) != 0;
|
||||||
|
state.hasResult = true;
|
||||||
|
state.inFlight = false;
|
||||||
|
PortalSceneRenderTrace.event(source + "->" + destination, "visibility-query-result", "visible=" + state.visible);
|
||||||
|
}
|
||||||
|
return !state.hasResult || state.visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean begin(UUID source, UUID destination) {
|
||||||
|
Pair pair = new Pair(source, destination);
|
||||||
|
QueryState state = QUERIES.computeIfAbsent(pair, key -> new QueryState(GL15.glGenQueries()));
|
||||||
|
if (state.inFlight || state.active) {
|
||||||
|
trim();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
state.active = true;
|
||||||
|
try {
|
||||||
|
GL15.glBeginQuery(GL15.GL_SAMPLES_PASSED, state.query);
|
||||||
|
} catch (RuntimeException | Error exception) {
|
||||||
|
state.active = false;
|
||||||
|
throw exception;
|
||||||
|
}
|
||||||
|
trim();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void end(UUID source, UUID destination, boolean started) {
|
||||||
|
if (!started) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QueryState state = QUERIES.get(new Pair(source, destination));
|
||||||
|
if (state == null || !state.active) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
GL15.glEndQuery(GL15.GL_SAMPLES_PASSED);
|
||||||
|
state.active = false;
|
||||||
|
state.inFlight = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void clear() {
|
||||||
|
for (QueryState state : QUERIES.values()) {
|
||||||
|
GL15.glDeleteQueries(state.query);
|
||||||
|
}
|
||||||
|
QUERIES.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void trim() {
|
||||||
|
Iterator<Map.Entry<Pair, QueryState>> iterator = QUERIES.entrySet().iterator();
|
||||||
|
while (QUERIES.size() > MAX_ENTRIES && iterator.hasNext()) {
|
||||||
|
QueryState state = iterator.next().getValue();
|
||||||
|
if (!state.active) {
|
||||||
|
GL15.glDeleteQueries(state.query);
|
||||||
|
iterator.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private record Pair(UUID source, UUID destination) {
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class QueryState {
|
||||||
|
private final int query;
|
||||||
|
private boolean active;
|
||||||
|
private boolean inFlight;
|
||||||
|
private boolean hasResult;
|
||||||
|
private boolean visible = true;
|
||||||
|
|
||||||
|
private QueryState(int query) {
|
||||||
|
this.query = query;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+67
-35
@@ -4,6 +4,7 @@ import com.craisinlord.antarchy.mixins.client.LevelRendererPortalSceneInvoker;
|
|||||||
import com.craisinlord.antarchy.mixins.client.LevelRendererPortalViewAreaAccessor;
|
import com.craisinlord.antarchy.mixins.client.LevelRendererPortalViewAreaAccessor;
|
||||||
import com.mojang.blaze3d.systems.RenderSystem;
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
import com.mojang.blaze3d.platform.Lighting;
|
import com.mojang.blaze3d.platform.Lighting;
|
||||||
|
import com.mojang.blaze3d.shaders.FogShape;
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
import net.minecraft.client.Camera;
|
import net.minecraft.client.Camera;
|
||||||
import net.minecraft.client.CloudStatus;
|
import net.minecraft.client.CloudStatus;
|
||||||
@@ -13,7 +14,6 @@ import net.minecraft.client.renderer.LevelRenderer;
|
|||||||
import net.minecraft.client.renderer.chunk.SectionRenderDispatcher;
|
import net.minecraft.client.renderer.chunk.SectionRenderDispatcher;
|
||||||
import net.minecraft.client.renderer.MultiBufferSource;
|
import net.minecraft.client.renderer.MultiBufferSource;
|
||||||
import net.minecraft.client.renderer.RenderType;
|
import net.minecraft.client.renderer.RenderType;
|
||||||
import net.minecraft.client.particle.ParticleRenderType;
|
|
||||||
import net.minecraft.client.renderer.culling.Frustum;
|
import net.minecraft.client.renderer.culling.Frustum;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
@@ -30,12 +30,21 @@ public final class PortalGunProxySceneRenderer {
|
|||||||
private PortalGunProxySceneRenderer() {
|
private PortalGunProxySceneRenderer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void render(Minecraft minecraft, LevelRenderer renderer, Camera camera, float partialTick, Matrix4f modelViewMatrix, Matrix4f projectionMatrix, String tracePair) {
|
public static void render(Minecraft minecraft, LevelRenderer renderer, Camera camera, float partialTick, Matrix4f modelViewMatrix, Matrix4f projectionMatrix, Matrix4f cullProjectionMatrix, String tracePair) {
|
||||||
|
Matrix4fStack outerModelViewStack = RenderSystem.getModelViewStack();
|
||||||
|
float previousFogStart = RenderSystem.getShaderFogStart();
|
||||||
|
float previousFogEnd = RenderSystem.getShaderFogEnd();
|
||||||
|
float[] previousFogColor = RenderSystem.getShaderFogColor().clone();
|
||||||
|
FogShape previousFogShape = RenderSystem.getShaderFogShape();
|
||||||
|
outerModelViewStack.pushMatrix();
|
||||||
|
outerModelViewStack.identity();
|
||||||
|
RenderSystem.applyModelViewMatrix();
|
||||||
|
try {
|
||||||
Vec3 cameraPosition = camera.getPosition();
|
Vec3 cameraPosition = camera.getPosition();
|
||||||
double cameraX = cameraPosition.x;
|
double cameraX = cameraPosition.x;
|
||||||
double cameraY = cameraPosition.y;
|
double cameraY = cameraPosition.y;
|
||||||
double cameraZ = cameraPosition.z;
|
double cameraZ = cameraPosition.z;
|
||||||
Frustum frustum = new Frustum(modelViewMatrix, projectionMatrix);
|
Frustum frustum = new Frustum(modelViewMatrix, cullProjectionMatrix);
|
||||||
frustum.prepare(cameraX, cameraY, cameraZ);
|
frustum.prepare(cameraX, cameraY, cameraZ);
|
||||||
LevelRendererPortalSceneInvoker scene = (LevelRendererPortalSceneInvoker) renderer;
|
LevelRendererPortalSceneInvoker scene = (LevelRendererPortalSceneInvoker) renderer;
|
||||||
float renderDistance = minecraft.gameRenderer.getRenderDistance();
|
float renderDistance = minecraft.gameRenderer.getRenderDistance();
|
||||||
@@ -55,29 +64,33 @@ public final class PortalGunProxySceneRenderer {
|
|||||||
() -> FogRenderer.setupFog(camera, FogRenderer.FogMode.FOG_SKY, renderDistance, foggy, partialTick));
|
() -> FogRenderer.setupFog(camera, FogRenderer.FogMode.FOG_SKY, renderDistance, foggy, partialTick));
|
||||||
}
|
}
|
||||||
|
|
||||||
try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(tracePair, "frustum-and-visibility", "renderDistance=" + rendererAccessDistance(renderer))) {
|
boolean sodium = SodiumCompat.isLoaded();
|
||||||
|
try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(tracePair, "frustum-and-visibility", "renderDistance=" + (sodium ? minecraft.options.getEffectiveRenderDistance() : rendererAccessDistance(renderer)))) {
|
||||||
FogRenderer.setupFog(camera, FogRenderer.FogMode.FOG_TERRAIN, Math.max(renderDistance, 32.0F), foggy, partialTick);
|
FogRenderer.setupFog(camera, FogRenderer.FogMode.FOG_TERRAIN, Math.max(renderDistance, 32.0F), foggy, partialTick);
|
||||||
scene.antarchy$setupPortalScene(camera, frustum, false, minecraft.player != null && minecraft.player.isSpectator());
|
scene.antarchy$setupPortalScene(camera, frustum, false, minecraft.player != null && minecraft.player.isSpectator());
|
||||||
}
|
}
|
||||||
LevelRendererPortalViewAreaAccessor viewAreaAccessor = (LevelRendererPortalViewAreaAccessor) renderer;
|
LevelRendererPortalViewAreaAccessor viewAreaAccessor = sodium ? null : (LevelRendererPortalViewAreaAccessor) renderer;
|
||||||
ObjectArrayList<SectionRenderDispatcher.RenderSection> fullVisibleSections = viewAreaAccessor.antarchy$getVisibleSections();
|
int visibleSectionCount = 0;
|
||||||
ObjectArrayList<SectionRenderDispatcher.RenderSection> budgetedVisibleSections = new ObjectArrayList<>();
|
if (viewAreaAccessor != null) {
|
||||||
PortalGunPortalRendererPool.beginSceneBudget();
|
ObjectArrayList<SectionRenderDispatcher.RenderSection> fullVisibleSections = viewAreaAccessor.antarchy$getVisibleSections();
|
||||||
int scannedVisibleSections = 0;
|
ObjectArrayList<SectionRenderDispatcher.RenderSection> budgetedVisibleSections = new ObjectArrayList<>();
|
||||||
while (scannedVisibleSections < fullVisibleSections.size() && PortalGunPortalRendererPool.remainingSectionBudgetNanos() > 0L) {
|
int scannedVisibleSections = 0;
|
||||||
budgetedVisibleSections.add(fullVisibleSections.get(scannedVisibleSections++));
|
while (scannedVisibleSections < fullVisibleSections.size() && PortalGunPortalRendererPool.remainingSectionBudgetNanos() > 0L) {
|
||||||
}
|
budgetedVisibleSections.add(fullVisibleSections.get(scannedVisibleSections++));
|
||||||
try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(tracePair, "compile-visible-sections", "visibleTotal=" + fullVisibleSections.size() + " visibleScanned=" + scannedVisibleSections + " rebuildBudgetNanos=" + PortalGunPortalRendererPool.remainingSectionBudgetNanos())) {
|
|
||||||
viewAreaAccessor.antarchy$setVisibleSections(budgetedVisibleSections);
|
|
||||||
try {
|
|
||||||
scene.antarchy$compilePortalSections(camera);
|
|
||||||
} finally {
|
|
||||||
viewAreaAccessor.antarchy$setVisibleSections(fullVisibleSections);
|
|
||||||
}
|
}
|
||||||
|
try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(tracePair, "compile-visible-sections", "visibleTotal=" + fullVisibleSections.size() + " visibleScanned=" + scannedVisibleSections + " rebuildBudgetNanos=" + PortalGunPortalRendererPool.remainingSectionBudgetNanos())) {
|
||||||
|
viewAreaAccessor.antarchy$setVisibleSections(budgetedVisibleSections);
|
||||||
|
try {
|
||||||
|
scene.antarchy$compilePortalSections(camera);
|
||||||
|
} finally {
|
||||||
|
viewAreaAccessor.antarchy$setVisibleSections(fullVisibleSections);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
visibleSectionCount = fullVisibleSections.size();
|
||||||
}
|
}
|
||||||
PortalSceneRenderTrace.event(tracePair, "visible-sections-ready", "count=" + viewAreaAccessor.antarchy$getVisibleSections().size() + " scheduledRebuilds=" + PortalGunPortalRendererPool.scheduledSectionRebuilds());
|
PortalSceneRenderTrace.event(tracePair, "visible-sections-ready", "renderer=" + (sodium ? "sodium" : "vanilla") + " count=" + visibleSectionCount + " scheduledRebuilds=" + PortalGunPortalRendererPool.scheduledSectionRebuilds());
|
||||||
|
|
||||||
try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(tracePair, "opaque-terrain-layers", "sections=" + viewAreaAccessor.antarchy$getVisibleSections().size())) {
|
try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(tracePair, "opaque-terrain-layers", "sections=" + visibleSectionCount)) {
|
||||||
RenderSystem.enableDepthTest();
|
RenderSystem.enableDepthTest();
|
||||||
RenderSystem.depthMask(true);
|
RenderSystem.depthMask(true);
|
||||||
scene.antarchy$renderPortalSectionLayer(RenderType.solid(), cameraX, cameraY, cameraZ, modelViewMatrix, projectionMatrix);
|
scene.antarchy$renderPortalSectionLayer(RenderType.solid(), cameraX, cameraY, cameraZ, modelViewMatrix, projectionMatrix);
|
||||||
@@ -98,7 +111,7 @@ public final class PortalGunProxySceneRenderer {
|
|||||||
RenderSystem.applyModelViewMatrix();
|
RenderSystem.applyModelViewMatrix();
|
||||||
}
|
}
|
||||||
PoseStack poseStack = new PoseStack();
|
PoseStack poseStack = new PoseStack();
|
||||||
MultiBufferSource.BufferSource buffers = minecraft.renderBuffers().bufferSource();
|
MultiBufferSource.BufferSource buffers = PortalGunPortalRendererPool.bufferSource();
|
||||||
try {
|
try {
|
||||||
int entityCount = 0;
|
int entityCount = 0;
|
||||||
try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(tracePair, "entities", "dispatch-start")) {
|
try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(tracePair, "entities", "dispatch-start")) {
|
||||||
@@ -122,32 +135,40 @@ public final class PortalGunProxySceneRenderer {
|
|||||||
PortalSceneRenderTrace.event(tracePair, "entities-dispatched", "count=" + entityCount);
|
PortalSceneRenderTrace.event(tracePair, "entities-dispatched", "count=" + entityCount);
|
||||||
|
|
||||||
int blockEntityCount = 0;
|
int blockEntityCount = 0;
|
||||||
try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(tracePair, "block-entities", "visibleSections=" + viewAreaAccessor.antarchy$getVisibleSections().size())) {
|
try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(tracePair, "block-entities", "visibleSections=" + visibleSectionCount)) {
|
||||||
for (var section : viewAreaAccessor.antarchy$getVisibleSections()) {
|
if (sodium) {
|
||||||
for (BlockEntity blockEntity : section.getCompiled().getRenderableBlockEntities()) {
|
int[] count = {0};
|
||||||
|
SodiumCompat.forEachVisibleBlockEntity(blockEntity -> {
|
||||||
renderBlockEntity(minecraft, blockEntity, cameraX, cameraY, cameraZ, partialTick, poseStack, buffers);
|
renderBlockEntity(minecraft, blockEntity, cameraX, cameraY, cameraZ, partialTick, poseStack, buffers);
|
||||||
blockEntityCount++;
|
count[0]++;
|
||||||
}
|
});
|
||||||
}
|
blockEntityCount = count[0];
|
||||||
synchronized (viewAreaAccessor.antarchy$getGlobalBlockEntities()) {
|
} else {
|
||||||
for (BlockEntity blockEntity : viewAreaAccessor.antarchy$getGlobalBlockEntities()) {
|
for (var section : viewAreaAccessor.antarchy$getVisibleSections()) {
|
||||||
if (frustum.isVisible(new AABB(blockEntity.getBlockPos()).inflate(1.0D))) {
|
for (BlockEntity blockEntity : section.getCompiled().getRenderableBlockEntities()) {
|
||||||
renderBlockEntity(minecraft, blockEntity, cameraX, cameraY, cameraZ, partialTick, poseStack, buffers);
|
renderBlockEntity(minecraft, blockEntity, cameraX, cameraY, cameraZ, partialTick, poseStack, buffers);
|
||||||
blockEntityCount++;
|
blockEntityCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
synchronized (viewAreaAccessor.antarchy$getGlobalBlockEntities()) {
|
||||||
|
for (BlockEntity blockEntity : viewAreaAccessor.antarchy$getGlobalBlockEntities()) {
|
||||||
|
if (frustum.isVisible(new AABB(blockEntity.getBlockPos()).inflate(1.0D))) {
|
||||||
|
renderBlockEntity(minecraft, blockEntity, cameraX, cameraY, cameraZ, partialTick, poseStack, buffers);
|
||||||
|
blockEntityCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
buffers.endBatch();
|
buffers.endBatch();
|
||||||
PortalSceneRenderTrace.event(tracePair, "block-entities-dispatched", "count=" + blockEntityCount);
|
PortalSceneRenderTrace.event(tracePair, "block-entities-dispatched", "count=" + blockEntityCount);
|
||||||
|
|
||||||
try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(tracePair, "translucent-and-particles", "rendering")) {
|
try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(tracePair, "translucent-and-particles", "rendering")) {
|
||||||
minecraft.particleEngine.render(minecraft.gameRenderer.lightTexture(), camera, partialTick, frustum, type -> !type.isTranslucent());
|
|
||||||
scene.antarchy$renderPortalSectionLayer(RenderType.translucent(), cameraX, cameraY, cameraZ, modelViewMatrix, projectionMatrix);
|
scene.antarchy$renderPortalSectionLayer(RenderType.translucent(), cameraX, cameraY, cameraZ, modelViewMatrix, projectionMatrix);
|
||||||
buffers.endBatch(RenderType.lines());
|
buffers.endBatch(RenderType.lines());
|
||||||
buffers.endBatch();
|
buffers.endBatch();
|
||||||
scene.antarchy$renderPortalSectionLayer(RenderType.tripwire(), cameraX, cameraY, cameraZ, modelViewMatrix, projectionMatrix);
|
scene.antarchy$renderPortalSectionLayer(RenderType.tripwire(), cameraX, cameraY, cameraZ, modelViewMatrix, projectionMatrix);
|
||||||
minecraft.particleEngine.render(minecraft.gameRenderer.lightTexture(), camera, partialTick, frustum, ParticleRenderType::isTranslucent);
|
minecraft.particleEngine.render(minecraft.gameRenderer.lightTexture(), camera, partialTick);
|
||||||
}
|
}
|
||||||
|
|
||||||
try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(tracePair, "clouds", minecraft.options.getCloudsType().toString())) {
|
try (PortalSceneRenderTrace.Phase ignored = PortalSceneRenderTrace.begin(tracePair, "clouds", minecraft.options.getCloudsType().toString())) {
|
||||||
@@ -173,6 +194,14 @@ public final class PortalGunProxySceneRenderer {
|
|||||||
RenderSystem.disableBlend();
|
RenderSystem.disableBlend();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
outerModelViewStack.popMatrix();
|
||||||
|
RenderSystem.applyModelViewMatrix();
|
||||||
|
RenderSystem.setShaderFogStart(previousFogStart);
|
||||||
|
RenderSystem.setShaderFogEnd(previousFogEnd);
|
||||||
|
RenderSystem.setShaderFogColor(previousFogColor[0], previousFogColor[1], previousFogColor[2], previousFogColor[3]);
|
||||||
|
RenderSystem.setShaderFogShape(previousFogShape);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int rendererAccessDistance(LevelRenderer renderer) {
|
private static int rendererAccessDistance(LevelRenderer renderer) {
|
||||||
@@ -186,8 +215,11 @@ public final class PortalGunProxySceneRenderer {
|
|||||||
}
|
}
|
||||||
BlockPos pos = blockEntity.getBlockPos();
|
BlockPos pos = blockEntity.getBlockPos();
|
||||||
poseStack.pushPose();
|
poseStack.pushPose();
|
||||||
poseStack.translate(pos.getX() - cameraX, pos.getY() - cameraY, pos.getZ() - cameraZ);
|
try {
|
||||||
minecraft.getBlockEntityRenderDispatcher().render(blockEntity, partialTick, poseStack, buffers);
|
poseStack.translate(pos.getX() - cameraX, pos.getY() - cameraY, pos.getZ() - cameraZ);
|
||||||
poseStack.popPose();
|
minecraft.getBlockEntityRenderDispatcher().render(blockEntity, partialTick, poseStack, buffers);
|
||||||
|
} finally {
|
||||||
|
poseStack.popPose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+8
@@ -5,7 +5,9 @@ import java.util.HashSet;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public final class PortalSceneRenderTrace {
|
public final class PortalSceneRenderTrace {
|
||||||
|
private static final String DEBUG_PROPERTY = "antarchy.portalGun.debugRender";
|
||||||
private static final Set<String> LOGGED_PHASES = new HashSet<>();
|
private static final Set<String> LOGGED_PHASES = new HashSet<>();
|
||||||
|
private static final Phase NOOP_PHASE = new Phase(0L, "", "", false, 0L);
|
||||||
private static long generation;
|
private static long generation;
|
||||||
private static String armedKey = "";
|
private static String armedKey = "";
|
||||||
|
|
||||||
@@ -27,6 +29,9 @@ public final class PortalSceneRenderTrace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Phase begin(String pair, String phase, String detail) {
|
public static Phase begin(String pair, String phase, String detail) {
|
||||||
|
if (!Boolean.getBoolean(DEBUG_PROPERTY)) {
|
||||||
|
return NOOP_PHASE;
|
||||||
|
}
|
||||||
long currentGeneration;
|
long currentGeneration;
|
||||||
boolean shouldLog;
|
boolean shouldLog;
|
||||||
synchronized (PortalSceneRenderTrace.class) {
|
synchronized (PortalSceneRenderTrace.class) {
|
||||||
@@ -40,6 +45,9 @@ public final class PortalSceneRenderTrace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void event(String pair, String event, String detail) {
|
public static void event(String pair, String event, String detail) {
|
||||||
|
if (!Boolean.getBoolean(DEBUG_PROPERTY)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
long currentGeneration;
|
long currentGeneration;
|
||||||
boolean shouldLog;
|
boolean shouldLog;
|
||||||
synchronized (PortalSceneRenderTrace.class) {
|
synchronized (PortalSceneRenderTrace.class) {
|
||||||
|
|||||||
+118
-18
@@ -1,5 +1,6 @@
|
|||||||
package com.craisinlord.antarchy.content.client.renderer;
|
package com.craisinlord.antarchy.content.client.renderer;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.Antarchy;
|
||||||
import com.mojang.blaze3d.pipeline.RenderTarget;
|
import com.mojang.blaze3d.pipeline.RenderTarget;
|
||||||
import com.mojang.blaze3d.systems.RenderSystem;
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -9,16 +10,25 @@ import java.util.Objects;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import org.lwjgl.opengl.GL11;
|
import org.lwjgl.opengl.GL11;
|
||||||
import org.lwjgl.opengl.GL30;
|
import org.lwjgl.opengl.GL30;
|
||||||
import com.mojang.blaze3d.pipeline.TextureTarget;
|
|
||||||
|
|
||||||
public final class PortalStencilTarget {
|
public final class PortalStencilTarget {
|
||||||
private static final Map<RenderTarget, Attachment> ATTACHMENTS = Collections.synchronizedMap(new IdentityHashMap<>());
|
private static final Map<RenderTarget, Attachment> ATTACHMENTS = Collections.synchronizedMap(new IdentityHashMap<>());
|
||||||
|
private static final Map<RenderTarget, Attachment> MAIN_STENCIL_ATTACHMENTS = Collections.synchronizedMap(new IdentityHashMap<>());
|
||||||
|
private static final Map<RenderTarget, Integer> UNSUPPORTED_MAIN_TARGETS = Collections.synchronizedMap(new IdentityHashMap<>());
|
||||||
private static final Set<RenderTarget> DIRECT_TARGETS = Collections.newSetFromMap(new IdentityHashMap<>());
|
private static final Set<RenderTarget> DIRECT_TARGETS = Collections.newSetFromMap(new IdentityHashMap<>());
|
||||||
|
|
||||||
private PortalStencilTarget() {
|
private PortalStencilTarget() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void prepareMainTarget(RenderTarget target) {
|
public static void prepareMainTarget(RenderTarget target) {
|
||||||
|
target.bindWrite(true);
|
||||||
|
if (stencilBits() > 0) {
|
||||||
|
UNSUPPORTED_MAIN_TARGETS.remove(target);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (Objects.equals(UNSUPPORTED_MAIN_TARGETS.get(target), target.frameBufferId)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
java.lang.reflect.Method enabled = target.getClass().getMethod("isStencilEnabled");
|
java.lang.reflect.Method enabled = target.getClass().getMethod("isStencilEnabled");
|
||||||
if (!Boolean.TRUE.equals(enabled.invoke(target))) {
|
if (!Boolean.TRUE.equals(enabled.invoke(target))) {
|
||||||
@@ -27,14 +37,26 @@ public final class PortalStencilTarget {
|
|||||||
} catch (ReflectiveOperationException ignored) {
|
} catch (ReflectiveOperationException ignored) {
|
||||||
}
|
}
|
||||||
target.bindWrite(true);
|
target.bindWrite(true);
|
||||||
|
if (stencilBits() <= 0) {
|
||||||
|
try {
|
||||||
|
ensureMainStencilAttachment(target);
|
||||||
|
} catch (IllegalStateException exception) {
|
||||||
|
UNSUPPORTED_MAIN_TARGETS.put(target, target.frameBufferId);
|
||||||
|
Antarchy.LOGGER.warn("Portal gun direct stencil is unavailable; using offscreen portal rendering", exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Scope beginDirect(RenderTarget target, TextureTarget depthBackup, Runnable drawApertureMask) {
|
public static boolean supportsDirect(RenderTarget target) {
|
||||||
target.bindWrite(true);
|
target.bindWrite(true);
|
||||||
if (GL11.glGetInteger(GL11.GL_STENCIL_BITS) <= 0) {
|
return stencilBits() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Scope beginDirect(RenderTarget target, Runnable drawApertureMask, Runnable clearApertureDepth, Runnable restoreApertureDepth) {
|
||||||
|
target.bindWrite(true);
|
||||||
|
if (stencilBits() <= 0) {
|
||||||
throw new IllegalStateException("Main render target has no stencil attachment");
|
throw new IllegalStateException("Main render target has no stencil attachment");
|
||||||
}
|
}
|
||||||
depthBackup.copyDepthFrom(target);
|
|
||||||
DIRECT_TARGETS.add(target);
|
DIRECT_TARGETS.add(target);
|
||||||
target.bindWrite(true);
|
target.bindWrite(true);
|
||||||
RenderSystem.disableScissor();
|
RenderSystem.disableScissor();
|
||||||
@@ -45,14 +67,32 @@ public final class PortalStencilTarget {
|
|||||||
RenderSystem.stencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_REPLACE);
|
RenderSystem.stencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_REPLACE);
|
||||||
RenderSystem.colorMask(false, false, false, false);
|
RenderSystem.colorMask(false, false, false, false);
|
||||||
RenderSystem.depthMask(false);
|
RenderSystem.depthMask(false);
|
||||||
RenderSystem.disableDepthTest();
|
RenderSystem.enableDepthTest();
|
||||||
GL11.glEnable(GL11.GL_STENCIL_TEST);
|
GL11.glEnable(GL11.GL_STENCIL_TEST);
|
||||||
try {
|
try {
|
||||||
Objects.requireNonNull(drawApertureMask).run();
|
Objects.requireNonNull(drawApertureMask).run();
|
||||||
|
RenderSystem.colorMask(false, false, false, false);
|
||||||
|
RenderSystem.depthMask(true);
|
||||||
|
RenderSystem.stencilMask(0x00);
|
||||||
|
RenderSystem.stencilFunc(GL11.GL_EQUAL, 1, 0xFF);
|
||||||
|
RenderSystem.stencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_KEEP);
|
||||||
|
Objects.requireNonNull(clearApertureDepth).run();
|
||||||
} catch (RuntimeException | Error exception) {
|
} catch (RuntimeException | Error exception) {
|
||||||
resetState();
|
try {
|
||||||
target.copyDepthFrom(depthBackup);
|
target.bindWrite(true);
|
||||||
DIRECT_TARGETS.remove(target);
|
GL11.glEnable(GL11.GL_STENCIL_TEST);
|
||||||
|
RenderSystem.stencilMask(0x00);
|
||||||
|
RenderSystem.stencilFunc(GL11.GL_EQUAL, 1, 0xFF);
|
||||||
|
RenderSystem.stencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_KEEP);
|
||||||
|
RenderSystem.colorMask(false, false, false, false);
|
||||||
|
RenderSystem.depthMask(true);
|
||||||
|
restoreApertureDepth.run();
|
||||||
|
} catch (RuntimeException | Error restoreFailure) {
|
||||||
|
exception.addSuppressed(restoreFailure);
|
||||||
|
} finally {
|
||||||
|
DIRECT_TARGETS.remove(target);
|
||||||
|
resetState();
|
||||||
|
}
|
||||||
throw exception;
|
throw exception;
|
||||||
}
|
}
|
||||||
RenderSystem.colorMask(true, true, true, true);
|
RenderSystem.colorMask(true, true, true, true);
|
||||||
@@ -60,9 +100,8 @@ public final class PortalStencilTarget {
|
|||||||
RenderSystem.stencilMask(0x00);
|
RenderSystem.stencilMask(0x00);
|
||||||
RenderSystem.stencilFunc(GL11.GL_EQUAL, 1, 0xFF);
|
RenderSystem.stencilFunc(GL11.GL_EQUAL, 1, 0xFF);
|
||||||
RenderSystem.stencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_KEEP);
|
RenderSystem.stencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_KEEP);
|
||||||
GL11.glClear(GL11.GL_DEPTH_BUFFER_BIT);
|
|
||||||
RenderSystem.enableDepthTest();
|
RenderSystem.enableDepthTest();
|
||||||
return new Scope(target, depthBackup);
|
return new Scope(target, restoreApertureDepth);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Scope begin(RenderTarget target, Runnable drawApertureMask) {
|
public static Scope begin(RenderTarget target, Runnable drawApertureMask) {
|
||||||
@@ -107,10 +146,15 @@ public final class PortalStencilTarget {
|
|||||||
|
|
||||||
public static void release(RenderTarget target) {
|
public static void release(RenderTarget target) {
|
||||||
DIRECT_TARGETS.remove(target);
|
DIRECT_TARGETS.remove(target);
|
||||||
|
UNSUPPORTED_MAIN_TARGETS.remove(target);
|
||||||
Attachment attachment = ATTACHMENTS.remove(target);
|
Attachment attachment = ATTACHMENTS.remove(target);
|
||||||
if (attachment != null) {
|
if (attachment != null) {
|
||||||
GL30.glDeleteRenderbuffers(attachment.renderbuffer());
|
GL30.glDeleteRenderbuffers(attachment.renderbuffer());
|
||||||
}
|
}
|
||||||
|
Attachment mainAttachment = MAIN_STENCIL_ATTACHMENTS.remove(target);
|
||||||
|
if (mainAttachment != null) {
|
||||||
|
GL30.glDeleteRenderbuffers(mainAttachment.renderbuffer());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void clear() {
|
public static void clear() {
|
||||||
@@ -118,9 +162,47 @@ public final class PortalStencilTarget {
|
|||||||
GL30.glDeleteRenderbuffers(attachment.renderbuffer());
|
GL30.glDeleteRenderbuffers(attachment.renderbuffer());
|
||||||
}
|
}
|
||||||
ATTACHMENTS.clear();
|
ATTACHMENTS.clear();
|
||||||
|
for (Attachment attachment : MAIN_STENCIL_ATTACHMENTS.values()) {
|
||||||
|
GL30.glDeleteRenderbuffers(attachment.renderbuffer());
|
||||||
|
}
|
||||||
|
MAIN_STENCIL_ATTACHMENTS.clear();
|
||||||
|
UNSUPPORTED_MAIN_TARGETS.clear();
|
||||||
DIRECT_TARGETS.clear();
|
DIRECT_TARGETS.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void ensureMainStencilAttachment(RenderTarget target) {
|
||||||
|
Attachment attachment = MAIN_STENCIL_ATTACHMENTS.get(target);
|
||||||
|
if (attachment != null
|
||||||
|
&& attachment.framebuffer() == target.frameBufferId
|
||||||
|
&& attachment.width() == target.width
|
||||||
|
&& attachment.height() == target.height) {
|
||||||
|
throw new IllegalStateException("Main render target stencil attachment has no stencil bits");
|
||||||
|
}
|
||||||
|
if (attachment != null) {
|
||||||
|
GL30.glDeleteRenderbuffers(attachment.renderbuffer());
|
||||||
|
MAIN_STENCIL_ATTACHMENTS.remove(target);
|
||||||
|
}
|
||||||
|
int previousRenderbuffer = GL11.glGetInteger(GL30.GL_RENDERBUFFER_BINDING);
|
||||||
|
int renderbuffer = GL30.glGenRenderbuffers();
|
||||||
|
try {
|
||||||
|
GL30.glBindRenderbuffer(GL30.GL_RENDERBUFFER, renderbuffer);
|
||||||
|
GL30.glRenderbufferStorage(GL30.GL_RENDERBUFFER, GL30.GL_STENCIL_INDEX8, target.width, target.height);
|
||||||
|
GL30.glFramebufferRenderbuffer(GL30.GL_FRAMEBUFFER, GL30.GL_STENCIL_ATTACHMENT, GL30.GL_RENDERBUFFER, renderbuffer);
|
||||||
|
int status = GL30.glCheckFramebufferStatus(GL30.GL_FRAMEBUFFER);
|
||||||
|
if (status != GL30.GL_FRAMEBUFFER_COMPLETE) {
|
||||||
|
GL30.glFramebufferRenderbuffer(GL30.GL_FRAMEBUFFER, GL30.GL_STENCIL_ATTACHMENT, GL30.GL_RENDERBUFFER, 0);
|
||||||
|
throw new IllegalStateException("Main render target is incomplete with stencil attachment: 0x" + Integer.toHexString(status));
|
||||||
|
}
|
||||||
|
MAIN_STENCIL_ATTACHMENTS.put(target, new Attachment(target.frameBufferId, renderbuffer, target.width, target.height));
|
||||||
|
PortalSceneRenderTrace.event("main-target", "stencil-attached", "framebuffer=" + target.frameBufferId + " size=" + target.width + "x" + target.height);
|
||||||
|
} catch (RuntimeException | Error exception) {
|
||||||
|
GL30.glDeleteRenderbuffers(renderbuffer);
|
||||||
|
throw exception;
|
||||||
|
} finally {
|
||||||
|
GL30.glBindRenderbuffer(GL30.GL_RENDERBUFFER, previousRenderbuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void ensureAttachment(RenderTarget target) {
|
private static void ensureAttachment(RenderTarget target) {
|
||||||
Attachment attachment = ATTACHMENTS.get(target);
|
Attachment attachment = ATTACHMENTS.get(target);
|
||||||
if (attachment != null
|
if (attachment != null
|
||||||
@@ -162,21 +244,28 @@ public final class PortalStencilTarget {
|
|||||||
RenderSystem.enableDepthTest();
|
RenderSystem.enableDepthTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int stencilBits() {
|
||||||
|
int type = GL30.glGetFramebufferAttachmentParameteri(GL30.GL_FRAMEBUFFER, GL30.GL_STENCIL_ATTACHMENT,
|
||||||
|
GL30.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE);
|
||||||
|
return type == GL11.GL_NONE ? 0 : GL30.glGetFramebufferAttachmentParameteri(GL30.GL_FRAMEBUFFER,
|
||||||
|
GL30.GL_STENCIL_ATTACHMENT, GL30.GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
private record Attachment(int framebuffer, int renderbuffer, int width, int height) {
|
private record Attachment(int framebuffer, int renderbuffer, int width, int height) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class Scope implements AutoCloseable {
|
public static final class Scope implements AutoCloseable {
|
||||||
private boolean closed;
|
private boolean closed;
|
||||||
private final RenderTarget target;
|
private final RenderTarget target;
|
||||||
private final TextureTarget depthBackup;
|
private final Runnable restoreApertureDepth;
|
||||||
|
|
||||||
private Scope(RenderTarget target) {
|
private Scope(RenderTarget target) {
|
||||||
this(target, null);
|
this(target, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Scope(RenderTarget target, TextureTarget depthBackup) {
|
private Scope(RenderTarget target, Runnable restoreApertureDepth) {
|
||||||
this.target = Objects.requireNonNull(target);
|
this.target = Objects.requireNonNull(target);
|
||||||
this.depthBackup = depthBackup;
|
this.restoreApertureDepth = restoreApertureDepth;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -185,12 +274,23 @@ public final class PortalStencilTarget {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
closed = true;
|
closed = true;
|
||||||
if (this.depthBackup != null) {
|
try {
|
||||||
this.target.copyDepthFrom(this.depthBackup);
|
if (this.restoreApertureDepth != null) {
|
||||||
this.target.bindWrite(true);
|
this.target.bindWrite(true);
|
||||||
DIRECT_TARGETS.remove(this.target);
|
GL11.glEnable(GL11.GL_STENCIL_TEST);
|
||||||
|
RenderSystem.stencilMask(0x00);
|
||||||
|
RenderSystem.stencilFunc(GL11.GL_EQUAL, 1, 0xFF);
|
||||||
|
RenderSystem.stencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_KEEP);
|
||||||
|
RenderSystem.colorMask(false, false, false, false);
|
||||||
|
RenderSystem.depthMask(true);
|
||||||
|
this.restoreApertureDepth.run();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (this.restoreApertureDepth != null) {
|
||||||
|
DIRECT_TARGETS.remove(this.target);
|
||||||
|
}
|
||||||
|
resetState();
|
||||||
}
|
}
|
||||||
resetState();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+25
-8
@@ -5,7 +5,9 @@ import java.lang.reflect.InvocationTargetException;
|
|||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
import java.util.Deque;
|
import java.util.Deque;
|
||||||
|
import java.util.function.Consumer;
|
||||||
import net.minecraft.client.Camera;
|
import net.minecraft.client.Camera;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
|
||||||
public final class SodiumCompat {
|
public final class SodiumCompat {
|
||||||
private static final String SODIUM_RENDERER_CLASS = "net.caffeinemc.mods.sodium.client.render.SodiumWorldRenderer";
|
private static final String SODIUM_RENDERER_CLASS = "net.caffeinemc.mods.sodium.client.render.SodiumWorldRenderer";
|
||||||
@@ -29,13 +31,10 @@ public final class SodiumCompat {
|
|||||||
RENDER_STATE.get().activeSetup = new TerrainSetup(camera, viewport, spectator, updateChunks);
|
RENDER_STATE.get().activeSetup = new TerrainSetup(camera, viewport, spectator, updateChunks);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TerrainScope beginPortalView(Camera portalCamera) {
|
public static TerrainScope beginPortalView() {
|
||||||
RenderState state = RENDER_STATE.get();
|
RenderState state = RENDER_STATE.get();
|
||||||
TerrainSetup previousSetup = state.activeSetup;
|
TerrainSetup previousSetup = state.activeSetup;
|
||||||
state.previousSetups.push(new PreviousSetup(previousSetup));
|
state.previousSetups.push(new PreviousSetup(previousSetup));
|
||||||
if (previousSetup != null) {
|
|
||||||
restoreTerrainSetup(previousSetup.withCamera(portalCamera), state);
|
|
||||||
}
|
|
||||||
return () -> {
|
return () -> {
|
||||||
PreviousSetup previous = state.previousSetups.pop();
|
PreviousSetup previous = state.previousSetups.pop();
|
||||||
if (previous.setup() == null) {
|
if (previous.setup() == null) {
|
||||||
@@ -50,6 +49,20 @@ public final class SodiumCompat {
|
|||||||
RENDER_STATE.remove();
|
RENDER_STATE.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void forEachVisibleBlockEntity(Consumer<BlockEntity> consumer) {
|
||||||
|
try {
|
||||||
|
ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
|
||||||
|
Class<?> rendererClass = Class.forName(SODIUM_RENDERER_CLASS, false,
|
||||||
|
contextLoader == null ? SodiumCompat.class.getClassLoader() : contextLoader);
|
||||||
|
Object renderer = rendererClass.getMethod("instanceNullable").invoke(null);
|
||||||
|
if (renderer != null) {
|
||||||
|
rendererClass.getMethod("iterateVisibleBlockEntities", Consumer.class).invoke(renderer, consumer);
|
||||||
|
}
|
||||||
|
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException | LinkageError exception) {
|
||||||
|
logRestoreFailure("Could not iterate Sodium block entities for a portal view", exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void restoreTerrainSetup(TerrainSetup setup, RenderState state) {
|
private static void restoreTerrainSetup(TerrainSetup setup, RenderState state) {
|
||||||
try {
|
try {
|
||||||
ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
|
ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
|
||||||
@@ -77,7 +90,14 @@ public final class SodiumCompat {
|
|||||||
state.activeSetup = setup;
|
state.activeSetup = setup;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
terrainSetup.invoke(renderer, setup.camera(), setup.viewport(), setup.spectator(), setup.updateChunks());
|
Class<?> deviceClass = Class.forName("net.caffeinemc.mods.sodium.client.gl.device.RenderDevice", false,
|
||||||
|
contextLoader == null ? SodiumCompat.class.getClassLoader() : contextLoader);
|
||||||
|
deviceClass.getMethod("enterManagedCode").invoke(null);
|
||||||
|
try {
|
||||||
|
terrainSetup.invoke(renderer, setup.camera(), setup.viewport(), setup.spectator(), setup.updateChunks());
|
||||||
|
} finally {
|
||||||
|
deviceClass.getMethod("exitManagedCode").invoke(null);
|
||||||
|
}
|
||||||
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException | LinkageError exception) {
|
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException | LinkageError exception) {
|
||||||
logRestoreFailure("Could not restore Sodium terrain after a portal view", exception);
|
logRestoreFailure("Could not restore Sodium terrain after a portal view", exception);
|
||||||
state.activeSetup = setup;
|
state.activeSetup = setup;
|
||||||
@@ -110,8 +130,5 @@ public final class SodiumCompat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private record TerrainSetup(Camera camera, Object viewport, boolean spectator, boolean updateChunks) {
|
private record TerrainSetup(Camera camera, Object viewport, boolean spectator, boolean updateChunks) {
|
||||||
private TerrainSetup withCamera(Camera camera) {
|
|
||||||
return new TerrainSetup(camera, this.viewport, this.spectator, this.updateChunks);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+1
-2
@@ -17,7 +17,6 @@ import org.joml.Matrix4f;
|
|||||||
import org.joml.Vector3f;
|
import org.joml.Vector3f;
|
||||||
|
|
||||||
public final class TemporalContractionAfterimageLayer<T extends LivingEntity, M extends EntityModel<T>> extends RenderLayer<T, M> {
|
public final class TemporalContractionAfterimageLayer<T extends LivingEntity, M extends EntityModel<T>> extends RenderLayer<T, M> {
|
||||||
private static final int RGB = 0xFFD35A;
|
|
||||||
private static final float BASE_ALPHA = 0.42F;
|
private static final float BASE_ALPHA = 0.42F;
|
||||||
private static final int SAMPLE_STRIDE = 2;
|
private static final int SAMPLE_STRIDE = 2;
|
||||||
|
|
||||||
@@ -64,7 +63,7 @@ public final class TemporalContractionAfterimageLayer<T extends LivingEntity, M
|
|||||||
|
|
||||||
Vector3f local = inverse.transformDirection(new Vector3f((float) dx, (float) dy, (float) dz));
|
Vector3f local = inverse.transformDirection(new Vector3f((float) dx, (float) dy, (float) dz));
|
||||||
int alpha = (int) (BASE_ALPHA * fade * 255.0F) & 0xFF;
|
int alpha = (int) (BASE_ALPHA * fade * 255.0F) & 0xFF;
|
||||||
int color = alpha << 24 | RGB;
|
int color = alpha << 24 | ContractionAfterimages.colorFor(entity);
|
||||||
|
|
||||||
model.setupAnim(entity, sample.limbPos, sample.limbSpeed, sample.ageInTicks,
|
model.setupAnim(entity, sample.limbPos, sample.limbSpeed, sample.ageInTicks,
|
||||||
sample.headYaw - sample.bodyYaw, sample.xRot);
|
sample.headYaw - sample.bodyYaw, sample.xRot);
|
||||||
|
|||||||
+1
-2
@@ -18,7 +18,6 @@ import software.bernie.geckolib.renderer.GeoRenderer;
|
|||||||
import software.bernie.geckolib.renderer.layer.GeoRenderLayer;
|
import software.bernie.geckolib.renderer.layer.GeoRenderLayer;
|
||||||
|
|
||||||
public final class TemporalContractionGeoLayer<T extends GeoAnimatable> extends GeoRenderLayer<T> {
|
public final class TemporalContractionGeoLayer<T extends GeoAnimatable> extends GeoRenderLayer<T> {
|
||||||
private static final int RGB = 0xFFD35A;
|
|
||||||
private static final float BASE_ALPHA = 0.42F;
|
private static final float BASE_ALPHA = 0.42F;
|
||||||
private static final int SAMPLE_STRIDE = 2;
|
private static final int SAMPLE_STRIDE = 2;
|
||||||
|
|
||||||
@@ -66,7 +65,7 @@ public final class TemporalContractionGeoLayer<T extends GeoAnimatable> extends
|
|||||||
|
|
||||||
Vector3f local = inverse.transformDirection(new Vector3f((float) dx, (float) dy, (float) dz));
|
Vector3f local = inverse.transformDirection(new Vector3f((float) dx, (float) dy, (float) dz));
|
||||||
int alpha = (int) (BASE_ALPHA * fade * 255.0F) & 0xFF;
|
int alpha = (int) (BASE_ALPHA * fade * 255.0F) & 0xFF;
|
||||||
int color = alpha << 24 | RGB;
|
int color = alpha << 24 | ContractionAfterimages.colorFor(entity);
|
||||||
|
|
||||||
poseStack.pushPose();
|
poseStack.pushPose();
|
||||||
poseStack.translate(local.x, local.y, local.z);
|
poseStack.translate(local.x, local.y, local.z);
|
||||||
|
|||||||
+38
-13
@@ -79,6 +79,7 @@ public class PortalGunPortalEntity extends Entity implements GeoEntity {
|
|||||||
private static final RawAnimation IDLE_ANIM = RawAnimation.begin().thenLoop("idle");
|
private static final RawAnimation IDLE_ANIM = RawAnimation.begin().thenLoop("idle");
|
||||||
private static final int OPEN_TICKS = 5;
|
private static final int OPEN_TICKS = 5;
|
||||||
public static final int TELEPORT_COOLDOWN_TICKS = 3;
|
public static final int TELEPORT_COOLDOWN_TICKS = 3;
|
||||||
|
private static final String DEBUG_TRAVERSAL_PROPERTY = "antarchy.portalGun.debugTraversal";
|
||||||
private static final double PORTAL_INSIDE_SHIFT = 0.05D;
|
private static final double PORTAL_INSIDE_SHIFT = 0.05D;
|
||||||
private static final Set<String> LOGGED_CROSSING_PATHS = new HashSet<>();
|
private static final Set<String> LOGGED_CROSSING_PATHS = new HashSet<>();
|
||||||
private static final double HALF_DEPTH = 0.35D;
|
private static final double HALF_DEPTH = 0.35D;
|
||||||
@@ -358,22 +359,26 @@ public class PortalGunPortalEntity extends Entity implements GeoEntity {
|
|||||||
Vec3 currentProbe = this.teleportProbePosition(entity, currentBox);
|
Vec3 currentProbe = this.teleportProbePosition(entity, currentBox);
|
||||||
Vec3 normal = this.getNormalVec().normalize();
|
Vec3 normal = this.getNormalVec().normalize();
|
||||||
if (entity instanceof Player && Math.abs(normal.y) < 0.5D) {
|
if (entity instanceof Player && Math.abs(normal.y) < 0.5D) {
|
||||||
double offset = Math.min(0.05D, Math.abs(this.position().subtract(entity.position()).dot(normal)));
|
PortalGunWorldPortalShape shape = this.getWorldPortalShape();
|
||||||
Vec3 shift = normal.scale(offset);
|
double previousDepth = shape.localCoords(previousProbe).depth();
|
||||||
if (this.getScanRange().move(shift).contains(currentProbe)
|
double currentDepth = shape.localCoords(currentProbe).depth();
|
||||||
|| !this.getPortalInsides().move(shift).contains(currentProbe)) {
|
double halfBodyDepth = entity.getBbWidth() * 0.5D;
|
||||||
|
if (previousDepth <= 0.0D || currentDepth >= previousDepth - 1.0E-6D
|
||||||
|
|| currentDepth - halfBodyDepth > 0.02D || currentDepth < -shape.halfDepth()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
PortalGunWorldPortalShape shape = this.getWorldPortalShape();
|
Vec3 center = currentBox.getCenter();
|
||||||
AABB flatPlane = shape.getFlatPlane();
|
PortalGunWorldPortalShape.PortalLocalCoords localCenter = shape.localCoords(center);
|
||||||
boolean aligned;
|
double halfX = (currentBox.maxX - currentBox.minX) * 0.5D;
|
||||||
if (Math.abs(normal.y) > 0.5D) {
|
double halfY = (currentBox.maxY - currentBox.minY) * 0.5D;
|
||||||
aligned = currentBox.minX >= flatPlane.minX && currentBox.maxX <= flatPlane.maxX
|
double halfZ = (currentBox.maxZ - currentBox.minZ) * 0.5D;
|
||||||
&& currentBox.minZ >= flatPlane.minZ && currentBox.maxZ <= flatPlane.maxZ;
|
double widthExtent = halfX * Math.abs(shape.right().x) + halfY * Math.abs(shape.right().y) + halfZ * Math.abs(shape.right().z);
|
||||||
} else {
|
double heightExtent = halfX * Math.abs(shape.up().x) + halfY * Math.abs(shape.up().y) + halfZ * Math.abs(shape.up().z);
|
||||||
aligned = currentBox.minY >= flatPlane.minY && currentBox.maxY <= flatPlane.maxY;
|
if (Math.abs(localCenter.horizontal()) + widthExtent > shape.halfWidth() + 1.0E-3D
|
||||||
|
|| Math.abs(localCenter.vertical()) + heightExtent > shape.halfHeight() + 1.0E-3D) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
return aligned ? new PortalCrossing(currentProbe, offset) : null;
|
return new PortalCrossing(currentProbe, Math.max(0.05D, currentDepth + 0.05D));
|
||||||
}
|
}
|
||||||
return this.crossesPortal(previousProbe, currentProbe) ? new PortalCrossing(currentProbe, 0.0D) : null;
|
return this.crossesPortal(previousProbe, currentProbe) ? new PortalCrossing(currentProbe, 0.0D) : null;
|
||||||
}
|
}
|
||||||
@@ -416,6 +421,10 @@ public class PortalGunPortalEntity extends Entity implements GeoEntity {
|
|||||||
}
|
}
|
||||||
PortalCrossing crossing = portal.resolveCrossing(entity, previousBox, currentBox);
|
PortalCrossing crossing = portal.resolveCrossing(entity, previousBox, currentBox);
|
||||||
if (crossing != null) {
|
if (crossing != null) {
|
||||||
|
if (entity instanceof Player && Boolean.getBoolean(DEBUG_TRAVERSAL_PROPERTY)) {
|
||||||
|
Antarchy.LOGGER.info("Portal gun traversal accepted path=movement portal={} player={} probe={} offset={} linked={}",
|
||||||
|
portal.getUUID(), entity.getUUID(), crossing.probe(), crossing.normalOffset(), linked.getUUID());
|
||||||
|
}
|
||||||
logCrossingPath(entity, "movement");
|
logCrossingPath(entity, "movement");
|
||||||
portal.teleportEntity(entity, linked, crossing.probe(), resolvedMovement, crossing.normalOffset());
|
portal.teleportEntity(entity, linked, crossing.probe(), resolvedMovement, crossing.normalOffset());
|
||||||
return;
|
return;
|
||||||
@@ -506,6 +515,10 @@ public class PortalGunPortalEntity extends Entity implements GeoEntity {
|
|||||||
}
|
}
|
||||||
PortalGunPortalEntity linked = this.findLinkedPortal(serverLevel);
|
PortalGunPortalEntity linked = this.findLinkedPortal(serverLevel);
|
||||||
if (linked == null || !linked.isAlive()) {
|
if (linked == null || !linked.isAlive()) {
|
||||||
|
if (Boolean.getBoolean(DEBUG_TRAVERSAL_PROPERTY) && this.ageTicks % 40 == 0) {
|
||||||
|
Antarchy.LOGGER.info("Portal gun traversal unavailable portal={} side={} linked={} loaded={}",
|
||||||
|
this.getUUID(), this.getPortalSide(), this.linkedPortalId, linked != null);
|
||||||
|
}
|
||||||
if (this.ageTicks % 100 == 0) {
|
if (this.ageTicks % 100 == 0) {
|
||||||
Antarchy.LOGGER.debug("Portal gun portal has no loaded linked portal portal={} owner={} side={} linked={}", this.getUUID(), this.ownerId, this.getPortalSide(), this.linkedPortalId);
|
Antarchy.LOGGER.debug("Portal gun portal has no loaded linked portal portal={} owner={} side={} linked={}", this.getUUID(), this.ownerId, this.getPortalSide(), this.linkedPortalId);
|
||||||
}
|
}
|
||||||
@@ -560,8 +573,20 @@ public class PortalGunPortalEntity extends Entity implements GeoEntity {
|
|||||||
AABB previousBox = currentBox.move(entity.xo - entity.getX(), entity.yo - entity.getY(), entity.zo - entity.getZ());
|
AABB previousBox = currentBox.move(entity.xo - entity.getX(), entity.yo - entity.getY(), entity.zo - entity.getZ());
|
||||||
PortalCrossing crossing = this.resolveCrossing(entity, previousBox, currentBox);
|
PortalCrossing crossing = this.resolveCrossing(entity, previousBox, currentBox);
|
||||||
if (crossing == null) {
|
if (crossing == null) {
|
||||||
|
if (entity instanceof Player && Boolean.getBoolean(DEBUG_TRAVERSAL_PROPERTY) && this.ageTicks % 20 == 0) {
|
||||||
|
Vec3 probe = this.teleportProbePosition(entity, currentBox);
|
||||||
|
double depth = this.getWorldPortalShape().localCoords(probe).depth();
|
||||||
|
if (depth < 1.5D) {
|
||||||
|
Antarchy.LOGGER.info("Portal gun traversal waiting portal={} player={} depth={} position={} linked={}",
|
||||||
|
this.getUUID(), entity.getUUID(), depth, entity.position(), linked.getUUID());
|
||||||
|
}
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (entity instanceof Player && Boolean.getBoolean(DEBUG_TRAVERSAL_PROPERTY)) {
|
||||||
|
Antarchy.LOGGER.info("Portal gun traversal accepted portal={} player={} probe={} offset={} linked={}",
|
||||||
|
this.getUUID(), entity.getUUID(), crossing.probe(), crossing.normalOffset(), linked.getUUID());
|
||||||
|
}
|
||||||
logCrossingPath(entity, "portal_tick");
|
logCrossingPath(entity, "portal_tick");
|
||||||
Vec3 resolvedMovement = entity.position().subtract(entity.xo, entity.yo, entity.zo);
|
Vec3 resolvedMovement = entity.position().subtract(entity.xo, entity.yo, entity.zo);
|
||||||
this.teleportEntity(entity, linked, crossing.probe(), resolvedMovement, crossing.normalOffset());
|
this.teleportEntity(entity, linked, crossing.probe(), resolvedMovement, crossing.normalOffset());
|
||||||
|
|||||||
+73
-2
@@ -5,6 +5,8 @@ import java.util.Map;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
import java.util.function.Predicate;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
@@ -17,6 +19,7 @@ public final class TimeDilationApi {
|
|||||||
};
|
};
|
||||||
private static final Map<UUID, Double> SYNCED_CLIENT_RATES = new ConcurrentHashMap<>();
|
private static final Map<UUID, Double> SYNCED_CLIENT_RATES = new ConcurrentHashMap<>();
|
||||||
private static final ThreadLocal<Integer> ROTATION_BYPASS_DEPTH = ThreadLocal.withInitial(() -> 0);
|
private static final ThreadLocal<Integer> ROTATION_BYPASS_DEPTH = ThreadLocal.withInitial(() -> 0);
|
||||||
|
private static final List<Predicate<Entity>> HORIZONTAL_ONLY_MOVEMENT = new CopyOnWriteArrayList<>();
|
||||||
|
|
||||||
private TimeDilationApi() {
|
private TimeDilationApi() {
|
||||||
}
|
}
|
||||||
@@ -98,7 +101,7 @@ public final class TimeDilationApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void applySyncedRate(UUID entityUuid, double rate) {
|
public static void applySyncedRate(UUID entityUuid, double rate) {
|
||||||
double clampedRate = TimeDilationMath.clampRate(rate);
|
double clampedRate = TimeDilationMath.clampRate(rate, TimeDilationMath.ABSOLUTE_MAX_RATE);
|
||||||
SYNCED_CLIENT_RATES.put(entityUuid, clampedRate);
|
SYNCED_CLIENT_RATES.put(entityUuid, clampedRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,7 +125,75 @@ public final class TimeDilationApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void syncEntityRate(Entity entity, double rate) {
|
public static void syncEntityRate(Entity entity, double rate) {
|
||||||
syncDispatcher.accept(entity, TimeDilationMath.clampRate(rate));
|
syncDispatcher.accept(entity, TimeDilationMath.clampRate(rate, TimeDilationMath.ABSOLUTE_MAX_RATE));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addHorizontalOnlyMovement(Predicate<Entity> predicate) {
|
||||||
|
HORIZONTAL_ONLY_MOVEMENT.add(predicate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isHorizontalOnlyMovement(Entity entity) {
|
||||||
|
for (Predicate<Entity> predicate : HORIZONTAL_ONLY_MOVEMENT) {
|
||||||
|
if (predicate.test(entity)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double getRateCeiling(Entity entity) {
|
||||||
|
if (entity instanceof TimeDilationEntityAccess access) {
|
||||||
|
return access.antarchy$getTimeDilationCeiling();
|
||||||
|
}
|
||||||
|
return TimeDilationMath.MAX_RATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setRateCeiling(Entity entity, double ceiling) {
|
||||||
|
if (entity instanceof TimeDilationEntityAccess access) {
|
||||||
|
access.antarchy$setTimeDilationCeiling(ceiling);
|
||||||
|
TimeDilationManager.trackPotentiallyAffected(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void clearRateCeiling(Entity entity) {
|
||||||
|
setRateCeiling(entity, TimeDilationMath.MAX_RATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setPersonalRate(Entity entity, String sourceId, double rate) {
|
||||||
|
if (entity instanceof TimeDilationEntityAccess access) {
|
||||||
|
double clampedRate = TimeDilationMath.clampRate(rate, TimeDilationMath.ABSOLUTE_MAX_RATE);
|
||||||
|
if (Math.abs(clampedRate - TimeDilationMath.NORMAL_RATE) < 0.001D) {
|
||||||
|
access.antarchy$getPersonalTimeDilationRates().remove(sourceId);
|
||||||
|
} else {
|
||||||
|
access.antarchy$getPersonalTimeDilationRates().put(sourceId, clampedRate);
|
||||||
|
}
|
||||||
|
TimeDilationManager.trackPotentiallyAffected(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void clearPersonalRate(Entity entity, String sourceId) {
|
||||||
|
if (entity instanceof TimeDilationEntityAccess access
|
||||||
|
&& access.antarchy$getPersonalTimeDilationRates().remove(sourceId) != null) {
|
||||||
|
TimeDilationManager.trackPotentiallyAffected(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double getPersonalRate(Entity entity, String sourceId) {
|
||||||
|
if (entity instanceof TimeDilationEntityAccess access) {
|
||||||
|
return access.antarchy$getPersonalTimeDilationRates().getOrDefault(sourceId, TimeDilationMath.NORMAL_RATE);
|
||||||
|
}
|
||||||
|
return TimeDilationMath.NORMAL_RATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean hasPersonalRates(Entity entity) {
|
||||||
|
return entity instanceof TimeDilationEntityAccess access && !access.antarchy$getPersonalTimeDilationRates().isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TimeDilationFieldEntity createAttachedField(ServerLevel level, Entity owner, double radius, double rate, int durationTicks) {
|
||||||
|
TimeDilationFieldEntity field = TimeDilationFieldEntity.create(level, owner.position(), radius, rate, durationTicks, owner.getUUID(), true);
|
||||||
|
field.attachTo(owner);
|
||||||
|
level.addFreshEntity(field);
|
||||||
|
return field;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void syncFields(ServerPlayer player, List<TimeDilationFieldSnapshot> fields) {
|
public static void syncFields(ServerPlayer player, List<TimeDilationFieldSnapshot> fields) {
|
||||||
|
|||||||
+8
@@ -1,6 +1,14 @@
|
|||||||
package com.craisinlord.antarchy.content.time;
|
package com.craisinlord.antarchy.content.time;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public interface TimeDilationEntityAccess {
|
public interface TimeDilationEntityAccess {
|
||||||
|
double antarchy$getTimeDilationCeiling();
|
||||||
|
|
||||||
|
void antarchy$setTimeDilationCeiling(double ceiling);
|
||||||
|
|
||||||
|
Map<String, Double> antarchy$getPersonalTimeDilationRates();
|
||||||
|
|
||||||
double antarchy$getTimeDilationRate();
|
double antarchy$getTimeDilationRate();
|
||||||
|
|
||||||
void antarchy$setTimeDilationRate(double rate);
|
void antarchy$setTimeDilationRate(double rate);
|
||||||
|
|||||||
+11
-2
@@ -77,6 +77,7 @@ public final class TimeDilationManager {
|
|||||||
&& Math.abs(access.antarchy$getTimeDilationRate() - TimeDilationMath.NORMAL_RATE) < 0.001D
|
&& Math.abs(access.antarchy$getTimeDilationRate() - TimeDilationMath.NORMAL_RATE) < 0.001D
|
||||||
&& Math.abs(access.antarchy$getInheritedTimeDilationRate() - TimeDilationMath.NORMAL_RATE) < 0.001D
|
&& Math.abs(access.antarchy$getInheritedTimeDilationRate() - TimeDilationMath.NORMAL_RATE) < 0.001D
|
||||||
&& Math.abs(TimeDilationApi.getVehicleRate(entity) - TimeDilationMath.NORMAL_RATE) < 0.001D
|
&& Math.abs(TimeDilationApi.getVehicleRate(entity) - TimeDilationMath.NORMAL_RATE) < 0.001D
|
||||||
|
&& !TimeDilationApi.hasPersonalRates(entity)
|
||||||
&& !hasTuner && !hasEffect) {
|
&& !hasTuner && !hasEffect) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -215,8 +216,16 @@ public final class TimeDilationManager {
|
|||||||
} else {
|
} else {
|
||||||
fastRate = Math.max(fastRate, inheritedRate);
|
fastRate = Math.max(fastRate, inheritedRate);
|
||||||
}
|
}
|
||||||
double targetRate = slowRate < TimeDilationMath.NORMAL_RATE ? slowRate : fastRate;
|
for (double personalRate : access.antarchy$getPersonalTimeDilationRates().values()) {
|
||||||
double rate = TimeDilationMath.transitionRate(previousRate, targetRate);
|
if (personalRate < TimeDilationMath.NORMAL_RATE) {
|
||||||
|
slowRate = Math.min(slowRate, personalRate);
|
||||||
|
} else {
|
||||||
|
fastRate = Math.max(fastRate, personalRate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
double ceiling = access.antarchy$getTimeDilationCeiling();
|
||||||
|
double targetRate = TimeDilationMath.clampRate(slowRate < TimeDilationMath.NORMAL_RATE ? slowRate : fastRate, ceiling);
|
||||||
|
double rate = TimeDilationMath.transitionRate(previousRate, targetRate, ceiling);
|
||||||
if (Math.abs(targetRate - TimeDilationMath.NORMAL_RATE) < 0.001D
|
if (Math.abs(targetRate - TimeDilationMath.NORMAL_RATE) < 0.001D
|
||||||
&& Math.abs(rate - TimeDilationMath.NORMAL_RATE) < 0.001D) {
|
&& Math.abs(rate - TimeDilationMath.NORMAL_RATE) < 0.001D) {
|
||||||
TimeDilationApi.clearRate(entity);
|
TimeDilationApi.clearRate(entity);
|
||||||
|
|||||||
+24
-4
@@ -4,6 +4,7 @@ public final class TimeDilationMath {
|
|||||||
public static final double MIN_RATE = 0.05D;
|
public static final double MIN_RATE = 0.05D;
|
||||||
public static final double NORMAL_RATE = 1.0D;
|
public static final double NORMAL_RATE = 1.0D;
|
||||||
public static final double MAX_RATE = 3.0D;
|
public static final double MAX_RATE = 3.0D;
|
||||||
|
public static final double ABSOLUTE_MAX_RATE = 20.0D;
|
||||||
public static final int FIELD_TRANSITION_TICKS = 20;
|
public static final int FIELD_TRANSITION_TICKS = 20;
|
||||||
public static final int EFFECT_TRANSITION_TICKS = 20;
|
public static final int EFFECT_TRANSITION_TICKS = 20;
|
||||||
private static final double GAUSSIAN_EDGE_EXPONENT = -4.5D;
|
private static final double GAUSSIAN_EDGE_EXPONENT = -4.5D;
|
||||||
@@ -18,12 +19,31 @@ public final class TimeDilationMath {
|
|||||||
return Math.max(MIN_RATE, Math.min(MAX_RATE, rate));
|
return Math.max(MIN_RATE, Math.min(MAX_RATE, rate));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static double clampCeiling(double ceiling) {
|
||||||
|
if (Double.isNaN(ceiling) || Double.isInfinite(ceiling)) {
|
||||||
|
return MAX_RATE;
|
||||||
|
}
|
||||||
|
return Math.max(NORMAL_RATE, Math.min(ABSOLUTE_MAX_RATE, ceiling));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double clampRate(double rate, double ceiling) {
|
||||||
|
if (Double.isNaN(rate) || Double.isInfinite(rate)) {
|
||||||
|
return NORMAL_RATE;
|
||||||
|
}
|
||||||
|
return Math.max(MIN_RATE, Math.min(clampCeiling(ceiling), rate));
|
||||||
|
}
|
||||||
|
|
||||||
public static double transitionRate(double currentRate, double targetRate) {
|
public static double transitionRate(double currentRate, double targetRate) {
|
||||||
double current = clampRate(currentRate);
|
return transitionRate(currentRate, targetRate, MAX_RATE);
|
||||||
double target = clampRate(targetRate);
|
}
|
||||||
double maximumStep = (MAX_RATE - MIN_RATE) / EFFECT_TRANSITION_TICKS;
|
|
||||||
|
public static double transitionRate(double currentRate, double targetRate, double ceiling) {
|
||||||
|
double maximum = clampCeiling(ceiling);
|
||||||
|
double current = clampRate(currentRate, maximum);
|
||||||
|
double target = clampRate(targetRate, maximum);
|
||||||
|
double maximumStep = (maximum - MIN_RATE) / EFFECT_TRANSITION_TICKS;
|
||||||
double delta = Math.max(-maximumStep, Math.min(maximumStep, target - current));
|
double delta = Math.max(-maximumStep, Math.min(maximumStep, target - current));
|
||||||
return clampRate(current + delta);
|
return clampRate(current + delta, maximum);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static double gaussianFalloff(double distance, double radius) {
|
public static double gaussianFalloff(double distance, double radius) {
|
||||||
|
|||||||
+3
-1
@@ -4,6 +4,7 @@ import com.craisinlord.antarchy.content.client.PortalGunPortalRenderState;
|
|||||||
import com.craisinlord.antarchy.content.client.renderer.PortalGunPortalViewAreaManager;
|
import com.craisinlord.antarchy.content.client.renderer.PortalGunPortalViewAreaManager;
|
||||||
import com.craisinlord.antarchy.content.client.renderer.PortalGunPortalRendererPool;
|
import com.craisinlord.antarchy.content.client.renderer.PortalGunPortalRendererPool;
|
||||||
import com.craisinlord.antarchy.content.client.renderer.PortalGunPortalViewRenderer;
|
import com.craisinlord.antarchy.content.client.renderer.PortalGunPortalViewRenderer;
|
||||||
|
import com.craisinlord.antarchy.content.client.renderer.PortalGunPortalVisibilityQueries;
|
||||||
import com.craisinlord.antarchy.content.client.renderer.PortalStencilTarget;
|
import com.craisinlord.antarchy.content.client.renderer.PortalStencilTarget;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.multiplayer.ClientLevel;
|
import net.minecraft.client.multiplayer.ClientLevel;
|
||||||
@@ -17,7 +18,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|||||||
public abstract class LevelRendererPortalLifecycleMixin {
|
public abstract class LevelRendererPortalLifecycleMixin {
|
||||||
@Inject(method = "renderLevel", at = @At("HEAD"))
|
@Inject(method = "renderLevel", at = @At("HEAD"))
|
||||||
private void antarchy$preparePortalStencil(CallbackInfo ci) {
|
private void antarchy$preparePortalStencil(CallbackInfo ci) {
|
||||||
if (!PortalGunPortalRendererPool.isProxy((LevelRenderer) (Object) this)) {
|
if (PortalGunPortalViewRenderer.isEnabled() && !PortalGunPortalRendererPool.isProxy((LevelRenderer) (Object) this)) {
|
||||||
PortalStencilTarget.prepareMainTarget(Minecraft.getInstance().getMainRenderTarget());
|
PortalStencilTarget.prepareMainTarget(Minecraft.getInstance().getMainRenderTarget());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -29,6 +30,7 @@ public abstract class LevelRendererPortalLifecycleMixin {
|
|||||||
}
|
}
|
||||||
PortalGunPortalRendererPool.clear();
|
PortalGunPortalRendererPool.clear();
|
||||||
PortalGunPortalViewAreaManager.clear();
|
PortalGunPortalViewAreaManager.clear();
|
||||||
|
PortalGunPortalVisibilityQueries.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Inject(method = "close", at = @At("HEAD"))
|
@Inject(method = "close", at = @At("HEAD"))
|
||||||
|
|||||||
+3
@@ -39,6 +39,9 @@ public abstract class EntityMoveTimeDilationMixin {
|
|||||||
if (Math.abs(rate - TimeDilationMath.NORMAL_RATE) < 0.001D) {
|
if (Math.abs(rate - TimeDilationMath.NORMAL_RATE) < 0.001D) {
|
||||||
return movement;
|
return movement;
|
||||||
}
|
}
|
||||||
|
if (rate > TimeDilationMath.NORMAL_RATE && TimeDilationApi.isHorizontalOnlyMovement(entity)) {
|
||||||
|
return movement.multiply(rate, 1.0D, rate);
|
||||||
|
}
|
||||||
return movement.scale(rate);
|
return movement.scale(rate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+21
-2
@@ -20,6 +20,25 @@ public abstract class EntityTimeDilationStateMixin implements TimeDilationEntity
|
|||||||
private boolean antarchy$inTimeDilationMove;
|
private boolean antarchy$inTimeDilationMove;
|
||||||
@Unique
|
@Unique
|
||||||
private boolean antarchy$applyingExternalImpulse;
|
private boolean antarchy$applyingExternalImpulse;
|
||||||
|
@Unique
|
||||||
|
private double antarchy$timeDilationCeiling = TimeDilationMath.MAX_RATE;
|
||||||
|
@Unique
|
||||||
|
private final Map<String, Double> antarchy$personalTimeDilationRates = new HashMap<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double antarchy$getTimeDilationCeiling() {
|
||||||
|
return this.antarchy$timeDilationCeiling;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void antarchy$setTimeDilationCeiling(double ceiling) {
|
||||||
|
this.antarchy$timeDilationCeiling = TimeDilationMath.clampCeiling(ceiling);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Double> antarchy$getPersonalTimeDilationRates() {
|
||||||
|
return this.antarchy$personalTimeDilationRates;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double antarchy$getTimeDilationRate() {
|
public double antarchy$getTimeDilationRate() {
|
||||||
@@ -29,7 +48,7 @@ public abstract class EntityTimeDilationStateMixin implements TimeDilationEntity
|
|||||||
@Override
|
@Override
|
||||||
public void antarchy$setTimeDilationRate(double rate) {
|
public void antarchy$setTimeDilationRate(double rate) {
|
||||||
double previousRate = this.antarchy$timeDilationRate;
|
double previousRate = this.antarchy$timeDilationRate;
|
||||||
this.antarchy$timeDilationRate = TimeDilationMath.clampRate(rate);
|
this.antarchy$timeDilationRate = TimeDilationMath.clampRate(rate, TimeDilationMath.ABSOLUTE_MAX_RATE);
|
||||||
if (previousRate != TimeDilationMath.NORMAL_RATE
|
if (previousRate != TimeDilationMath.NORMAL_RATE
|
||||||
&& this.antarchy$timeDilationRate == TimeDilationMath.NORMAL_RATE) {
|
&& this.antarchy$timeDilationRate == TimeDilationMath.NORMAL_RATE) {
|
||||||
this.antarchy$timeDilationTimerProgress.clear();
|
this.antarchy$timeDilationTimerProgress.clear();
|
||||||
@@ -53,7 +72,7 @@ public abstract class EntityTimeDilationStateMixin implements TimeDilationEntity
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int antarchy$consumeTimeDilationTicks(String timerKey, double rate) {
|
public int antarchy$consumeTimeDilationTicks(String timerKey, double rate) {
|
||||||
double clampedRate = TimeDilationMath.clampRate(rate);
|
double clampedRate = TimeDilationMath.clampRate(rate, TimeDilationMath.ABSOLUTE_MAX_RATE);
|
||||||
if (Math.abs(clampedRate - TimeDilationMath.NORMAL_RATE) < 0.001D) {
|
if (Math.abs(clampedRate - TimeDilationMath.NORMAL_RATE) < 0.001D) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 861 B |
+5
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"villager": {
|
||||||
|
"hat": "full"
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 613 B |
+5
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"villager": {
|
||||||
|
"hat": "none"
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-2
@@ -633,8 +633,8 @@ public final class AntarchyFabricClientBootstrap {
|
|||||||
BloodCrystalKatanaTrailHandler.render(context);
|
BloodCrystalKatanaTrailHandler.render(context);
|
||||||
ScorpionWhipTetherRenderHandler.render(context);
|
ScorpionWhipTetherRenderHandler.render(context);
|
||||||
WormHookTetherRenderHandler.render(context);
|
WormHookTetherRenderHandler.render(context);
|
||||||
if (context.matrixStack() != null && com.craisinlord.antarchy.content.client.renderer.PortalGunPortalViewRenderer.isEnabled()) {
|
if (com.craisinlord.antarchy.content.client.renderer.PortalGunPortalViewRenderer.isEnabled()) {
|
||||||
com.craisinlord.antarchy.content.client.renderer.PortalGunPortalViewRenderer.render(context.camera(), context.matrixStack().last().pose(), context.projectionMatrix(), context.tickCounter());
|
com.craisinlord.antarchy.content.client.renderer.PortalGunPortalViewRenderer.render(context.camera(), context.positionMatrix(), context.projectionMatrix(), context.tickCounter());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -17,7 +17,7 @@ public final class PortalGunPortalViewRenderHandler {
|
|||||||
if (!PortalGunPortalViewRenderer.isEnabled()) {
|
if (!PortalGunPortalViewRenderer.isEnabled()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (event.getStage() != RenderLevelStageEvent.Stage.AFTER_BLOCK_ENTITIES) {
|
if (event.getStage() != RenderLevelStageEvent.Stage.AFTER_LEVEL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
PortalGunPortalViewRenderer.render(event.getCamera(), event.getModelViewMatrix(), event.getProjectionMatrix(), event.getPartialTick());
|
PortalGunPortalViewRenderer.render(event.getCamera(), event.getModelViewMatrix(), event.getProjectionMatrix(), event.getPartialTick());
|
||||||
|
|||||||
Reference in new issue
Block a user