Create a world-to-screen projection helper
We also grab the view matrix and set up a world rendering hook I needed to use LWJGL 2's util for GLU, but I can probably switch to JOML or somethingmain
parent
d11f3e0927
commit
0d831078a8
|
@ -49,6 +49,8 @@ dependencies {
|
|||
}
|
||||
implementation("io.github.spair:imgui-java-natives-windows-ft:$imguiVersion")
|
||||
|
||||
implementation(files("vendor/lwjgl-util.jar"))
|
||||
|
||||
runtimeOnly("org.joml:joml:1.10.2")
|
||||
runtimeOnly("org.anarres:jcpp:1.4.14")
|
||||
modRuntimeOnly(files("vendor/iris-mc1.18.1-1.2.0-pre.jar"))
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
package codes.som.hibiscus.mixins;
|
||||
|
||||
import codes.som.hibiscus.HibiscusMod;
|
||||
import codes.som.hibiscus.events.RenderWorldEvent;
|
||||
import codes.som.hibiscus.util.graphics.WorldToScreenProjection;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.render.Camera;
|
||||
import net.minecraft.client.render.GameRenderer;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.util.math.Matrix4f;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(GameRenderer.class)
|
||||
public abstract class MixinGameRenderer {
|
||||
@Shadow
|
||||
@Final
|
||||
private MinecraftClient client;
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
private Camera camera;
|
||||
|
||||
@Inject(
|
||||
method = "renderWorld(FJLnet/minecraft/client/util/math/MatrixStack;)V",
|
||||
at = @At(
|
||||
value = "INVOKE_STRING",
|
||||
target = "Lnet/minecraft/util/profiler/Profiler;swap(Ljava/lang/String;)V",
|
||||
args = "ldc=hand",
|
||||
shift = At.Shift.BEFORE))
|
||||
private void preRenderHand(float tickDelta, long limitTime, MatrixStack matrices, CallbackInfo ci) {
|
||||
Matrix4f modelView = matrices.peek().getModel();
|
||||
|
||||
WorldToScreenProjection.INSTANCE.updateViewport(client.getWindow(), modelView);
|
||||
|
||||
matrices.push();
|
||||
RenderSystem.applyModelViewMatrix();
|
||||
HibiscusMod.bus().fire(new RenderWorldEvent(tickDelta, this.camera, matrices));
|
||||
matrices.pop();
|
||||
}
|
||||
}
|
|
@ -1,5 +1,8 @@
|
|||
package codes.som.hibiscus.events
|
||||
|
||||
import codes.som.hibiscus.api.event.Event
|
||||
import net.minecraft.client.render.Camera
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
|
||||
class PostRenderAllEvent(val delta: Float) : Event
|
||||
class RenderWorldEvent(val delta: Float, val camera: Camera, val matrices: MatrixStack) : Event
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
package codes.som.hibiscus.util.graphics
|
||||
|
||||
import codes.som.hibiscus.mc
|
||||
import net.minecraft.client.util.GlAllocationUtils
|
||||
import net.minecraft.client.util.Window
|
||||
import net.minecraft.util.math.MathHelper
|
||||
import net.minecraft.util.math.Matrix4f
|
||||
import net.minecraft.util.math.Vec3d
|
||||
import org.lwjgl.opengl.GL11
|
||||
import org.lwjgl.util.glu.Project.gluProject
|
||||
import kotlin.math.absoluteValue
|
||||
import kotlin.math.sign
|
||||
|
||||
object WorldToScreenProjection {
|
||||
private const val PROJECTION_MATRIX_PLANE_RATIO_INDEX = 10
|
||||
private const val PROJECTION_MATRIX_FAR_PLANE_INDEX = 14
|
||||
private const val VIEWPORT_MATRIX_Y_OFFSET_INDEX = 1
|
||||
private const val VIEWPORT_MATRIX_WIDTH_INDEX = 2
|
||||
private const val VIEWPORT_MATRIX_HEIGHT_INDEX = 3
|
||||
private const val PLANE_RATIO = -1.0f
|
||||
|
||||
private val FAR_PLANE_DISTANCE = -6.0E7f * MathHelper.SQUARE_ROOT_OF_TWO * 2.0f
|
||||
|
||||
private const val WINDOW_POSITION_VECTOR_DIMENSIONALITY = 3
|
||||
private const val WINDOW_POSITION_VECTOR_X_INDEX = 0
|
||||
private const val WINDOW_POSITION_VECTOR_Y_INDEX = 1
|
||||
private const val WINDOW_POSITION_VECTOR_Z_INDEX = 2
|
||||
|
||||
private val VIEWPORT_MATRIX =
|
||||
GlAllocationUtils.allocateByteBuffer(4 * Int.SIZE_BYTES).asIntBuffer() // 4x1 matrix of integers
|
||||
private val MODEL_MATRIX =
|
||||
GlAllocationUtils.allocateByteBuffer(16 * Float.SIZE_BYTES).asFloatBuffer() // 4x4 matrix of floats
|
||||
private val PROJECTION_MATRIX =
|
||||
GlAllocationUtils.allocateByteBuffer(16 * Float.SIZE_BYTES).asFloatBuffer() // 4x4 matrix of floats
|
||||
private val WINDOW_POSITION_VECTOR =
|
||||
GlAllocationUtils.allocateByteBuffer(WINDOW_POSITION_VECTOR_DIMENSIONALITY * Float.SIZE_BYTES).asFloatBuffer()
|
||||
|
||||
private var scaledWidth = 0
|
||||
private var scaledHeight = 0
|
||||
|
||||
private var cameraX = 0.0
|
||||
private var cameraY = 0.0
|
||||
private var cameraZ = 0.0
|
||||
|
||||
fun updateViewport(window: Window, modelView: Matrix4f) {
|
||||
scaledWidth = window.scaledWidth
|
||||
scaledHeight = window.scaledHeight
|
||||
val camera = mc.gameRenderer.camera
|
||||
val cameraPos = if (camera == null) Vec3d.ZERO else camera.pos
|
||||
cameraX = cameraPos.x
|
||||
cameraY = cameraPos.y
|
||||
cameraZ = cameraPos.z
|
||||
modelView.writeRowMajor(MODEL_MATRIX)
|
||||
GL11.glGetFloatv(GL11.GL_PROJECTION_MATRIX, PROJECTION_MATRIX)
|
||||
PROJECTION_MATRIX.put(PROJECTION_MATRIX_PLANE_RATIO_INDEX, PLANE_RATIO)
|
||||
PROJECTION_MATRIX.put(PROJECTION_MATRIX_FAR_PLANE_INDEX, FAR_PLANE_DISTANCE)
|
||||
VIEWPORT_MATRIX.put(VIEWPORT_MATRIX_Y_OFFSET_INDEX, scaledHeight)
|
||||
VIEWPORT_MATRIX.put(VIEWPORT_MATRIX_WIDTH_INDEX, scaledWidth)
|
||||
VIEWPORT_MATRIX.put(VIEWPORT_MATRIX_HEIGHT_INDEX, -scaledHeight)
|
||||
}
|
||||
|
||||
fun project(x: Double, y: Double, z: Double, offScreen: Boolean): Vec3d? {
|
||||
gluProject(
|
||||
(x - cameraX).toFloat(),
|
||||
(y - cameraY).toFloat(),
|
||||
(z - cameraZ).toFloat(),
|
||||
MODEL_MATRIX,
|
||||
PROJECTION_MATRIX,
|
||||
VIEWPORT_MATRIX,
|
||||
WINDOW_POSITION_VECTOR
|
||||
)
|
||||
|
||||
var windowX = WINDOW_POSITION_VECTOR[WINDOW_POSITION_VECTOR_X_INDEX]
|
||||
var windowY = WINDOW_POSITION_VECTOR[WINDOW_POSITION_VECTOR_Y_INDEX]
|
||||
val windowZ = WINDOW_POSITION_VECTOR[WINDOW_POSITION_VECTOR_Z_INDEX]
|
||||
if (windowZ > 0) {
|
||||
if (!offScreen) {
|
||||
return null
|
||||
}
|
||||
|
||||
windowX = scaledWidth - windowX
|
||||
windowY = scaledHeight - windowY
|
||||
|
||||
var offsetFromCentreWindowX = windowX - scaledWidth / 2
|
||||
var offsetFromCentreWindowY = windowY - scaledWidth / 2
|
||||
|
||||
if (offsetFromCentreWindowX.absoluteValue < offsetFromCentreWindowY.absoluteValue) {
|
||||
val newWindowXOffset = scaledWidth * offsetFromCentreWindowX.sign
|
||||
|
||||
offsetFromCentreWindowY *= newWindowXOffset / offsetFromCentreWindowX
|
||||
offsetFromCentreWindowX = newWindowXOffset
|
||||
} else {
|
||||
val newWindowYOffset = scaledHeight * offsetFromCentreWindowY.sign
|
||||
|
||||
offsetFromCentreWindowX *= newWindowYOffset / offsetFromCentreWindowY
|
||||
offsetFromCentreWindowY = newWindowYOffset
|
||||
}
|
||||
|
||||
windowX = scaledWidth / 2 + offsetFromCentreWindowX
|
||||
windowY = scaledHeight / 2 + offsetFromCentreWindowY
|
||||
}
|
||||
|
||||
return Vec3d(windowX.toDouble(), windowY.toDouble(), windowZ.toDouble())
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue