-Fixed objects of variable width and length from being positioned incorrectly on the map.

-Renamed LocationKey to ModelKey and added another field so that cached values are correct for objects using the same models.
-Implemented shading to the scene.
-Implement full SceneTilePaint with variable colors and textures.
-Implement textures while rendering SceneTileModel
-Enable maps to be loaded by their region id instead of just their coordinates.
-Implement full object model creation (replacement colors, replacement textures, resizing, translation)
-Added two new methods to ModelDefinition used in object model creation.
This commit is contained in:
Qatell
2018-07-08 10:35:06 +08:00
committed by Adam
parent 86754bccbe
commit 49ace3f7c7
6 changed files with 361 additions and 125 deletions

View File

@@ -27,9 +27,10 @@ package net.runelite.modelviewer;
import lombok.Value;
@Value
public class LocationKey
public class ModelKey
{
private final int id;
private final int modelId;
private final int defId;
private final int type;
private final int orientation;
}

View File

@@ -27,6 +27,7 @@ package net.runelite.modelviewer;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
import net.runelite.cache.IndexType;
import net.runelite.cache.definitions.ModelDefinition;
import net.runelite.cache.definitions.ObjectDefinition;
@@ -44,29 +45,100 @@ public class ModelManager
private static final Logger logger = LoggerFactory.getLogger(ModelManager.class);
private final Store store;
private final Map<LocationKey, ModelDefinition> models = new HashMap<>();
private final Map<ModelKey, ModelDefinition> models = new HashMap<>();
private final ModelLoader loader = new ModelLoader();
public ModelManager(Store store)
{
this.store = store;
}
public ModelDefinition getModel(int id)
{
return this.getModel(new ModelKey(id, -1, -1, -1), null);
}
public ModelDefinition getModel(int id, ObjectDefinition object, Location location)
{
LocationKey key;
Integer rot = null;
if (location != null)
int type = location.getType();
int rot = location.getOrientation();
return this.getModel(new ModelKey(id, object.getId(), type, rot), md ->
{
rot = location.getOrientation();
key = new LocationKey(id, location.getType(), rot);
}
else
{
key = new LocationKey(id, -1, -1);
}
// this logic is from method3697 in 140
if (object.getObjectTypes() == null)
{
boolean isRotate = object.isRotated();
if (type == 2 && rot > 3)
{
isRotate = !isRotate;
}
if (isRotate)
{
md.method1493();
}
}
else
{
boolean isRotate = object.isRotated() ^ rot > 3;
if (isRotate)
{
md.method1493();
}
}
if (type == 4 && rot > 3)
{
md.rotate(256);
md.move(45, 0, -45);
}
switch (rot & 3)
{
case 1:
md.rotate1();
break;
case 2:
md.rotate2();
break;
case 3:
md.rotate3();
break;
}
short[] recolorToFind = object.getRecolorToFind();
if (recolorToFind != null)
{
short[] recolorToReplace = object.getRecolorToReplace();
for (int i = 0; i < recolorToFind.length; ++i)
{
md.recolor(recolorToFind[i], recolorToReplace[i]);
}
}
short[] retextureToFind = object.getRetextureToFind();
if (retextureToFind != null)
{
short[] textureToReplace = object.getTextureToReplace();
for (int i = 0; i < retextureToFind.length; ++i)
{
md.retexture(retextureToFind[i], textureToReplace[i]);
}
}
if (object.getModelSizeX() != 128 || object.getModelSizeHeight() != 128 || object.getModelSizeY() != 128)
{
md.resize(object.getModelSizeX(), object.getModelSizeHeight(), object.getModelSizeY());
}
if (object.getOffsetX() != 0 || object.getOffsetHeight() != 0 || object.getOffsetY() != 0)
{
md.move((short) object.getOffsetX(), (short) object.getOffsetHeight(), (short) object.getOffsetY());
}
});
}
private ModelDefinition getModel(ModelKey key, Consumer<ModelDefinition> loadConsumer)
{
ModelDefinition md = models.get(key);
if (md != null)
{
@@ -76,7 +148,7 @@ public class ModelManager
Storage storage = store.getStorage();
Index index = store.getIndex(IndexType.MODELS);
Archive modelArchive = index.getArchive(id);
Archive modelArchive = index.getArchive(key.getModelId());
byte[] contents;
try
{
@@ -87,57 +159,14 @@ public class ModelManager
throw new RuntimeException(e);
}
ModelLoader loader = new ModelLoader();
md = loader.load(modelArchive.getArchiveId(), contents);
if (object != null && location != null)
{
rotate(md, object, location, rot);
md.computeNormals();
}
models.put(key, md);
return md;
}
// this logic is from method3697 in 140
private static void rotate(ModelDefinition md, ObjectDefinition object, Location location, int rot)
{
if (object.getObjectTypes() == null)
if (loadConsumer != null)
{
boolean isRotate = object.isRotated();
if (location.getType() == 2 && rot > 3)
{
isRotate = !isRotate;
}
if (isRotate)
{
md.method1493();
}
}
else
{
boolean isRotate = object.isRotated() ^ rot > 3;
if (isRotate)
{
md.method1493();
}
}
switch (rot & 3)
{
case 1:
md.rotate1();
break;
case 2:
md.rotate2();
break;
case 3:
md.rotate3();
break;
loadConsumer.accept(md);
}
md.computeNormals();
models.put(key, md);
return md;
}
}

