diff --git a/runelite-api/src/main/java/net/runelite/api/Perspective.java b/runelite-api/src/main/java/net/runelite/api/Perspective.java index 89d1fade1c..2ddd236fd5 100644 --- a/runelite-api/src/main/java/net/runelite/api/Perspective.java +++ b/runelite-api/src/main/java/net/runelite/api/Perspective.java @@ -123,24 +123,25 @@ public class Perspective y -= client.getCameraY(); z -= client.getCameraZ(); - int cameraPitch = client.getCameraPitch(); - int cameraYaw = client.getCameraYaw(); + final int cameraPitch = client.getCameraPitch(); + final int cameraYaw = client.getCameraYaw(); - int pitchSin = SINE[cameraPitch]; - int pitchCos = COSINE[cameraPitch]; - int yawSin = SINE[cameraYaw]; - int yawCos = COSINE[cameraYaw]; + final int pitchSin = SINE[cameraPitch]; + final int pitchCos = COSINE[cameraPitch]; + final int yawSin = SINE[cameraYaw]; + final int yawCos = COSINE[cameraYaw]; - int var8 = yawCos * x + y * yawSin >> 16; - y = yawCos * y - yawSin * x >> 16; - x = var8; - var8 = pitchCos * z - y * pitchSin >> 16; - y = z * pitchSin + y * pitchCos >> 16; + final int + x1 = x * yawCos + y * yawSin >> 16, + y1 = y * yawCos - x * yawSin >> 16, + y2 = z * pitchCos - y1 * pitchSin >> 16, + z1 = y1 * pitchCos + z * pitchSin >> 16; - if (y >= 50) + if (z1 >= 50) { - int pointX = client.getViewportWidth() / 2 + x * client.getScale() / y; - int pointY = client.getViewportHeight() / 2 + var8 * client.getScale() / y; + final int scale = client.getScale(); + final int pointX = client.getViewportWidth() / 2 + x1 * scale / z1; + final int pointY = client.getViewportHeight() / 2 + y2 * scale / z1; return new Point( pointX + client.getViewportXOffset(), pointY + client.getViewportYOffset()); @@ -151,9 +152,88 @@ public class Perspective } /** - * Translates a model's vertices into 2d space + * Translates a model's vertices into 2d space. There is a separate implementation for GPU since GPU + * uses a slightly more precise projection that can cause features like model outlines being noticeably + * off otherwise. */ public static void modelToCanvas(Client client, int end, int x3dCenter, int y3dCenter, int z3dCenter, int rotate, int[] x3d, int[] y3d, int[] z3d, int[] x2d, int[] y2d) + { + if (client.isGpu()) + { + modelToCanvasGpu(client, end, x3dCenter, y3dCenter, z3dCenter, rotate, x3d, y3d, z3d, x2d, y2d); + } + else + { + modelToCanvasCpu(client, end, x3dCenter, y3dCenter, z3dCenter, rotate, x3d, y3d, z3d, x2d, y2d); + } + } + + private static void modelToCanvasGpu(Client client, int end, int x3dCenter, int y3dCenter, int z3dCenter, int rotate, int[] x3d, int[] y3d, int[] z3d, int[] x2d, int[] y2d) + { + final int + cameraPitch = client.getCameraPitch(), + cameraYaw = client.getCameraYaw(); + final float + pitchSin = SINE[cameraPitch] / 65536.0f, + pitchCos = COSINE[cameraPitch] / 65536.0f, + yawSin = SINE[cameraYaw] / 65536.0f, + yawCos = COSINE[cameraYaw] / 65536.0f, + rotateSin = SINE[rotate] / 65536.0f, + rotateCos = COSINE[rotate] / 65536.0f, + + cx = x3dCenter - client.getCameraX(), + cy = y3dCenter - client.getCameraY(), + cz = z3dCenter - client.getCameraZ(), + + viewportXMiddle = client.getViewportWidth() / 2f, + viewportYMiddle = client.getViewportHeight() / 2f, + viewportXOffset = client.getViewportXOffset(), + viewportYOffset = client.getViewportYOffset(), + + zoom3d = client.getScale(); + + for (int i = 0; i < end; i++) + { + float x = x3d[i]; + float y = y3d[i]; + float z = z3d[i]; + + if (rotate != 0) + { + float x0 = x; + x = x0 * rotateCos + y * rotateSin; + y = y * rotateCos - x0 * rotateSin; + } + + x += cx; + y += cy; + z += cz; + + final float + x1 = x * yawCos + y * yawSin, + y1 = y * yawCos - x * yawSin, + y2 = z * pitchCos - y1 * pitchSin, + z1 = y1 * pitchCos + z * pitchSin; + + int viewX, viewY; + + if (z1 < 50) + { + viewX = Integer.MIN_VALUE; + viewY = Integer.MIN_VALUE; + } + else + { + viewX = Math.round((viewportXMiddle + x1 * zoom3d / z1) + viewportXOffset); + viewY = Math.round((viewportYMiddle + y2 * zoom3d / z1) + viewportYOffset); + } + + x2d[i] = viewX; + y2d[i] = viewY; + } + } + + private static void modelToCanvasCpu(Client client, int end, int x3dCenter, int y3dCenter, int z3dCenter, int rotate, int[] x3d, int[] y3d, int[] z3d, int[] x2d, int[] y2d) { final int cameraPitch = client.getCameraPitch(),