diff --git a/cache/src/main/java/net/runelite/cache/definitions/ModelDefinition.java b/cache/src/main/java/net/runelite/cache/definitions/ModelDefinition.java index f0d8a554bc..ee0ed4939f 100644 --- a/cache/src/main/java/net/runelite/cache/definitions/ModelDefinition.java +++ b/cache/src/main/java/net/runelite/cache/definitions/ModelDefinition.java @@ -1,5 +1,7 @@ package net.runelite.cache.definitions; +import java.util.Arrays; +import net.runelite.cache.models.CircularAngle; import net.runelite.cache.models.FaceNormal; import net.runelite.cache.models.VertexNormal; @@ -153,7 +155,8 @@ public class ModelDefinition } /** - * Computes the UV coordinates for every three-vertex face that has a texture. + * Computes the UV coordinates for every three-vertex face that has a + * texture. */ public void computeTextureUVCoordinates() { @@ -266,4 +269,80 @@ public class ModelDefinition } } } + + public void rotate(int orientation) + { + int sin = CircularAngle.SINE[orientation]; + int cos = CircularAngle.COSINE[orientation]; + + assert vertexPositionsX.length == vertexPositionsY.length; + assert vertexPositionsY.length == vertexPositionsZ.length; + + for (int i = 0; i < vertexPositionsX.length; ++i) + { + vertexPositionsX[i] = vertexPositionsX[i] * cos + vertexPositionsZ[i] * sin >> 16; + vertexPositionsZ[i] = vertexPositionsZ[i] * cos - vertexPositionsX[i] * sin >> 16; + } + + reset(); + } + + public void method1493() + { + int var1; + for (var1 = 0; var1 < this.vertexCount; ++var1) + { + this.vertexPositionsZ[var1] = -this.vertexPositionsZ[var1]; + } + + for (var1 = 0; var1 < this.faceCount; ++var1) + { + int var2 = this.faceVertexIndices1[var1]; + this.faceVertexIndices1[var1] = this.faceVertexIndices3[var1]; + this.faceVertexIndices3[var1] = var2; + } + + reset(); + } + + public void rotate1() + { + for (int var1 = 0; var1 < this.vertexCount; ++var1) + { + int var2 = this.vertexPositionsX[var1]; + this.vertexPositionsX[var1] = this.vertexPositionsZ[var1]; + this.vertexPositionsZ[var1] = -var2; + } + + reset(); + } + + public void rotate2() + { + for (int var1 = 0; var1 < this.vertexCount; ++var1) + { + this.vertexPositionsX[var1] = -this.vertexPositionsX[var1]; + this.vertexPositionsZ[var1] = -this.vertexPositionsZ[var1]; + } + + reset(); + } + + public void rotate3() + { + for (int var1 = 0; var1 < this.vertexCount; ++var1) + { + int var2 = this.vertexPositionsZ[var1]; + this.vertexPositionsZ[var1] = this.vertexPositionsX[var1]; + this.vertexPositionsX[var1] = -var2; + } + + reset(); + } + + private void reset() + { + faceNormals = null; + faceTextureUCoordinates = faceTextureVCoordinates = null; + } } diff --git a/cache/src/main/java/net/runelite/cache/definitions/ObjectDefinition.java b/cache/src/main/java/net/runelite/cache/definitions/ObjectDefinition.java index b33dd54f08..b7dc1d4744 100644 --- a/cache/src/main/java/net/runelite/cache/definitions/ObjectDefinition.java +++ b/cache/src/main/java/net/runelite/cache/definitions/ObjectDefinition.java @@ -65,7 +65,7 @@ public class ObjectDefinition private int anInt2105 = -1; private int anInt2106 = -1; private int[] configChangeDest; - private boolean aBool2108 = false; + private boolean isRotated = false; private int configId = -1; private int anInt2110 = -1; private boolean aBool2111 = false; @@ -434,14 +434,14 @@ public class ObjectDefinition this.configChangeDest = configChangeDest; } - public boolean isaBool2108() + public boolean isRotated() { - return aBool2108; + return isRotated; } - public void setaBool2108(boolean aBool2108) + public void setIsRotated(boolean isRotated) { - this.aBool2108 = aBool2108; + this.isRotated = isRotated; } public int getConfigId() diff --git a/cache/src/main/java/net/runelite/cache/definitions/loaders/ObjectLoader.java b/cache/src/main/java/net/runelite/cache/definitions/loaders/ObjectLoader.java index c629672214..d10d109fc1 100644 --- a/cache/src/main/java/net/runelite/cache/definitions/loaders/ObjectLoader.java +++ b/cache/src/main/java/net/runelite/cache/definitions/loaders/ObjectLoader.java @@ -199,7 +199,7 @@ public class ObjectLoader } else if (62 == opcode) { - def.setaBool2108(true); + def.setIsRotated(true); } else if (opcode == 64) { diff --git a/cache/src/main/java/net/runelite/cache/models/CircularAngle.java b/cache/src/main/java/net/runelite/cache/models/CircularAngle.java new file mode 100644 index 0000000000..b93f1eec5c --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/models/CircularAngle.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2017, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.cache.models; + +public class CircularAngle +{ + private static final double UNIT = Math.PI / 1024d; // How much of the circle each unit of SINE/COSINE is + + public static final int[] SINE = new int[2048]; // sine angles for each of the 2048 units, * 65536 and stored as an int + public static final int[] COSINE = new int[2048]; // cosine + + static + { + for (int i = 0; i < 2048; ++i) + { + SINE[i] = (int) (65536.0D * Math.sin((double) i * UNIT)); + COSINE[i] = (int) (65536.0D * Math.cos((double) i * UNIT)); + } + } +} diff --git a/model-viewer/src/main/java/net/runelite/modelviewer/LocationKey.java b/model-viewer/src/main/java/net/runelite/modelviewer/LocationKey.java new file mode 100644 index 0000000000..990dc6f3aa --- /dev/null +++ b/model-viewer/src/main/java/net/runelite/modelviewer/LocationKey.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2017, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.modelviewer; + +public class LocationKey +{ + private final int id; + private final int type; + private final int orientation; + + public LocationKey(int id, int type, int orientation) + { + this.id = id; + this.type = type; + this.orientation = orientation; + } + + @Override + public int hashCode() + { + int hash = 5; + hash = 97 * hash + this.id; + hash = 97 * hash + this.type; + hash = 97 * hash + this.orientation; + return hash; + } + + @Override + public boolean equals(Object obj) + { + if (this == obj) + { + return true; + } + if (obj == null) + { + return false; + } + if (getClass() != obj.getClass()) + { + return false; + } + final LocationKey other = (LocationKey) obj; + if (this.id != other.id) + { + return false; + } + if (this.type != other.type) + { + return false; + } + if (this.orientation != other.orientation) + { + return false; + } + return true; + } +} diff --git a/model-viewer/src/main/java/net/runelite/modelviewer/ModelManager.java b/model-viewer/src/main/java/net/runelite/modelviewer/ModelManager.java new file mode 100644 index 0000000000..505edde4d2 --- /dev/null +++ b/model-viewer/src/main/java/net/runelite/modelviewer/ModelManager.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2017, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.modelviewer; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.HashMap; +import java.util.Map; +import net.runelite.cache.definitions.ModelDefinition; +import net.runelite.cache.definitions.ObjectDefinition; +import net.runelite.cache.definitions.loaders.ModelLoader; +import net.runelite.cache.region.Location; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ModelManager +{ + private static final Logger logger = LoggerFactory.getLogger(ModelManager.class); + + private static Map models = new HashMap<>(); + + public static ModelDefinition getModel(int id, ObjectDefinition object, Location location) + { + LocationKey key; + + if (location != null) + { + key = new LocationKey(id, location.getType(), location.getOrientation()); + } + else + { + key = new LocationKey(id, -1, -1); + } + + ModelDefinition md = models.get(key); + if (md != null) + { + return md; + } + + try + { + byte[] b = Files.readAllBytes(new File("models/" + id + ".model").toPath()); + + ModelLoader loader = new ModelLoader(); + md = loader.load(id, b); + + rotate(md, object, location); + + models.put(key, md); + return md; + } + catch (IOException ex) + { + logger.warn(null, ex); + return null; + } + } + + // this logic is from method3697 in 140 + private static void rotate(ModelDefinition md, ObjectDefinition object, Location location) + { + if (object.getObjectTypes() == null) + { + boolean isRotate = object.isRotated(); + + if (location.getType() == 2 && location.getOrientation() > 3) + { + isRotate = !isRotate; + } + + if (isRotate) + { + md.method1493(); + } + } + else + { + boolean isRotate = object.isRotated() ^ location.getOrientation() > 3; + + if (isRotate) + { + md.method1493(); + } + } + + switch (location.getOrientation()) + { + case 1: + md.rotate1(); + break; + case 2: + md.rotate2(); + break; + case 3: + md.rotate3(); + break; + } + } +} diff --git a/model-viewer/src/main/java/net/runelite/modelviewer/ModelViewer.java b/model-viewer/src/main/java/net/runelite/modelviewer/ModelViewer.java index f5cb061cb3..4afb896837 100644 --- a/model-viewer/src/main/java/net/runelite/modelviewer/ModelViewer.java +++ b/model-viewer/src/main/java/net/runelite/modelviewer/ModelViewer.java @@ -27,13 +27,11 @@ package net.runelite.modelviewer; import com.google.gson.Gson; import java.awt.Color; import java.awt.image.BufferedImage; -import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.nio.ByteBuffer; -import java.nio.file.Files; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -45,7 +43,6 @@ import net.runelite.cache.definitions.ObjectDefinition; import net.runelite.cache.definitions.OverlayDefinition; import net.runelite.cache.definitions.TextureDefinition; import net.runelite.cache.definitions.UnderlayDefinition; -import net.runelite.cache.definitions.loaders.ModelLoader; import net.runelite.cache.models.Vector3f; import net.runelite.cache.models.VertexNormal; import net.runelite.cache.region.Location; @@ -78,7 +75,6 @@ public class ModelViewer private static final int NUM_OVERLAYS = 174; private static final int NUM_TEXTURES = 61; private static final int NUM_OBJECTS = 28598; - private static final int NUM_MODELS = 31247; /** * size of a tile in local coordinates @@ -91,7 +87,6 @@ public class ModelViewer private static Map textures = new HashMap<>(); private static ObjectDefinition[] objects = new ObjectDefinition[NUM_OBJECTS]; - private static ModelDefinition[] models = new ModelDefinition[NUM_MODELS]; public static void main(String[] args) throws Exception { @@ -124,7 +119,7 @@ public class ModelViewer // render model String model = cmd.getOptionValue("model"); - ModelDefinition md = getModel(Integer.parseInt(model)); + ModelDefinition md = ModelManager.getModel(Integer.parseInt(model), null, null); models.add(md); } if (cmd.hasOption("npc")) @@ -138,7 +133,7 @@ public class ModelViewer for (int model : npcdef.models) { - ModelDefinition md = getModel(model); + ModelDefinition md = ModelManager.getModel(model, null, null); models.add(md); } } @@ -153,7 +148,7 @@ public class ModelViewer for (int model : objdef.getObjectModels()) { - ModelDefinition md = getModel(model); + ModelDefinition md = ModelManager.getModel(model, null, null); models.add(md); } } @@ -301,6 +296,9 @@ public class ModelViewer Texture texture = getTexture(textureId); assert texture != null; + if (md.faceTextureUCoordinates == null || md.faceTextureVCoordinates == null) + md.computeTextureUVCoordinates(); + u = md.faceTextureUCoordinates[i]; v = md.faceTextureVCoordinates[i]; @@ -529,7 +527,6 @@ public class ModelViewer int regionY = objectPos.getY() - region.getBaseY(); int height = -region.getTileHeight(objectPos.getZ(), regionX, regionY) / HEIGHT_MOD; - //byte overlayRotation = region.getOverlayRotation(objectPos.getZ(), regionX, regionY); GL11.glMatrixMode(GL11.GL_MODELVIEW); // TILE_SCALE/2 to draw the object from the center of the tile it is on @@ -537,14 +534,11 @@ public class ModelViewer for (int i = 0; i < object.getObjectModels().length; ++i) { - ModelDefinition md = getModel(object.getObjectModels()[i]); + ModelDefinition md = ModelManager.getModel(object.getObjectModels()[i], object, location); - if (object.getObjectTypes() != null) + if (object.getObjectTypes() != null && object.getObjectTypes()[i] != location.getType()) { - if (object.getObjectTypes()[i] != location.getType()) - { - continue; - } + continue; } drawModel(md, object.getRecolorToFind(), object.getRecolorToReplace()); @@ -606,31 +600,6 @@ public class ModelViewer } } - private static ModelDefinition getModel(int id) - { - ModelDefinition md = models[id]; - if (md != null) - { - return md; - } - - try - { - byte[] b = Files.readAllBytes(new File("models/" + id + ".model").toPath()); - - ModelLoader loader = new ModelLoader(); - md = loader.load(id, b); - - models[id] = md; - return md; - } - catch (IOException ex) - { - logger.warn(null, ex); - return null; - } - } - private static Texture getTexture(int id) { Texture texture = textures.get(id);