View File

@@ -67,6 +67,7 @@ import net.runelite.cache.fs.FSFile;
import net.runelite.cache.fs.Index;
import net.runelite.cache.fs.Storage;
import net.runelite.cache.fs.Store;
import net.runelite.cache.item.ColorPalette;
import net.runelite.cache.models.Vector3f;
import net.runelite.cache.models.VertexNormal;
import net.runelite.cache.region.Location;
@@ -99,12 +100,11 @@ public class ModelViewer
* size of a tile in local coordinates
*/
private static final int TILE_SCALE = 128;
private static final int[] palette = new ColorPalette(0.6, 0, 512).getColorPalette();//0.6, 0.7, 0.8, 0.9
private static ObjectManager objectManager;
private static TextureManager textureManager;
private static SpriteManager spriteManager;
private static ModelManager modelManager;
private static Map<Integer, Texture> textures = new HashMap<>();
private static Map<Integer, SequenceDefinition> seqs = new HashMap<>();
private static Multimap<Integer, FrameDefinition> frames = HashMultimap.create();
@@ -174,7 +174,7 @@ public class ModelViewer
// render model
String model = cmd.getOptionValue("model");
ModelDefinition md = modelManager.getModel(Integer.parseInt(model), null, null);
ModelDefinition md = modelManager.getModel(Integer.parseInt(model));
models.add(md);
}
if (cmd.hasOption("npc"))
@@ -185,7 +185,11 @@ public class ModelViewer
for (int model : npcdef.models)
{
ModelDefinition md = modelManager.getModel(model, null, null);
ModelDefinition md = modelManager.getModel(model);
for (int i = 0; i < npcdef.recolorToFind.length; i++)
{
md.recolor(npcdef.recolorToFind[i], npcdef.recolorToReplace[i]);
}
models.add(md);
}
}
@@ -197,16 +201,25 @@ public class ModelViewer
for (int model : objdef.getObjectModels())
{
ModelDefinition md = modelManager.getModel(model, null, null);
models.add(md);
models.add(modelManager.getModel(model, objdef, null));
}
}
if (cmd.hasOption("map"))
{
String map = cmd.getOptionValue("map");
String[] s = map.split(",");
int x = Integer.parseInt(s[0]), y = Integer.parseInt(s[1]);
int x, y;
if (s.length == 1)
{
int regionId = Integer.parseInt(s[0]);
x = regionId >> 8;
y = regionId & 0xFF;
}
else
{
x = Integer.parseInt(s[0]);
y = Integer.parseInt(s[1]);
}
XteaKeyManager keyManager = new XteaKeyManager();
keyManager.loadKeys();
@@ -244,7 +257,7 @@ public class ModelViewer
KitDefinition kit = KitManager.getKit(kitId);
for (int model : kit.modelIds)
{
ModelDefinition md = modelManager.getModel(model, null, null);
ModelDefinition md = modelManager.getModel(model);
models.add(md);
}
}
@@ -283,7 +296,7 @@ public class ModelViewer
if (region != null)
{
scene = new Scene(underlayManager, overlayManager);
scene.loadRegion(region);
scene.loadRegion(region, objectManager);
}
SequenceDefinition sequenceDefinition = null;
@@ -341,19 +354,7 @@ public class ModelViewer
for (ModelDefinition def : models)
{
short[] recolourToFind = null, recolourToReplace = null;
if (npcdef != null)
{
recolourToFind = npcdef.recolorToFind;
recolourToReplace = npcdef.recolorToReplace;
}
if (objdef != null)
{
recolourToFind = objdef.getRecolorToFind();
recolourToReplace = objdef.getRecolorToReplace();
}
drawModel(def, recolourToFind, recolourToReplace);
drawModel(def);
}
if (region != null)
@@ -374,7 +375,7 @@ public class ModelViewer
Display.destroy();
}
private static void drawModel(ModelDefinition md, short[] recolourToFind, short[] recolourToReplace)
private static void drawModel(ModelDefinition md)
{
for (int i = 0; i < md.faceCount; ++i)
{
@@ -456,22 +457,7 @@ public class ModelViewer
}
else
{
short hsb = md.faceColors[i];
// Check recolor
if (recolourToFind != null)
{
for (int j = 0; j < recolourToFind.length; ++j)
{
if (recolourToFind[j] == hsb)
{
hsb = recolourToReplace[j];
}
}
}
int rgb = RS2HSB_to_RGB(hsb);
color = new Color(rgb);
color = new Color(getPaletteColor(md.faceColors[i]));
}
// convert to range of 0-1
@@ -525,8 +511,15 @@ public class ModelViewer
{
for (int y = 0; y < Region.Y; ++y)
{
drawSceneTileModel(region, x, y, z, sceneTileModels[x][y]);
drawSceneTilePaint(region, x, y, z, sceneTilePaint[x][y]);
SceneTilePaint paint = sceneTilePaint[x][y];
if (paint != null)
{
drawSceneTilePaint(region, x, y, z, paint);
}
else
{
drawSceneTileModel(region, x, y, z, sceneTileModels[x][y]);
}
}
}
}
@@ -543,11 +536,14 @@ public class ModelViewer
int glTexture = -1;
Color color;
Color swColor;
Color seColor;
Color neColor;
Color nwColor;
if (sceneTilePaint.texture > -1)
{
color = Color.WHITE;
swColor = seColor = neColor = nwColor = Color.WHITE;
Texture texture = getTexture(sceneTilePaint.texture);
glTexture = texture.getOpenglId();
@@ -558,7 +554,14 @@ public class ModelViewer
}
else
{
color = new Color(RS2HSB_to_RGB(sceneTilePaint.color));
if (sceneTilePaint.swColor == 12345678)
{
return;
}
swColor = new Color(getPaletteColor(sceneTilePaint.swColor));
seColor = new Color(getPaletteColor(sceneTilePaint.seColor));
neColor = new Color(getPaletteColor(sceneTilePaint.neColor));
nwColor = new Color(getPaletteColor(sceneTilePaint.nwColor));
}
@@ -567,40 +570,45 @@ public class ModelViewer
int x = regionX * TILE_SCALE;
int y = regionY * TILE_SCALE;
GL11.glColor3f((float) color.getRed() / 255f, (float) color.getGreen() / 255f, (float) color.getBlue() / 255f);
int z1 = -region.getTileHeight(z, regionX, regionY);
int z2 = regionX + 1 < Region.X ? -region.getTileHeight(z, regionX + 1, regionY) : z1;
int z3 = regionY + 1 < Region.Y ? -region.getTileHeight(z, regionX, regionY + 1) : z1;
int z4 = regionX + 1 < Region.X && regionY + 1 < Region.Y ? -region.getTileHeight(z, regionX + 1, regionY + 1) : z1;
// triangle 1
glColor3f(swColor);
if (glTexture > -1)
{
GL11.glTexCoord2f(0, 0);
}
GL11.glVertex3i(x, z1, -y);
glColor3f(seColor);
if (glTexture > -1)
{
GL11.glTexCoord2f(1, 0);
}
GL11.glVertex3i(x + TILE_SCALE, z2, -y);
glColor3f(nwColor);
if (glTexture > -1)
{
GL11.glTexCoord2f(0, 1);
}
GL11.glVertex3i(x, z3, -(y + TILE_SCALE));
// triangle 2
if (glTexture > -1)
{
GL11.glTexCoord2f(0, 1);
}
GL11.glVertex3i(x, z3, -(y + TILE_SCALE));
glColor3f(seColor);
if (glTexture > -1)
{
GL11.glTexCoord2f(1, 0);
}
GL11.glVertex3i(x + TILE_SCALE, z2, -y);
glColor3f(neColor);
if (glTexture > -1)
{
GL11.glTexCoord2f(1, 1);
@@ -643,21 +651,51 @@ public class ModelViewer
int colorA = sceneTileModel.triangleColorA[i];
int colorB = sceneTileModel.triangleColorB[i];
int colorC = sceneTileModel.triangleColorC[i];
int textureId = sceneTileModel.triangleTextureId == null ? -1 : sceneTileModel.triangleTextureId[i];
Color color = null;
Color colorAc, colorBc, colorCc;
int glTexture = -1;
if (textureId != -1)
{
colorAc = colorBc = colorCc = Color.WHITE;
Texture texture = getTexture(textureId);
glTexture = texture.getOpenglId();
assert glTexture > -1;
color = new Color(RS2HSB_to_RGB(colorA));
GL11.glEnable(GL11.GL_TEXTURE_2D);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, glTexture);
}
else
{
if (colorA == 12345678)
{
return;
}
colorAc = new Color(getPaletteColor(colorA));
colorBc = new Color(getPaletteColor(colorB));
colorCc = new Color(getPaletteColor(colorC));
}
GL11.glBegin(GL11.GL_TRIANGLES);
if (color != null)
glColor3f(colorAc);
if (glTexture > -1)
{
GL11.glColor3f((float) color.getRed() / 255f, (float) color.getGreen() / 255f, (float) color.getBlue() / 255f);
GL11.glTexCoord2f(0, 0);
}
GL11.glVertex3i(vertexAx, -vertexAy, -vertexAz);
glColor3f(colorBc);
if (glTexture > -1)
{
GL11.glTexCoord2f(1, 0);
}
GL11.glVertex3i(vertexBx, -vertexBy, -vertexBz);
glColor3f(colorCc);
if (glTexture > -1)
{
GL11.glTexCoord2f(0, 1);
}
GL11.glVertex3i(vertexCx, -vertexCy, -vertexCz);
GL11.glEnd();
@@ -669,6 +707,11 @@ public class ModelViewer
}
}
private static void glColor3f(Color color)
{
GL11.glColor3f((float) color.getRed() / 255f, (float) color.getGreen() / 255f, (float) color.getBlue() / 255f);
}
private static void drawLocations(Region region)
{
for (Location location : region.getLocations())
@@ -682,14 +725,41 @@ public class ModelViewer
}
Position objectPos = location.getPosition();
int width;
int length;
if (location.getOrientation() != 1 && location.getOrientation() != 3)
{
width = object.getSizeX();
length = object.getSizeY();
}
else
{
width = object.getSizeY();
length = object.getSizeX();
}
int regionX = objectPos.getX() - region.getBaseX();
int regionY = objectPos.getY() - region.getBaseY();
int height = -region.getTileHeight(objectPos.getZ(), regionX, regionY);
int height = Integer.MIN_VALUE;
for (int xOff = 0; xOff < width; xOff++)
{
for (int yOff = 0; yOff < length; yOff++)
{
if (regionX + xOff < Region.X && regionY + yOff < Region.Y)
{
height = Math.max(height, -region.getTileHeight(objectPos.getZ(), regionX + xOff, regionY + yOff));
}
}
}
GL11.glMatrixMode(GL11.GL_MODELVIEW);
// TILE_SCALE/2 to draw the object from the center of the tile it is on
GL11.glTranslatef(regionX * TILE_SCALE + (TILE_SCALE / 2), height + (location.getPosition().getZ() * 0), -regionY * TILE_SCALE - (TILE_SCALE / 2));
GL11.glTranslatef(
(regionX * TILE_SCALE) + ((width * TILE_SCALE) / 2),
height,
(-regionY * TILE_SCALE) - ((length * TILE_SCALE) / 2)
);
for (int i = 0; i < object.getObjectModels().length; ++i)
{
@@ -705,10 +775,14 @@ public class ModelViewer
continue;
}
drawModel(md, object.getRecolorToFind(), object.getRecolorToReplace());
drawModel(md);
}
GL11.glTranslatef(-regionX * TILE_SCALE - (TILE_SCALE / 2), -(height + (location.getPosition().getZ() * 0)), regionY * TILE_SCALE + (TILE_SCALE / 2));
GL11.glTranslatef(
(-regionX * TILE_SCALE) - ((width * TILE_SCALE) / 2),
-height,
(regionY * TILE_SCALE) + ((length * TILE_SCALE) / 2)
);
GL11.glPopMatrix();
}
}
@@ -825,6 +899,11 @@ public class ModelViewer
}
}
public static int getPaletteColor(int hsb)
{
return palette[hsb & 0xFFFF];
}
// found these two functions here https://www.rune-server.org/runescape-development/rs2-client/tools/589900-rs2-hsb-color-picker.html
public static int RGB_to_RS2HSB(int red, int green, int blue)
{
@@ -843,6 +922,21 @@ public class ModelViewer
int decode_hue = (RS2HSB >> 10) & 0x3f;
int decode_saturation = (RS2HSB >> 7) & 0x07;
int decode_brightness = (RS2HSB & 0x7f);
return Color.HSBtoRGB((float) decode_hue / 63, (float) decode_saturation / 7, (float) decode_brightness / 127);
int rgb = Color.HSBtoRGB((float) decode_hue / 63, (float) decode_saturation / 7, (float) decode_brightness / 127);
return adjustRGB(rgb & 0xFFFFFF, 0.6);
}
private static int adjustRGB(int rgb, double brightness)
{
double rp = (double) (rgb >> 16) / 256.0D;
double gp = (double) (rgb >> 8 & 255) / 256.0D;
double bp = (double) (rgb & 255) / 256.0D;
rp = Math.pow(rp, brightness);
gp = Math.pow(gp, brightness);
bp = Math.pow(bp, brightness);
int r = (int) (rp * 256.0D);
int g = (int) (gp * 256.0D);
int b = (int) (bp * 256.0D);
return b + (g << 8) + (r << 16);
}
}

