Reduce render event GC pressure

This commit is contained in:
James Seibel
2026-05-30 09:17:21 -05:00
parent 9fe5dcc16e
commit 95e4db2998
12 changed files with 350 additions and 278 deletions
@@ -59,23 +59,25 @@ public abstract class DhApiBeforeBufferRenderEvent implements IDhApiEvent<DhApiB
* Measured in blocks.
* Should be applied to the model view matrix to move the buffer into its proper place.
*/
public final DhApiVec3f modelPos;
public DhApiVec3f modelPos;
public EventParam(DhApiRenderParam parent, DhApiVec3f modelPos)
public EventParam() { }
public void update(DhApiRenderParam parent, DhApiVec3f modelPos)
{
super(parent);
super.update(parent);
this.modelPos = modelPos;
}
@Override
public EventParam copy()
{
return new EventParam(
this, this.modelPos.copy()
);
}
public boolean getCopyBeforeFire() { return false; }
@Override
public EventParam copy() { return this; }
}
}
@@ -60,9 +60,9 @@ public abstract class DhApiBeforeFogRenderEvent implements IDhApiCancelableEvent
public static class EventParam implements IDhApiEventParam
{
private final DhApiRenderParam renderParam;
private final DhApiFogRenderParam originalFogRenderParam;
private final DhApiMutableFogRenderParam fogRenderParam;
private DhApiRenderParam renderParam;
private DhApiFogRenderParam originalFogRenderParam;
private DhApiMutableFogRenderParam fogRenderParam;
@@ -71,7 +71,9 @@ public abstract class DhApiBeforeFogRenderEvent implements IDhApiCancelableEvent
//=============//
//region
public EventParam(DhApiRenderParam renderParam, DhApiFogRenderParam fogRenderParam)
public EventParam() {}
public void update(DhApiRenderParam renderParam, DhApiFogRenderParam fogRenderParam)
{
this.renderParam = renderParam;
this.originalFogRenderParam = fogRenderParam;
@@ -54,44 +54,45 @@ public abstract class DhApiBeforeGenericObjectRenderEvent implements IDhApiCance
public static class EventParam extends DhApiRenderParam implements IDhApiEventParam
{
public final long boxGroupId;
public final String resourceLocationNamespace;
public final String resourceLocationPath;
public long boxGroupId;
public String resourceLocationNamespace;
public String resourceLocationPath;
public EventParam(
DhApiRenderParam renderParam,
IDhApiRenderableBoxGroup boxGroup
)
//==============//
// constructors //
//==============//
//region
public EventParam() { }
/** internal DH method */
public void update(DhApiRenderParam renderParam, IDhApiRenderableBoxGroup boxGroup)
{
super(renderParam);
super.update(renderParam);
this.boxGroupId = boxGroup.getId();
this.resourceLocationNamespace = boxGroup.getResourceLocationNamespace();
this.resourceLocationPath = boxGroup.getResourceLocationPath();
}
public EventParam(
DhApiRenderParam renderParam,
long boxGroupId, String resourceLocationNamespace, String resourceLocationPath
)
{
super(renderParam);
this.boxGroupId = boxGroupId;
this.resourceLocationNamespace = resourceLocationNamespace;
this.resourceLocationPath = resourceLocationPath;
}
//endregion
//================//
// base overrides //
//================//
//region
@Override
public EventParam copy()
{
return new EventParam(
this,
this.boxGroupId, this.resourceLocationNamespace, this.resourceLocationPath
);
}
public EventParam copy() { return this; }
//endregion
}
}
@@ -35,62 +35,69 @@ import com.seibel.distanthorizons.api.objects.math.DhApiMat4f;
public class DhApiRenderParam implements IDhApiEventParam
{
/** Indicates what render pass DH is currently rendering */
public final EDhApiRenderPass renderPass;
public EDhApiRenderPass renderPass;
/** Indicates how far into this tick the frame is. */
public final float partialTicks;
public float partialTicks;
/**
* Indicates DH's near clip plane, measured in blocks.
* Note: this may change based on time, player speed, and other factors.
*/
public final float nearClipPlane;
public float nearClipPlane;
/**
* Indicates DH's far clip plane, measured in blocks.
* Note: this may change based on time, player speed, and other factors.
*/
public final float farClipPlane;
public float farClipPlane;
/** The projection matrix Minecraft is using to render this frame. */
public final DhApiMat4f mcProjectionMatrix;
public final DhApiMat4f mcProjectionMatrix = new DhApiMat4f();
/** The model view matrix Minecraft is using to render this frame. */
public final DhApiMat4f mcModelViewMatrix;
public final DhApiMat4f mcModelViewMatrix = new DhApiMat4f();
public final DhApiMat4f mcInverseMvmProjectionMatrix = new DhApiMat4f();
/** The projection matrix Distant Horizons is using to render this frame. */
public final DhApiMat4f dhProjectionMatrix;
public final DhApiMat4f dhProjectionMatrix = new DhApiMat4f();
/** The model view matrix Distant Horizons is using to render this frame. */
public final DhApiMat4f dhModelViewMatrix;
public final DhApiMat4f dhModelViewMatrix = new DhApiMat4f();
/** combination of the MVM and projection matrices */
public final DhApiMat4f dhMvmProjMatrix;
public final DhApiMat4f dhMvmProjMatrix = new DhApiMat4f();
public final DhApiMat4f dhInverseMvmProjectionMatrix = new DhApiMat4f();
public final int worldYOffset;
public int worldYOffset;
/**
* The level currently being rendered.
*
* @since API 5.1.0
*/
public final IDhApiLevelWrapper clientLevelWrapper;
public IDhApiLevelWrapper clientLevelWrapper;
//==============//
// constructors //
//==============//
//region
public DhApiRenderParam(DhApiRenderParam parent)
public DhApiRenderParam() {}
/** Internal DH method */
public void update(DhApiRenderParam param)
{
this(
parent.renderPass,
parent.partialTicks,
parent.nearClipPlane, parent.farClipPlane,
parent.mcProjectionMatrix.copy(), parent.mcModelViewMatrix.copy(),
parent.dhProjectionMatrix.copy(), parent.dhModelViewMatrix.copy(),
parent.worldYOffset,
parent.clientLevelWrapper
this.update(
param.renderPass,
param.partialTicks,
param.nearClipPlane, param.farClipPlane,
param.mcProjectionMatrix, param.mcModelViewMatrix,
param.dhProjectionMatrix, param.mcModelViewMatrix,
param.worldYOffset,
param.clientLevelWrapper
);
}
public DhApiRenderParam(
/** Internal DH method */
public void update(
EDhApiRenderPass renderPass,
float newPartialTicks,
float nearClipPlane, float farClipPlane,
@@ -107,29 +114,51 @@ public class DhApiRenderParam implements IDhApiEventParam
this.farClipPlane = farClipPlane;
this.nearClipPlane = nearClipPlane;
this.mcProjectionMatrix = newMcProjectionMatrix;
this.mcModelViewMatrix = newMcModelViewMatrix;
// mc matricies
{
this.mcProjectionMatrix.set(newMcProjectionMatrix);
this.mcModelViewMatrix.set(newMcModelViewMatrix);
this.dhProjectionMatrix = newDhProjectionMatrix;
this.dhModelViewMatrix = newDhModelViewMatrix;
// inverse mvm Proj
this.mcInverseMvmProjectionMatrix.set(newMcProjectionMatrix);
this.mcInverseMvmProjectionMatrix.invert();
}
DhApiMat4f combinedMatrix = new DhApiMat4f(this.dhProjectionMatrix);
combinedMatrix.multiply(this.dhModelViewMatrix);
this.dhMvmProjMatrix = combinedMatrix;
// dh matricies
{
this.dhProjectionMatrix.set(newDhProjectionMatrix);
this.dhModelViewMatrix.set(newDhModelViewMatrix);
// proj
this.dhMvmProjMatrix.set(this.dhProjectionMatrix);
this.dhMvmProjMatrix.multiply(this.dhModelViewMatrix);
// inverse mvm Proj
this.dhInverseMvmProjectionMatrix.set(this.dhMvmProjMatrix);
this.dhInverseMvmProjectionMatrix.invert();
}
this.worldYOffset = worldYOffset;
this.clientLevelWrapper = clientLevelWrapper;
}
//endregion
//================//
// base overrides //
//================//
//region
@Override
public DhApiRenderParam copy() { return new DhApiRenderParam(this); }
public boolean getCopyBeforeFire() { return false; }
@Override
public DhApiRenderParam copy() { return this; }
//endregion
@@ -21,6 +21,8 @@ package com.seibel.distanthorizons.api.objects.math;
import com.seibel.distanthorizons.api.interfaces.util.IDhApiCopyable;
import java.nio.FloatBuffer;
/**
* An (almost) exact copy of Minecraft's 1.16.5
* implementation of a 4x4 float matrix. <br><br>
@@ -33,7 +35,7 @@ import com.seibel.distanthorizons.api.interfaces.util.IDhApiCopyable;
* </code>
*
* @author James Seibel
* @version 2024-6-30
* @version 2026-05-22
*/
public class DhApiMat4f implements IDhApiCopyable
{
@@ -62,6 +64,7 @@ public class DhApiMat4f implements IDhApiCopyable
//==============//
// constructors //
//==============//
//region
public DhApiMat4f() { /* all values are 0 */ }
@@ -71,14 +74,17 @@ public class DhApiMat4f implements IDhApiCopyable
this.m01 = sourceMatrix.m01;
this.m02 = sourceMatrix.m02;
this.m03 = sourceMatrix.m03;
this.m10 = sourceMatrix.m10;
this.m11 = sourceMatrix.m11;
this.m12 = sourceMatrix.m12;
this.m13 = sourceMatrix.m13;
this.m20 = sourceMatrix.m20;
this.m21 = sourceMatrix.m21;
this.m22 = sourceMatrix.m22;
this.m23 = sourceMatrix.m23;
this.m30 = sourceMatrix.m30;
this.m31 = sourceMatrix.m31;
this.m32 = sourceMatrix.m32;
@@ -109,12 +115,74 @@ public class DhApiMat4f implements IDhApiCopyable
this.m33 = values[15];
}
//endregion
//=========//
// methods //
//=========//
//region
/** Returns the values of this matrix in row major order (AKA rows then columns) */
public float[] getValuesAsArray()
{
float[] array = new float[16];
this.putValuesInArray(array);
return array;
}
/**
* Returns the values of this matrix in row major order (AKA rows then columns)
* @since API 7.0.0
*/
public void putValuesInArray(float[] array)
{
array[0] = this.m00;
array[1] = this.m01;
array[2] = this.m02;
array[3] = this.m03;
array[4] = this.m10;
array[5] = this.m11;
array[6] = this.m12;
array[7] = this.m13;
array[8] = this.m20;
array[9] = this.m21;
array[10] = this.m22;
array[11] = this.m23;
array[12] = this.m30;
array[13] = this.m31;
array[14] = this.m32;
array[15] = this.m33;
}
/** @since API 7.0.0 */
public void set(DhApiMat4f mat)
{
this.m00 = mat.m00;
this.m01 = mat.m01;
this.m02 = mat.m02;
this.m03 = mat.m03;
this.m10 = mat.m10;
this.m11 = mat.m11;
this.m12 = mat.m12;
this.m13 = mat.m13;
this.m20 = mat.m20;
this.m21 = mat.m21;
this.m22 = mat.m22;
this.m23 = mat.m23;
this.m30 = mat.m30;
this.m31 = mat.m31;
this.m32 = mat.m32;
this.m33 = mat.m33;
}
public void setIdentity()
{
@@ -279,47 +347,14 @@ public class DhApiMat4f implements IDhApiCopyable
this.m33 *= scalar;
}
//==================//
// Distant Horizons //
// methods //
//==================//
private static int getArrayIndex(int xIndex, int zIndex) { return (zIndex * 4) + xIndex; }
/** Returns the values of this matrix in row major order (AKA rows then columns) */
public float[] getValuesAsArray()
{
return new float[]{
this.m00,
this.m01,
this.m02,
this.m03,
this.m10,
this.m11,
this.m12,
this.m13,
this.m20,
this.m21,
this.m22,
this.m23,
this.m30,
this.m31,
this.m32,
this.m33,
};
}
//endregion
//================//
// base overrides //
//================//
//region
@Override
public boolean equals(Object obj)
@@ -388,4 +423,8 @@ public class DhApiMat4f implements IDhApiCopyable
@Override
public DhApiMat4f copy() { return new DhApiMat4f(this); }
//endregion
}
@@ -99,6 +99,11 @@ public class ClientApi
* Only downside is making sure each variable is populated before rendering.
*/
public static final DhRenderState RENDER_STATE = new DhRenderState();
/**
* static variable so we don't have to re-create it each frame,
* reducing GC pressure.
*/
private static final RenderParams RENDER_PARAMS = new RenderParams();
/**
* 50ms = 20 FPS
@@ -148,8 +153,6 @@ public class ClientApi
private Vec3d lastCameraPosForSpeedCheck = new Vec3d();
private long msSinceLastSpeedCheck = 0L;
public static long firstRenderTimeMs = 0;
/**
* keeping track of this is necessary to fix
* out-of-date LODs from rendering when the shading
@@ -570,7 +573,7 @@ public class ClientApi
// render prep and actual rendering into different threads/methods
// this is annoying since it's possible to start a render with only
// partially complete info, but there isn't a better option at the moment
RenderParams renderParams = new RenderParams(renderPass, RENDER_STATE);
RENDER_PARAMS.update(renderPass, RENDER_STATE);
//endregion
@@ -581,12 +584,7 @@ public class ClientApi
//============//
//region
if (firstRenderTimeMs == 0)
{
firstRenderTimeMs = System.currentTimeMillis();
}
String validationMessage = renderParams.getValidationErrorMessage(firstRenderTimeMs);
String validationMessage = RENDER_PARAMS.getValidationErrorMessage();
if (validationMessage != null)
{
// store the error message so it can be seen on the F3 screen
@@ -632,10 +630,10 @@ public class ClientApi
{
if (!renderingDeferredLayer)
{
boolean renderingCancelled = ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeRenderEvent.class, renderParams);
boolean renderingCancelled = ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeRenderEvent.class, RENDER_PARAMS);
if (!renderingCancelled)
{
LodRenderer.INSTANCE.render(renderParams, profiler);
LodRenderer.INSTANCE.render(RENDER_PARAMS, profiler);
}
if (!DhApi.Delayed.renderProxy.getDeferTransparentRendering())
@@ -645,10 +643,10 @@ public class ClientApi
}
else
{
boolean renderingCancelled = ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeDeferredRenderEvent.class, renderParams);
boolean renderingCancelled = ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeDeferredRenderEvent.class, RENDER_PARAMS);
if (!renderingCancelled)
{
LodRenderer.INSTANCE.renderDeferred(renderParams, profiler);
LodRenderer.INSTANCE.renderDeferred(RENDER_PARAMS, profiler);
}
@@ -669,11 +667,11 @@ public class ClientApi
{
// meta renderer needed for render state/texture
// for setup on some APIs (IE openGL)
metaRenderer.runRenderPassSetup(renderParams);
metaRenderer.runRenderPassSetup(RENDER_PARAMS);
testRenderer.render(renderParams);
testRenderer.render(RENDER_PARAMS);
metaRenderer.runRenderPassCleanup(renderParams);
metaRenderer.runRenderPassCleanup(RENDER_PARAMS);
}
else
{
@@ -730,8 +728,8 @@ public class ClientApi
// don't fade when Iris shaders are active, otherwise the rendering can get weird
&& !DhApiRenderProxy.INSTANCE.getDeferTransparentRendering())
{
RenderParams renderParams = new RenderParams(EDhApiRenderPass.OPAQUE, RENDER_STATE);
fadeRenderer.render(renderParams);
RENDER_PARAMS.update(EDhApiRenderPass.OPAQUE, RENDER_STATE);
fadeRenderer.render(RENDER_PARAMS);
}
}
/**
@@ -761,8 +759,8 @@ public class ClientApi
&& !DhApiRenderProxy.INSTANCE.getDeferTransparentRendering();
if (renderFade)
{
RenderParams renderParams = new RenderParams(EDhApiRenderPass.TRANSPARENT, RENDER_STATE);
fadeRenderer.render(renderParams);
RENDER_PARAMS.update(EDhApiRenderPass.TRANSPARENT, RENDER_STATE);
fadeRenderer.render(RENDER_PARAMS);
}
}
}
@@ -22,6 +22,7 @@ package com.seibel.distanthorizons.core.render;
import com.seibel.distanthorizons.api.DhApi;
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiCullingFrustum;
import com.seibel.distanthorizons.api.interfaces.override.rendering.IDhApiShadowCullingFrustum;
import com.seibel.distanthorizons.api.objects.math.DhApiMat4f;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodBufferContainer;
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
@@ -36,9 +37,11 @@ import com.seibel.distanthorizons.core.render.QuadTree.LodRenderSection;
import com.seibel.distanthorizons.core.render.renderer.LodRenderer;
import com.seibel.distanthorizons.core.render.renderer.cullingFrustum.DhFrustumBounds;
import com.seibel.distanthorizons.core.render.renderer.cullingFrustum.NeverCullFrustum;
import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.util.objects.SortedArraySet;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IIrisAccessor;
import com.seibel.distanthorizons.coreapi.ModInfo;
import com.seibel.distanthorizons.coreapi.interfaces.dependencyInjection.IOverrideInjector;
import com.seibel.distanthorizons.core.util.math.Mat4f;
import com.seibel.distanthorizons.core.util.math.Vec3d;
@@ -58,6 +61,13 @@ public class RenderBufferHandler implements AutoCloseable
private static final IIrisAccessor IRIS_ACCESSOR = ModAccessorInjector.INSTANCE.get(IIrisAccessor.class);
// static values for re-use to reduce GC pressure
private static final float[] JOML_TRANSPOSE_ARRAY = new float[16];
private static final Matrix4f WORLD_VIEW_JOML_MATRIX = new Matrix4f();
private static final Matrix4f WORLD_VIEW_PROJ_JOML_MATRIX = new Matrix4f();
private static final Mat4f FRUSTOM_DH_MATRIX = new Mat4f();
/** contains all relevant data */
public final LodQuadTree lodQuadTree;
@@ -123,6 +133,14 @@ public class RenderBufferHandler implements AutoCloseable
*/
public void buildRenderList(RenderParams renderParams)
{
if (ModInfo.IS_DEV_BUILD)
{
if (!RenderThreadTaskHandler.INSTANCE.isCurrentThread())
{
LodUtil.assertNotReach("Should only be run on the render thread");
}
}
// clear the old list so we can start fresh
this.loadedNearToFarBuffers.clear();
@@ -156,18 +174,21 @@ public class RenderBufferHandler implements AutoCloseable
Vec3d cameraPos = MC_RENDER.getCameraExactPosition();
Matrix4fc matWorldView = new Matrix4f()
.setTransposed(renderParams.mcModelViewMatrix.getValuesAsArray())
.translate(
-(float) cameraPos.x,
-(float) cameraPos.y,
-(float) cameraPos.z);
renderParams.mcModelViewMatrix.putValuesInArray(JOML_TRANSPOSE_ARRAY);
WORLD_VIEW_JOML_MATRIX
.setTransposed(JOML_TRANSPOSE_ARRAY)
.translate(
-(float) cameraPos.x,
-(float) cameraPos.y,
-(float) cameraPos.z);
Matrix4fc matWorldViewProjection = new Matrix4f()
.setTransposed(renderParams.dhProjectionMatrix.getValuesAsArray())
.mul(matWorldView);
renderParams.dhProjectionMatrix.putValuesInArray(JOML_TRANSPOSE_ARRAY);
WORLD_VIEW_PROJ_JOML_MATRIX
.setTransposed(JOML_TRANSPOSE_ARRAY)
.mul(WORLD_VIEW_JOML_MATRIX);
frustum.update(worldMinY, worldMinY + worldHeight, new Mat4f(matWorldViewProjection));
FRUSTOM_DH_MATRIX.set(WORLD_VIEW_PROJ_JOML_MATRIX);
frustum.update(worldMinY, worldMinY + worldHeight, FRUSTOM_DH_MATRIX);
}
@@ -175,6 +196,7 @@ public class RenderBufferHandler implements AutoCloseable
//=========================//
// Update the section list //
//=========================//
//region
if (isShadowPass)
{
@@ -251,6 +273,9 @@ public class RenderBufferHandler implements AutoCloseable
{
this.visibleBufferCount = this.loadedNearToFarBuffers.size();
}
//endregion
}
//endregion
@@ -2,22 +2,19 @@ package com.seibel.distanthorizons.core.render;
import com.seibel.distanthorizons.api.enums.rendering.EDhApiRenderPass;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
import com.seibel.distanthorizons.api.objects.math.DhApiMat4f;
import com.seibel.distanthorizons.core.api.internal.SharedApi;
import com.seibel.distanthorizons.core.api.internal.rendering.DhRenderState;
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.jar.EPlatform;
import com.seibel.distanthorizons.core.level.IDhClientLevel;
import com.seibel.distanthorizons.core.util.RenderUtil;
import com.seibel.distanthorizons.core.util.math.Mat4f;
import com.seibel.distanthorizons.core.util.math.Vec3d;
import com.seibel.distanthorizons.core.util.threading.PriorityTaskPicker;
import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil;
import com.seibel.distanthorizons.core.world.IDhClientWorld;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.ILightMapWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.AbstractOptifineAccessor;
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IOptifineAccessor;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.renderPass.IDhGenericRenderer;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
@@ -34,8 +31,12 @@ public class RenderParams extends DhApiRenderParam
private static final IOptifineAccessor OPTIFINE_ACCESSOR = ModAccessorInjector.INSTANCE.get(IOptifineAccessor.class);
private static final long TIME_FOR_MAC_TO_FINISH_COMPILING_IN_MS = 10_000;
private static boolean initialLoadingComplete = false;
/**
* Copy used for API events. <br>
* A separate copy is used to prevent API users from accidentally setting values
* that screw up DH's copy of the render parameters.
*/
public final DhApiRenderParam apiCopy = new DhApiRenderParam();
public IDhClientWorld dhClientWorld;
@@ -58,36 +59,27 @@ public class RenderParams extends DhApiRenderParam
//=============//
//region
public RenderParams(EDhApiRenderPass renderPass, DhRenderState renderState)
public void update(EDhApiRenderPass renderPass, DhRenderState renderState)
{
this(renderPass,
renderState.partialTickTime,
renderState.mcProjectionMatrix, renderState.mcModelViewMatrix,
renderState.clientLevelWrapper,
renderState.vanillaFogEnabled
);
}
private RenderParams(
EDhApiRenderPass renderPass,
float newPartialTicks,
Mat4f newMcProjectionMatrix, Mat4f newMcModelViewMatrix,
IClientLevelWrapper clientLevelWrapper,
boolean vanillaFogEnabled
)
{
super(renderPass,
newPartialTicks,
RenderUtil.getNearClipPlaneInBlocks(), RenderUtil.getFarClipPlaneDistanceInBlocks(),
newMcProjectionMatrix, newMcModelViewMatrix,
RenderUtil.createLodProjectionMatrix(newMcProjectionMatrix), RenderUtil.createLodModelViewMatrix(newMcModelViewMatrix),
clientLevelWrapper.getMinHeight(),
clientLevelWrapper);
RenderUtil.setDhProjectionMatrix(this.dhProjectionMatrix, renderState.mcProjectionMatrix);
this.dhModelViewMatrix.set(renderState.mcModelViewMatrix); // DH and MC MVM matrix are the same
super.update(renderPass,
renderState.partialTickTime,
RenderUtil.getNearClipPlaneInBlocks(), RenderUtil.getFarClipPlaneDistanceInBlocks(),
renderState.mcProjectionMatrix, renderState.mcModelViewMatrix,
this.dhProjectionMatrix, this.dhModelViewMatrix,
renderState.clientLevelWrapper.getMinHeight(),
renderState.clientLevelWrapper);
this.clientLevelWrapper = renderState.clientLevelWrapper;
this.dhClientWorld = SharedApi.tryGetDhClientWorld();
if (this.dhClientWorld != null)
{
this.dhClientLevel = (IDhClientLevel) this.dhClientWorld.getLevel(clientLevelWrapper);
this.dhClientLevel = (IDhClientLevel) this.dhClientWorld.getLevel(this.clientLevelWrapper);
if (this.dhClientLevel != null)
{
this.renderBufferHandler = this.dhClientLevel.getRenderBufferHandler();
@@ -95,7 +87,6 @@ public class RenderParams extends DhApiRenderParam
}
}
this.clientLevelWrapper = clientLevelWrapper;
this.lightmap = MC_RENDER.getLightmapWrapper(this.clientLevelWrapper);
if (MC_CLIENT.playerExists())
@@ -103,8 +94,9 @@ public class RenderParams extends DhApiRenderParam
this.exactCameraPosition = MC_RENDER.getCameraExactPosition();
}
this.vanillaFogEnabled = vanillaFogEnabled;
this.vanillaFogEnabled = renderState.vanillaFogEnabled;
this.apiCopy.update(this);
}
//endregion
@@ -120,7 +112,7 @@ public class RenderParams extends DhApiRenderParam
* Should be called before rendering is done.
* @return a message if LODs shouldn't be rendered, null if the LODs can render
*/
public String getValidationErrorMessage(long firstRenderTimeMs)
public String getValidationErrorMessage()
{
// Note: all strings here should be constants to prevent String allocations
@@ -162,12 +154,21 @@ public class RenderParams extends DhApiRenderParam
return "No Generic Renderer Present";
}
if (this.dhModelViewMatrix == null
|| this.mcModelViewMatrix == null)
if (this.dhModelViewMatrix.equals(Mat4f.IDENTITY)
|| this.dhModelViewMatrix.equals(Mat4f.EMPTY))
{
return "No MVM or Proj Matrix Given";
return "No DH MVM Matrix Given";
}
if (this.mcModelViewMatrix.equals(Mat4f.IDENTITY)
|| this.mcModelViewMatrix.equals(Mat4f.EMPTY))
{
return "No MC MVM Matrix Given";
}
// projection matrix not checked since there are some MC versions where
// the MVM and projection matrices are pre-multiplied together
if (OPTIFINE_ACCESSOR != null
&& MC_RENDER.getTargetFramebuffer() == -1)
{
@@ -21,9 +21,18 @@ public class FogRenderParamFactory
{
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
/** cached object to reduce GC pressure */
private static final DhApiBeforeFogRenderEvent.EventParam EVENT_PARAM = new DhApiBeforeFogRenderEvent.EventParam();
public static DhApiBeforeFogRenderEvent.EventParam createRenderParam(RenderParams renderParams)
//=========//
// methods //
//=========//
//region
/** returns a cached object to reduce GC pressure */
public static DhApiBeforeFogRenderEvent.EventParam getRenderParam(RenderParams renderParams)
{
Color fogColor = getFogColor(renderParams.partialTicks);
@@ -74,8 +83,8 @@ public class FogRenderParamFactory
heightFogDensity
);
DhApiBeforeFogRenderEvent.EventParam fogRenderEventParam = new DhApiBeforeFogRenderEvent.EventParam(renderParams, fogRenderParam);
return fogRenderEventParam;
EVENT_PARAM.update(renderParams, fogRenderParam);
return EVENT_PARAM;
}
private static Color getFogColor(float partialTicks)
@@ -94,6 +103,8 @@ public class FogRenderParamFactory
return fogColor;
}
//endregion
}
@@ -21,7 +21,6 @@ package com.seibel.distanthorizons.core.render.renderer;
import com.seibel.distanthorizons.api.enums.rendering.EDhApiTransparency;
import com.seibel.distanthorizons.api.methods.events.abstractEvents.*;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiFogRenderParam;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dataObjects.render.bufferBuilding.LodBufferContainer;
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
@@ -119,9 +118,9 @@ public class LodRenderer
private void renderTerrain(RenderParams renderParams, IProfilerWrapper profiler, boolean runningDeferredPass)
{
// validate rendering //
//====================//
//====================//
//===============//
// validate pass //
//===============//
//region
boolean deferTransparentRendering = DhApiRenderProxy.INSTANCE.getDeferTransparentRendering();
@@ -147,7 +146,7 @@ public class LodRenderer
//=================//
//region
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeRenderSetupEvent.class, renderParams);
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeRenderSetupEvent.class, renderParams.apiCopy);
try (IProfilerWrapper.IProfileBlock terrainRender_profile = profiler.push("LOD GL setup")) // starts the new profile block for most DH rendering
{
@@ -203,7 +202,7 @@ public class LodRenderer
renderFog |= renderParams.vanillaFogEnabled;
}
DhApiBeforeFogRenderEvent.EventParam fogRenderEventParam = FogRenderParamFactory.createRenderParam(renderParams);
DhApiBeforeFogRenderEvent.EventParam fogRenderEventParam = FogRenderParamFactory.getRenderParam(renderParams);
//endregion
@@ -216,7 +215,7 @@ public class LodRenderer
if (!runningDeferredPass)
{
// needs to be fired after all the textures have been created/bound
boolean clearTextures = !ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeTextureClearEvent.class, renderParams);
boolean clearTextures = !ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeTextureClearEvent.class, renderParams.apiCopy);
if (clearTextures)
{
this.metaRenderer.clearDhDepthAndColorTextures(renderParams);
@@ -318,7 +317,7 @@ public class LodRenderer
// Apply to the MC Framebuffer //
//=============================//
boolean cancelApplyShader = ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeApplyShaderRenderEvent.class, renderParams);
boolean cancelApplyShader = ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeApplyShaderRenderEvent.class, renderParams.apiCopy);
if (!cancelApplyShader)
{
profiler.popPush("Apply to MC");
@@ -356,7 +355,7 @@ public class LodRenderer
//================//
profiler.popPush("LOD cleanup");
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeRenderCleanupEvent.class, renderParams);
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeRenderCleanupEvent.class, renderParams.apiCopy);
this.metaRenderer.runRenderPassCleanup(renderParams);
}
@@ -34,7 +34,6 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IIrisAccess
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
import com.seibel.distanthorizons.coreapi.util.MathUtil;
import com.seibel.distanthorizons.core.util.math.Mat4f;
/**
* This holds miscellaneous helper code
@@ -76,7 +75,7 @@ public class RenderUtil
*
* @param mcProjMat Minecraft's current projection matrix
*/
public static Mat4f createLodProjectionMatrix(DhApiMat4f mcProjMat)
public static void setDhProjectionMatrix(DhApiMat4f updateMatrix, DhApiMat4f mcProjMat)
{
// in James' testing a near clip plane distance of 2 blocks is enough to allow the fragment
// culling to take effect instead of seeing the near clip plane.
@@ -93,28 +92,32 @@ public class RenderUtil
float farClipDist = RenderUtil.getFarClipPlaneDistanceInBlocks();
// Create a copy of the current matrix, so it won't be modified.
Mat4f lodProj = new Mat4f(mcProjMat);
updateMatrix.set(mcProjMat);
// Set new far and near clip plane values.
if (RENDER_API_DEF.getRenderDepth() == EDhRenderDepth.FORWARD_Z)
{
lodProj.setClipPlanes(nearClipDist, farClipDist, false);
setClipPlanes(updateMatrix, nearClipDist, farClipDist, false);
}
else
{
lodProj.setClipPlanes(farClipDist, nearClipDist, true);
setClipPlanes(updateMatrix, farClipDist, nearClipDist, true);
}
return lodProj;
}
/** create and return a new projection matrix based on MC's modelView and projection matrices */
public static Mat4f createLodModelViewMatrix(DhApiMat4f mcModelViewMat)
/**
* Changes the values that store the clipping planes.
* Formula for calculating matrix values is the same that OpenGL uses when making matrices.
*
* @param nearClip New near clipping plane value.
* @param farClip New far clipping plane value.
*/
public static void setClipPlanes(DhApiMat4f matrix, float nearClip, float farClip, boolean zZeroToOne)
{
// nothing beyond copying needs to be done to MC's MVM currently,
// this method is just here in case that changes in the future
return new Mat4f(mcModelViewMat);
// formula copied JOML's implementation to match Minecraft
matrix.m22 = (zZeroToOne ? farClip : farClip + nearClip) / (nearClip - farClip);
matrix.m23 = (zZeroToOne ? farClip : farClip + farClip) * nearClip / (nearClip - farClip);
}
//endregion
@@ -20,8 +20,6 @@
package com.seibel.distanthorizons.core.util.math;
import com.seibel.distanthorizons.api.objects.math.DhApiMat4f;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.wrapperInterfaces.render.AbstractDhRenderApiDefinition;
import org.joml.Matrix4f;
import org.joml.Matrix4fc;
@@ -36,12 +34,33 @@ import java.nio.FloatBuffer;
*/
public class Mat4f extends DhApiMat4f
{
/**
* A matrix containing all 0's. <br><br>
*
* Should not be modified. <br>
* Can be used for comparison testing.
*/
public static final DhApiMat4f EMPTY = new DhApiMat4f();
/**
* The 4x4 identity matrix. <br><br>
*
* Should not be modified. <br>
* Can be used for comparison testing.
*/
public static final DhApiMat4f IDENTITY = new DhApiMat4f();
static
{
IDENTITY.setIdentity();
}
//==============//
// constructors //
//==============//
public Mat4f() { /* all values are 0 */ }
/** all values are 0 */
public Mat4f() { }
public Mat4f(DhApiMat4f sourceMatrix) { super(sourceMatrix); }
@@ -50,56 +69,31 @@ public class Mat4f extends DhApiMat4f
/** Expects the values of the input array to be in row major order (AKA rows then columns) */
public Mat4f(float[] values) { super(values); }
public Mat4f(Matrix4fc sourceMatrix) { this(convertJomlMatrixToArray(sourceMatrix)); }
private static float[] convertJomlMatrixToArray(Matrix4fc sourceMatrix)
public Mat4f(Matrix4fc sourceMatrix) { this.set(sourceMatrix); }
public void set(Matrix4fc sourceMatrix)
{
FloatBuffer buffer = FloatBuffer.allocate(16);
// JOML matricies are stored transposed vs DH's matricies
this.m00 = sourceMatrix.m00();
this.m01 = sourceMatrix.m10();
this.m02 = sourceMatrix.m20();
this.m03 = sourceMatrix.m30();
buffer.put(bufferIndex(0, 0), sourceMatrix.m00());
buffer.put(bufferIndex(0, 1), sourceMatrix.m01());
buffer.put(bufferIndex(0, 2), sourceMatrix.m02());
buffer.put(bufferIndex(0, 3), sourceMatrix.m03());
this.m10 = sourceMatrix.m01();
this.m11 = sourceMatrix.m11();
this.m12 = sourceMatrix.m21();
this.m13 = sourceMatrix.m31();
buffer.put(bufferIndex(1, 0), sourceMatrix.m10());
buffer.put(bufferIndex(1, 1), sourceMatrix.m11());
buffer.put(bufferIndex(1, 2), sourceMatrix.m12());
buffer.put(bufferIndex(1, 3), sourceMatrix.m13());
this.m20 = sourceMatrix.m02();
this.m21 = sourceMatrix.m12();
this.m22 = sourceMatrix.m22();
this.m23 = sourceMatrix.m32();
buffer.put(bufferIndex(2, 0), sourceMatrix.m20());
buffer.put(bufferIndex(2, 1), sourceMatrix.m21());
buffer.put(bufferIndex(2, 2), sourceMatrix.m22());
buffer.put(bufferIndex(2, 3), sourceMatrix.m23());
buffer.put(bufferIndex(3, 0), sourceMatrix.m30());
buffer.put(bufferIndex(3, 1), sourceMatrix.m31());
buffer.put(bufferIndex(3, 2), sourceMatrix.m32());
buffer.put(bufferIndex(3, 3), sourceMatrix.m33());
return buffer.array();
this.m30 = sourceMatrix.m03();
this.m31 = sourceMatrix.m13();
this.m32 = sourceMatrix.m23();
this.m33 = sourceMatrix.m33();
}
private static int bufferIndex(int xIndex, int zIndex) { return (zIndex * 4) + xIndex; }
public void store(FloatBuffer floatBuffer)
{
floatBuffer.put(bufferIndex(0, 0), this.m00);
floatBuffer.put(bufferIndex(0, 1), this.m01);
floatBuffer.put(bufferIndex(0, 2), this.m02);
floatBuffer.put(bufferIndex(0, 3), this.m03);
floatBuffer.put(bufferIndex(1, 0), this.m10);
floatBuffer.put(bufferIndex(1, 1), this.m11);
floatBuffer.put(bufferIndex(1, 2), this.m12);
floatBuffer.put(bufferIndex(1, 3), this.m13);
floatBuffer.put(bufferIndex(2, 0), this.m20);
floatBuffer.put(bufferIndex(2, 1), this.m21);
floatBuffer.put(bufferIndex(2, 2), this.m22);
floatBuffer.put(bufferIndex(2, 3), this.m23);
floatBuffer.put(bufferIndex(3, 0), this.m30);
floatBuffer.put(bufferIndex(3, 1), this.m31);
floatBuffer.put(bufferIndex(3, 2), this.m32);
floatBuffer.put(bufferIndex(3, 3), this.m33);
}
public static Matrix4f createJomlMatrix(DhApiMat4f matrix)
{
@@ -171,26 +165,6 @@ public class Mat4f extends DhApiMat4f
// Forge methods //
//===============//
public void set(DhApiMat4f mat)
{
this.m00 = mat.m00;
this.m01 = mat.m01;
this.m02 = mat.m02;
this.m03 = mat.m03;
this.m10 = mat.m10;
this.m11 = mat.m11;
this.m12 = mat.m12;
this.m13 = mat.m13;
this.m20 = mat.m20;
this.m21 = mat.m21;
this.m22 = mat.m22;
this.m23 = mat.m23;
this.m30 = mat.m30;
this.m31 = mat.m31;
this.m32 = mat.m32;
this.m33 = mat.m33;
}
public void add(DhApiMat4f other)
{
m00 += other.m00;
@@ -229,20 +203,8 @@ public class Mat4f extends DhApiMat4f
this.m23 = z;
}
/**
* Changes the values that store the clipping planes.
* Formula for calculating matrix values is the same that OpenGL uses when making matrices.
*
* @param nearClip New near clipping plane value.
* @param farClip New far clipping plane value.
*/
public void setClipPlanes(float nearClip, float farClip, boolean zZeroToOne)
{
//convert to matrix values, formula copied JOML's implementation to match Minecraft
this.m22 = (zZeroToOne ? farClip : farClip + nearClip) / (nearClip - farClip);
this.m23 = (zZeroToOne ? farClip : farClip + farClip) * nearClip / (nearClip - farClip);
}
public Mat4f copy() { return new Mat4f(this); }
}