-
Notifications
You must be signed in to change notification settings - Fork 182
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
333 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package mrtjp.projectred.redui; | ||
|
||
import codechicken.lib.colour.EnumColour; | ||
import com.mojang.blaze3d.matrix.MatrixStack; | ||
import mrtjp.core.gui.GuiLib; | ||
import mrtjp.core.vec.Point; | ||
import mrtjp.core.vec.Rect; | ||
import mrtjp.core.vec.Size; | ||
import net.minecraft.client.gui.AbstractGui; | ||
import net.minecraft.util.text.StringTextComponent; | ||
import org.lwjgl.glfw.GLFW; | ||
|
||
import java.util.Collections; | ||
|
||
public class DebugRectNode extends AbstractGuiNode { | ||
|
||
private boolean clickDown = false; | ||
private int colorArgb = EnumColour.RED.argb(); | ||
private String name = ""; | ||
|
||
public void setName(String name) { | ||
this.name = name; | ||
} | ||
|
||
public void setColorArgb(int colorArgb) { | ||
this.colorArgb = colorArgb; | ||
} | ||
|
||
@Override | ||
public void drawBack(MatrixStack stack, Point mouse, float partialFrame) { | ||
GuiLib.drawLine(stack, getFrame().x(), getFrame().y(), getFrame().maxX(), getFrame().y(), 3, EnumColour.RED.argb()); | ||
GuiLib.drawLine(stack, getFrame().maxX(), getFrame().y(), getFrame().maxX(), getFrame().maxY(), 3, EnumColour.RED.argb()); | ||
GuiLib.drawLine(stack, getFrame().maxX(), getFrame().maxY(), getFrame().x(), getFrame().maxY(), 3, EnumColour.RED.argb()); | ||
GuiLib.drawLine(stack, getFrame().x(), getFrame().maxY(), getFrame().x(), getFrame().y(), 3, EnumColour.RED.argb()); | ||
|
||
AbstractGui.fill(stack, getFrame().x(), getFrame().y(), getFrame().maxX(), getFrame().maxY(), colorArgb); | ||
} | ||
|
||
@Override | ||
public void drawFront(MatrixStack stack, Point mouse, float partialFrame) { | ||
|
||
if (!isFirstHit(mouse)) | ||
return; | ||
|
||
// Rect around mouse position | ||
Rect cursorRect = new Rect(mouse.subtract(3, 3), new Size(6, 6)); | ||
AbstractGui.fill(stack, cursorRect.x(), cursorRect.y(), cursorRect.maxX(), cursorRect.maxY(), EnumColour.WHITE.argb(clickDown ? 150 : 50)); | ||
|
||
// Tooltip showing name | ||
renderTooltip(stack, mouse, Collections.singletonList(new StringTextComponent(name))); | ||
} | ||
|
||
@Override | ||
public boolean mouseClicked(Point p, int glfwMouseButton, boolean consumed) { | ||
if (!consumed&& glfwMouseButton == GLFW.GLFW_MOUSE_BUTTON_LEFT && isFirstHit(p) ) { | ||
clickDown = true; | ||
return true; | ||
} | ||
return false; | ||
} | ||
|
||
@Override | ||
public boolean mouseReleased(Point p, int glfwMouseButton, long timeHeld, boolean consumed) { | ||
if (clickDown && glfwMouseButton == GLFW.GLFW_MOUSE_BUTTON_LEFT) { | ||
clickDown = false; | ||
return true; | ||
} | ||
return false; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
package mrtjp.projectred.redui; | ||
|
||
import codechicken.lib.vec.Matrix4; | ||
import codechicken.lib.vec.Vector3; | ||
import com.mojang.blaze3d.matrix.MatrixStack; | ||
|
||
/** | ||
* Calculates a view matrix based on camera position, x rotation, and y rotation. | ||
*/ | ||
public class PVMMatrix { | ||
|
||
private final Matrix4 projectionMatrix = new Matrix4(); | ||
private final Matrix4 viewMatrix = new Matrix4(); | ||
private final Matrix4 orientationMatrix = new Matrix4(); | ||
|
||
private final Vector3 forward = new Vector3(); | ||
private final Vector3 right = new Vector3(); | ||
private final Vector3 up = new Vector3(); | ||
|
||
private final Vector3 cameraPosition = new Vector3(0, 0, 0); | ||
|
||
private double fovY; | ||
private double width; | ||
private double height; | ||
private double zNear; | ||
private double zFar; | ||
|
||
public void setProjection(double fovY, double windowWidth, double windowHeight, double zNear, double zFar) { | ||
this.fovY = fovY; | ||
this.width = windowWidth; | ||
this.height = windowHeight; | ||
this.zNear = zNear; | ||
this.zFar = zFar; | ||
projectionMatrix.setIdentity(); | ||
perspective(projectionMatrix, fovY, windowWidth / windowHeight, zNear, zFar); | ||
} | ||
|
||
public void setView(double x, double y, double z, double xRot, double yRot) { | ||
cameraPosition.set(x, y, z); | ||
|
||
orientationMatrix.setIdentity(); | ||
orientationMatrix.rotate(-yRot, Vector3.Y_POS); | ||
orientationMatrix.rotate(-xRot, Vector3.X_POS); | ||
|
||
forward.set(Vector3.Z_NEG); | ||
right.set(Vector3.X_POS); | ||
up.set(Vector3.Y_POS); | ||
|
||
orientationMatrix.apply(forward); | ||
orientationMatrix.apply(right); | ||
orientationMatrix.apply(up); | ||
|
||
viewMatrix.setIdentity(); | ||
lookAt(viewMatrix, cameraPosition, cameraPosition.copy().add(forward), up); | ||
viewMatrix.transpose(); | ||
} | ||
|
||
public Matrix4 getProjectionMatrix() { | ||
return projectionMatrix; | ||
} | ||
|
||
public Matrix4 getViewMatrix() { | ||
return viewMatrix; | ||
} | ||
|
||
public MatrixStack getModelViewMatrixStack() { | ||
MatrixStack stack = new MatrixStack(); | ||
stack.pushPose(); | ||
stack.last().pose().set(viewMatrix.toMatrix4f()); | ||
return stack; | ||
} | ||
|
||
/** | ||
* Projects NDC coordinates [-1, 1] onto a target plane at some fixed distance | ||
* to the camera taking into account the FOV. This target plane is assumed to be | ||
* parallel to the near and far planes of the perspective view frustum. | ||
* | ||
* @param ndcX X coordinate on the viewport in [-1, 1] range | ||
* @param ndcY Y coordinate on the viewport in [-1, 1] range | ||
* @param planeDist Distance of the projection | ||
* @return Projection of (ndcX, ndcY) into world-space | ||
*/ | ||
public Vector3 ndcToWorldCoordinates(double ndcX, double ndcY, double planeDist) { | ||
// Assume camera at 0,0,0 facing -z | ||
// Find top and right sides of target plane visible in this viewport | ||
double maxY = Math.tan(fovY / 2) * planeDist; | ||
double maxX = maxY * width / height; | ||
|
||
// Map ndc points onto plane to get look vector | ||
double dx = ndcX * maxX; | ||
double dy = ndcY * maxY; | ||
Vector3 lookVec = new Vector3(dx, dy, -planeDist); | ||
|
||
// Apply transforms to account for camera position and orientation | ||
orientationMatrix.apply(lookVec); | ||
lookVec.add(cameraPosition); | ||
|
||
return lookVec; | ||
} | ||
|
||
public static void perspective(Matrix4 m, double fovY, double aspect, double zNear, double zFar) { | ||
double tanHalfFovY = Math.tan(fovY / 2D); | ||
double deltaZ = zFar - zNear; | ||
|
||
m.m00 = 1D / (aspect * tanHalfFovY); | ||
m.m11 = 1D / tanHalfFovY; | ||
m.m22 = -(zFar + zNear) / deltaZ; | ||
m.m32 = -1; | ||
m.m23 = -2D * (zFar * zNear) / deltaZ; | ||
m.m33 = 0; | ||
} | ||
|
||
public static void orthographic(Matrix4 m, double width, double height, double zNear, double zFar) { | ||
double deltaZ = zFar - zNear; | ||
|
||
m.m00 = 2 / width; | ||
m.m11 = 2 / height; | ||
m.m22 = -2 / deltaZ; | ||
m.m33 = 1; | ||
m.m03 = -1; | ||
m.m13 = 1; | ||
m.m23 = -(zFar + zNear) / deltaZ; | ||
} | ||
|
||
public static void lookAt(Matrix4 m, Vector3 eye, Vector3 center, Vector3 up) { | ||
Vector3 f = center.copy().subtract(eye).normalize(); | ||
Vector3 s = f.copy().crossProduct(up).normalize(); | ||
Vector3 u = s.copy().crossProduct(f); | ||
|
||
m.m00 = s.x; | ||
m.m10 = s.y; | ||
m.m20 = s.z; | ||
|
||
m.m01 = u.x; | ||
m.m11 = u.y; | ||
m.m21 = u.z; | ||
|
||
m.m02 = -f.x; | ||
m.m12 = -f.y; | ||
m.m22 = -f.z; | ||
|
||
m.m30 = -s.dotProduct(eye); | ||
m.m31 = -u.dotProduct(eye); | ||
m.m32 = f.dotProduct(eye); | ||
} | ||
} |
111 changes: 111 additions & 0 deletions
111
src/core/scala/mrtjp/projectred/redui/ViewportRenderNode.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
package mrtjp.projectred.redui; | ||
|
||
import codechicken.lib.math.MathHelper; | ||
import codechicken.lib.vec.Vector3; | ||
import com.mojang.blaze3d.matrix.MatrixStack; | ||
import com.mojang.blaze3d.systems.RenderSystem; | ||
import mrtjp.core.vec.Point; | ||
import mrtjp.core.vec.Rect; | ||
import mrtjp.core.vec.Size; | ||
import mrtjp.core.vec.Vec2; | ||
import net.minecraft.util.text.ITextProperties; | ||
import org.lwjgl.opengl.GL11; | ||
|
||
import java.util.List; | ||
|
||
/** | ||
* Renders a viewport within the node frame. Overrides provided to obtain the camera position fov, etc. | ||
*/ | ||
public abstract class ViewportRenderNode extends AbstractGuiNode { | ||
|
||
private final PVMMatrix pvMatrix = new PVMMatrix(); | ||
|
||
protected abstract void renderInViewport(MatrixStack renderStack, Vec2 ndcMouse, float partialFrame, boolean isFirstHit); | ||
|
||
protected abstract List<ITextProperties> getToolTip(Point mousePosition, boolean isFirstHit); | ||
|
||
protected abstract double getTargetPlaneDistance(); | ||
|
||
protected abstract double getVerticalFOV(); | ||
|
||
protected abstract double getMaxRenderDist(); | ||
|
||
protected abstract Vector3 getCameraPosition(); | ||
|
||
protected Rect getGlFrame() { | ||
// Convert frame to screen space anchored at bottom-left instead of top-left | ||
Rect screenFrame = getRoot().getScreenFrame(); | ||
Rect frame = convertParentRectToScreen(getFrame()); | ||
|
||
Rect bottomLeftFrame = new Rect( | ||
new Point(frame.x(), screenFrame.height() - frame.y() - frame.height()), | ||
frame.size()); | ||
|
||
// Convert from GUI screen space to GL11 screen space using the Minecraft Gui Scale value | ||
double glWScale = getRoot().getMinecraft().getWindow().getGuiScale(); | ||
double glHScale = getRoot().getMinecraft().getWindow().getGuiScale(); | ||
|
||
return new Rect(new Point((int) Math.round(bottomLeftFrame.x() * glWScale), (int) Math.round(bottomLeftFrame.y() * glHScale)), | ||
new Size((int) Math.round(bottomLeftFrame.width() * glWScale), (int) Math.round(bottomLeftFrame.height() * glHScale))); | ||
} | ||
|
||
protected Vector3 mouseToWorld(Point mouse) { | ||
return ndcMouseToWorld(getFrame().ndc(mouse)); | ||
} | ||
|
||
protected Vector3 ndcMouseToWorld(Vec2 ndcMouse) { | ||
return pvMatrix.ndcToWorldCoordinates(ndcMouse.dx(), ndcMouse.dy(), getTargetPlaneDistance()); | ||
} | ||
|
||
@Override | ||
public void drawBack(MatrixStack stack, Point mouse, float partialFrame) { | ||
|
||
// Set up projection and view matrices | ||
Rect glFrame = getGlFrame(); | ||
pvMatrix.setProjection(getVerticalFOV(), glFrame.width(), glFrame.height(), 0.2F, getMaxRenderDist()); | ||
pvMatrix.setView(getCameraPosition().x, getCameraPosition().y, getCameraPosition().z, 90 * MathHelper.torad, 0); | ||
|
||
// Create a new viewport | ||
GL11.glPushAttrib(GL11.GL_VIEWPORT_BIT); | ||
RenderSystem.viewport(glFrame.x(), glFrame.y(), glFrame.width(), glFrame.height()); | ||
|
||
// Apply projection matrix | ||
RenderSystem.matrixMode(GL11.GL_PROJECTION); | ||
RenderSystem.pushMatrix(); | ||
RenderSystem.loadIdentity(); | ||
RenderSystem.multMatrix(pvMatrix.getProjectionMatrix().toMatrix4f()); | ||
|
||
RenderSystem.matrixMode(GL11.GL_MODELVIEW); | ||
RenderSystem.pushMatrix(); | ||
RenderSystem.loadIdentity(); | ||
|
||
/* | ||
TODO Figure out how to sandwich the viewport at this node's z position, +- some small range. | ||
For now, this only renders properly if correctly ordered in the tree (i.e. everything | ||
under it renders before, and everything above it renders after). | ||
*/ | ||
RenderSystem.clear(GL11.GL_DEPTH_BUFFER_BIT, false); | ||
|
||
// Render | ||
renderInViewport(pvMatrix.getModelViewMatrixStack(), getFrame().ndc(mouse), partialFrame, isFirstHit(mouse)); | ||
|
||
// Restore previous matrices | ||
RenderSystem.matrixMode(GL11.GL_PROJECTION); | ||
RenderSystem.popMatrix(); | ||
|
||
RenderSystem.matrixMode(GL11.GL_MODELVIEW); | ||
|
||
RenderSystem.popMatrix(); | ||
|
||
// Restore previous viewport | ||
GL11.glPopAttrib(); | ||
} | ||
|
||
@Override | ||
public void drawFront(MatrixStack stack, Point mouse, float partialFrame) { | ||
|
||
List<ITextProperties> tooltip = getToolTip(mouse, isFirstHit(mouse)); | ||
|
||
renderTooltip(stack, mouse, tooltip); | ||
} | ||
} |