View File

@@ -26,11 +26,14 @@ package net.runelite.modelviewer;
import lombok.AllArgsConstructor;
import lombok.Getter;
import net.runelite.cache.ObjectManager;
import net.runelite.cache.definitions.ObjectDefinition;
import net.runelite.cache.definitions.OverlayDefinition;
import net.runelite.cache.definitions.UnderlayDefinition;
import net.runelite.cache.definitions.providers.OverlayProvider;
import net.runelite.cache.definitions.providers.UnderlayProvider;
import net.runelite.cache.item.ColorPalette;
import net.runelite.cache.region.Location;
import net.runelite.cache.region.Region;
@AllArgsConstructor
@@ -61,8 +64,102 @@ public class Scene
@Getter
private final SceneTilePaint[][][] sceneTilePaint = new SceneTilePaint[Region.Z][Region.X][Region.Y];
public void loadRegion(Region region)
private byte[][] createShadows(Region region, ObjectManager manager)
{
byte[][] shadow = new byte[Region.X + 8][Region.Y + 8];
for (Location location : region.getLocations())
{
int id = location.getId();
ObjectDefinition object = manager.getObject(id);
if (object == null || object.getObjectModels() == null)
{
continue;
}
if (!object.isABool2097())
{
continue;
}
int regionX = location.getPosition().getX() - region.getBaseX();
int regionY = location.getPosition().getY() - region.getBaseY();
if (location.getType() == 0)
{
if (location.getOrientation() == 0)
{
shadow[regionX][regionY] = 50;
shadow[regionX][regionY + 1] = 50;
}
else if (location.getOrientation() == 1)
{
shadow[regionX][regionY + 1] = 50;
shadow[regionX + 1][regionY + 1] = 50;
}
else if (location.getOrientation() == 2)
{
shadow[regionX + 1][regionY] = 50;
shadow[regionX + 1][regionY + 1] = 50;
}
else if (location.getOrientation() == 3)
{
shadow[regionX][regionY] = 50;
shadow[regionX + 1][regionY] = 50;
}
}
else if (location.getType() == 1 || location.getType() == 3)
{
if (location.getOrientation() == 0)
{
shadow[regionX][regionY + 1] = 50;
}
else if (location.getOrientation() == 1)
{
shadow[regionX + 1][regionY + 1] = 50;
}
else if (location.getOrientation() == 2)
{
shadow[regionX + 1][regionY] = 50;
}
else if (location.getOrientation() == 3)
{
shadow[regionX][regionY] = 50;
}
}
else if (location.getType() == 10 || location.getType() == 11)
{
int width;
int length;
if (location.getOrientation() != 1 && location.getOrientation() != 3)
{
width = object.getSizeX();
length = object.getSizeY();
}
else
{
width = object.getSizeY();
length = object.getSizeX();
}
int var23 = 15;
for (int x = 0; x <= width; x++)
{
int xOff = x + regionX;
for (int y = 0; y <= length; y++)
{
int yOff = y + regionY;
if (var23 > shadow[xOff][yOff])
{
shadow[xOff][yOff] = (byte) var23;
}
}
}
}
}
return shadow;
}
public void loadRegion(Region region, ObjectManager manager)
{
byte[][] shadow = createShadows(region, manager);
int[][] field3834 = new int[Region.X][Region.Y];
int var11 = (int) Math.sqrt(5100.0D);
int var63 = var11 * 768 >> 8;
@@ -80,8 +177,7 @@ public class Scene
int var50 = 65536 / var17;
int var20 = (dy << 8) / var17;
int var21 = (var20 * -50 + var18 * -50 + var50 * -10) / var63 + 96;
// int var22 = (var68[y - 1][x] >> 2) + (var68[y][x - 1] >> 2) + (var68[y + 1][x] >> 3) + (var68[y][x + 1] >> 3) + (var68[y][x] >> 1);
int var22 = 0;
int var22 = (shadow[y - 1][x] >> 2) + (shadow[y][x - 1] >> 2) + (shadow[y + 1][x] >> 3) + (shadow[y][x + 1] >> 3) + (shadow[y][x] >> 1);
field3834[y][x] = var21 - var22;
}
}
@@ -263,12 +359,12 @@ public class Scene
{
if (shape == 0)
{
SceneTilePaint sceneTilePaint = new SceneTilePaint(underlayColor, texture);
SceneTilePaint sceneTilePaint = new SceneTilePaint(underlayColor, underlayColorX1, underlayColorX1Y1, underlayColorY1, -1, underlayColorRgb, false);
this.sceneTilePaint[z][x][y] = sceneTilePaint;
}
else if (shape == 1)
{
SceneTilePaint sceneTilePaint = new SceneTilePaint(overlayColor, texture);
SceneTilePaint sceneTilePaint = new SceneTilePaint(overlayColor, overlayColorX1, overlayColorX1Y1, overlayColorY1, texture, underlayColorRgb, tileHeightX1 == tileHeight && tileHeight == tileHeightX1Y1 && tileHeightY1 == tileHeight);
this.sceneTilePaint[z][x][y] = sceneTilePaint;
}
else

View File

@@ -29,6 +29,11 @@ import lombok.AllArgsConstructor;
@AllArgsConstructor
public class SceneTilePaint
{
final int color;
final int swColor;
final int seColor;
final int neColor;
final int nwColor;
final int texture;
final int rgb;
final boolean flatShade;
}