726 lines
21 KiB
Java
726 lines
21 KiB
Java
/*
|
|
* Copyright (c) 2016-2018, Adam <Adam@sigterm.info>
|
|
* 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 com.google.gson.Gson;
|
|
import java.awt.Color;
|
|
import java.io.File;
|
|
import java.io.FileInputStream;
|
|
import java.io.InputStreamReader;
|
|
import java.nio.ByteBuffer;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import net.runelite.cache.IndexType;
|
|
import net.runelite.cache.ObjectManager;
|
|
import net.runelite.cache.OverlayManager;
|
|
import net.runelite.cache.SpriteManager;
|
|
import net.runelite.cache.TextureManager;
|
|
import net.runelite.cache.UnderlayManager;
|
|
import net.runelite.cache.definitions.KitDefinition;
|
|
import net.runelite.cache.definitions.LocationsDefinition;
|
|
import net.runelite.cache.definitions.MapDefinition;
|
|
import net.runelite.cache.definitions.ModelDefinition;
|
|
import net.runelite.cache.definitions.NpcDefinition;
|
|
import net.runelite.cache.definitions.ObjectDefinition;
|
|
import net.runelite.cache.definitions.SpriteDefinition;
|
|
import net.runelite.cache.definitions.TextureDefinition;
|
|
import net.runelite.cache.definitions.loaders.LocationsLoader;
|
|
import net.runelite.cache.definitions.loaders.MapLoader;
|
|
import net.runelite.cache.fs.Archive;
|
|
import net.runelite.cache.fs.Index;
|
|
import net.runelite.cache.fs.Storage;
|
|
import net.runelite.cache.fs.Store;
|
|
import net.runelite.cache.models.Vector3f;
|
|
import net.runelite.cache.models.VertexNormal;
|
|
import net.runelite.cache.region.Location;
|
|
import net.runelite.cache.region.Position;
|
|
import net.runelite.cache.region.Region;
|
|
import net.runelite.cache.util.XteaKeyManager;
|
|
import org.apache.commons.cli.CommandLine;
|
|
import org.apache.commons.cli.CommandLineParser;
|
|
import org.apache.commons.cli.DefaultParser;
|
|
import org.apache.commons.cli.Options;
|
|
import org.lwjgl.opengl.Display;
|
|
import org.lwjgl.opengl.DisplayMode;
|
|
import org.lwjgl.opengl.GL11;
|
|
import static org.lwjgl.opengl.GL11.GL_NEAREST;
|
|
import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D;
|
|
import static org.lwjgl.opengl.GL11.GL_TEXTURE_MAG_FILTER;
|
|
import static org.lwjgl.opengl.GL11.GL_TEXTURE_MIN_FILTER;
|
|
import static org.lwjgl.opengl.GL11.GL_TEXTURE_WRAP_S;
|
|
import static org.lwjgl.opengl.GL11.GL_TEXTURE_WRAP_T;
|
|
import static org.lwjgl.opengl.GL11.glTexParameteri;
|
|
import static org.lwjgl.opengl.GL12.GL_CLAMP_TO_EDGE;
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
public class ModelViewer
|
|
{
|
|
private static final Logger logger = LoggerFactory.getLogger(ModelViewer.class);
|
|
|
|
/**
|
|
* size of a tile in local coordinates
|
|
*/
|
|
private static final int TILE_SCALE = 128;
|
|
private static final int HEIGHT_MOD = 4;
|
|
|
|
private static ObjectManager objectManager;
|
|
private static TextureManager textureManager;
|
|
private static SpriteManager spriteManager;
|
|
|
|
private static Map<Integer, Texture> textures = new HashMap<>();
|
|
|
|
public static void main(String[] args) throws Exception
|
|
{
|
|
Options options = new Options();
|
|
|
|
options.addOption(null, "store", true, "store directory");
|
|
|
|
options.addOption(null, "npcdir", true, "npc directory");
|
|
options.addOption(null, "mapdir", true, "maps directory");
|
|
options.addOption(null, "objectdir", true, "objects directory");
|
|
|
|
options.addOption(null, "npc", true, "npc to render");
|
|
options.addOption(null, "object", true, "object to render");
|
|
options.addOption(null, "model", true, "model to render");
|
|
options.addOption(null, "map", true, "map region to render");
|
|
options.addOption(null, "kits", true, "kits to render");
|
|
|
|
CommandLineParser parser = new DefaultParser();
|
|
CommandLine cmd = parser.parse(options, args);
|
|
|
|
String npcdir = cmd.getOptionValue("npcdir");
|
|
String mapdir = cmd.getOptionValue("mapdir");
|
|
String objectdir = cmd.getOptionValue("objectdir");
|
|
|
|
NpcDefinition npcdef = null;
|
|
ObjectDefinition objdef = null;
|
|
Store store = null;
|
|
UnderlayManager underlayManager = null;
|
|
OverlayManager overlayManager = null;
|
|
|
|
List<ModelDefinition> models = new ArrayList<>();
|
|
Region region = null;
|
|
|
|
if (cmd.hasOption("store"))
|
|
{
|
|
store = new Store(new File(cmd.getOptionValue("store")));
|
|
store.load();
|
|
|
|
underlayManager = new UnderlayManager(store);
|
|
underlayManager.load();
|
|
|
|
overlayManager = new OverlayManager(store);
|
|
overlayManager.load();
|
|
|
|
objectManager = new ObjectManager(store);
|
|
objectManager.load();
|
|
|
|
textureManager = new TextureManager(store);
|
|
textureManager.load();
|
|
|
|
spriteManager = new SpriteManager(store);
|
|
spriteManager.load();
|
|
}
|
|
if (cmd.hasOption("model"))
|
|
{
|
|
// render model
|
|
String model = cmd.getOptionValue("model");
|
|
|
|
ModelDefinition md = ModelManager.getModel(Integer.parseInt(model), null, null);
|
|
models.add(md);
|
|
}
|
|
if (cmd.hasOption("npc"))
|
|
{
|
|
String npc = cmd.getOptionValue("npc");
|
|
|
|
try (FileInputStream fin = new FileInputStream(npcdir + "/" + npc + ".json"))
|
|
{
|
|
npcdef = new Gson().fromJson(new InputStreamReader(fin), NpcDefinition.class);
|
|
}
|
|
|
|
for (int model : npcdef.models)
|
|
{
|
|
ModelDefinition md = ModelManager.getModel(model, null, null);
|
|
models.add(md);
|
|
}
|
|
}
|
|
if (cmd.hasOption("object"))
|
|
{
|
|
String obj = cmd.getOptionValue("object");
|
|
|
|
try (FileInputStream fin = new FileInputStream(objectdir + "/" + obj + ".json"))
|
|
{
|
|
objdef = new Gson().fromJson(new InputStreamReader(fin), ObjectDefinition.class);
|
|
}
|
|
|
|
for (int model : objdef.getObjectModels())
|
|
{
|
|
ModelDefinition md = ModelManager.getModel(model, null, null);
|
|
models.add(md);
|
|
}
|
|
}
|
|
if (cmd.hasOption("map"))
|
|
{
|
|
String map = cmd.getOptionValue("map");
|
|
String[] s = map.split(",");
|
|
|
|
int x = Integer.parseInt(s[0]), y = Integer.parseInt(s[1]);
|
|
|
|
XteaKeyManager keyManager = new XteaKeyManager();
|
|
keyManager.loadKeys();
|
|
|
|
int[] keys = keyManager.getKeys(x << 8 | y);
|
|
|
|
Storage storage = store.getStorage();
|
|
Index index = store.getIndex(IndexType.MAPS);
|
|
|
|
Archive mapArchive = index.findArchiveByName("m" + x + "_" + y);
|
|
Archive locationsArchive = index.findArchiveByName("l" + x + "_" + y);
|
|
|
|
region = new Region(x, y);
|
|
|
|
byte[] mapData = mapArchive.decompress(storage.loadArchive(mapArchive));
|
|
MapLoader mapLoader = new MapLoader();
|
|
MapDefinition mapDef = mapLoader.load(x, y, mapData);
|
|
region.loadTerrain(mapDef);
|
|
|
|
if (keys != null)
|
|
{
|
|
byte[] locationData = locationsArchive.decompress(storage.loadArchive(locationsArchive), keys);
|
|
LocationsLoader locationsLoader = new LocationsLoader();
|
|
LocationsDefinition locDef = locationsLoader.load(x, y, locationData);
|
|
region.loadLocations(locDef);
|
|
}
|
|
}
|
|
if (cmd.hasOption("kits"))
|
|
{
|
|
String kits = cmd.getOptionValue("kits");
|
|
Integer[] kitIds = Arrays.stream(kits.split(",")).map(s -> Integer.parseInt(s)).toArray(Integer[]::new);
|
|
|
|
for (int kitId : kitIds)
|
|
{
|
|
KitDefinition kit = KitManager.getKit(kitId);
|
|
for (int model : kit.modelIds)
|
|
{
|
|
ModelDefinition md = ModelManager.getModel(model, null, null);
|
|
models.add(md);
|
|
}
|
|
}
|
|
}
|
|
|
|
Display.setDisplayMode(new DisplayMode(800, 600));
|
|
Display.setTitle("Model Viewer");
|
|
Display.setInitialBackground((float) Color.gray.getRed() / 255f, (float) Color.gray.getGreen() / 255f, (float) Color.gray.getBlue() / 255f);
|
|
Display.create();
|
|
|
|
GL11.glMatrixMode(GL11.GL_PROJECTION);
|
|
GL11.glLoadIdentity();
|
|
double aspect = 1;
|
|
double near = 1; // near should be chosen as far into the scene as possible
|
|
double far = 10000;
|
|
double fov = 1; // 1 gives you a 90° field of view. It's tan(fov_angle)/2.
|
|
GL11.glFrustum(-aspect * near * fov, aspect * near * fov, -fov, fov, near, far);
|
|
GL11.glPopMatrix();
|
|
|
|
GL11.glEnable(GL11.GL_DEPTH_TEST);
|
|
|
|
GL11.glCullFace(GL11.GL_BACK);
|
|
GL11.glEnable(GL11.GL_CULL_FACE);
|
|
|
|
GL11.glEnable(GL11.GL_BLEND);
|
|
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
long last = 0;
|
|
|
|
Camera camera = new Camera();
|
|
Scene scene = new Scene(underlayManager, overlayManager);
|
|
scene.loadRegion(region);
|
|
|
|
while (!Display.isCloseRequested())
|
|
{
|
|
// Clear the screen and depth buffer
|
|
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
|
|
|
|
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);
|
|
}
|
|
|
|
drawScene(region, scene);
|
|
//drawRegion(region);
|
|
|
|
Display.update();
|
|
Display.sync(20); // fps
|
|
|
|
long delta = System.currentTimeMillis() - last;
|
|
last = System.currentTimeMillis();
|
|
|
|
camera.acceptInput(delta);
|
|
camera.apply();
|
|
}
|
|
|
|
Display.destroy();
|
|
}
|
|
|
|
private static void drawModel(ModelDefinition md, short[] recolourToFind, short[] recolourToReplace)
|
|
{
|
|
for (int i = 0; i < md.faceCount; ++i)
|
|
{
|
|
if (md.faceRenderTypes != null)
|
|
{
|
|
byte faceRenderType = md.faceRenderTypes[i];
|
|
|
|
if ((faceRenderType & 2) != 0)
|
|
{
|
|
continue; // what is this?
|
|
}
|
|
}
|
|
|
|
int vertexA = md.faceVertexIndices1[i];
|
|
int vertexB = md.faceVertexIndices2[i];
|
|
int vertexC = md.faceVertexIndices3[i];
|
|
|
|
VertexNormal normalVertexA = md.vertexNormals[vertexA];
|
|
VertexNormal normalVertexB = md.vertexNormals[vertexB];
|
|
VertexNormal normalVertexC = md.vertexNormals[vertexC];
|
|
|
|
Vector3f nA = normalVertexA.normalize();
|
|
Vector3f nB = normalVertexB.normalize();
|
|
Vector3f nC = normalVertexC.normalize();
|
|
|
|
// Invert y
|
|
nA.y = -nA.y;
|
|
nB.y = -nB.y;
|
|
nC.y = -nC.y;
|
|
|
|
// and z
|
|
nA.z = -nA.z;
|
|
nB.z = -nB.z;
|
|
nC.z = -nC.z;
|
|
|
|
int vertexAx = md.vertexPositionsX[vertexA];
|
|
int vertexAy = md.vertexPositionsY[vertexA];
|
|
int vertexAz = md.vertexPositionsZ[vertexA];
|
|
|
|
int vertexBx = md.vertexPositionsX[vertexB];
|
|
int vertexBy = md.vertexPositionsY[vertexB];
|
|
int vertexBz = md.vertexPositionsZ[vertexB];
|
|
|
|
int vertexCx = md.vertexPositionsX[vertexC];
|
|
int vertexCy = md.vertexPositionsY[vertexC];
|
|
int vertexCz = md.vertexPositionsZ[vertexC];
|
|
|
|
short textureId = md.faceTextures != null ? md.faceTextures[i] : -1;
|
|
int alpha = md.faceAlphas != null ? (md.faceAlphas[i] & 0xFF) : 255;
|
|
if (alpha == 0)
|
|
{
|
|
alpha = 255;
|
|
}
|
|
|
|
Color color;
|
|
|
|
float[] u = null;
|
|
float[] v = null;
|
|
|
|
if (textureId != -1)
|
|
{
|
|
color = Color.WHITE;
|
|
|
|
Texture texture = getTexture(textureId);
|
|
assert texture != null;
|
|
|
|
if (md.faceTextureUCoordinates == null || md.faceTextureVCoordinates == null)
|
|
{
|
|
md.computeTextureUVCoordinates();
|
|
}
|
|
|
|
u = md.faceTextureUCoordinates[i];
|
|
v = md.faceTextureVCoordinates[i];
|
|
|
|
int glTexture = texture.getOpenglId();
|
|
|
|
GL11.glEnable(GL11.GL_TEXTURE_2D);
|
|
GL11.glBindTexture(GL11.GL_TEXTURE_2D, glTexture);
|
|
}
|
|
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);
|
|
}
|
|
|
|
// convert to range of 0-1
|
|
float rf = (float) color.getRed() / 255f;
|
|
float gf = (float) color.getGreen() / 255f;
|
|
float bf = (float) color.getBlue() / 255f;
|
|
float af = (float) alpha / 255f;
|
|
|
|
GL11.glBegin(GL11.GL_TRIANGLES);
|
|
|
|
GL11.glColor4f(rf, gf, bf, af);
|
|
|
|
GL11.glNormal3f(nA.x, nA.y, nA.z);
|
|
if (textureId != -1)
|
|
{
|
|
GL11.glTexCoord2f(u[0], v[0]);
|
|
}
|
|
GL11.glVertex3i(vertexAx, -vertexAy, -vertexAz);
|
|
|
|
GL11.glNormal3f(nB.x, nB.y, nB.z);
|
|
if (textureId != -1)
|
|
{
|
|
GL11.glTexCoord2f(u[1], v[1]);
|
|
}
|
|
GL11.glVertex3i(vertexBx, -vertexBy, -vertexBz);
|
|
|
|
GL11.glNormal3f(nC.x, nC.y, nC.z);
|
|
if (textureId != -1)
|
|
{
|
|
GL11.glTexCoord2f(u[2], v[2]);
|
|
}
|
|
GL11.glVertex3i(vertexCx, -vertexCy, -vertexCz);
|
|
|
|
GL11.glEnd();
|
|
|
|
if (textureId != -1)
|
|
{
|
|
GL11.glDisable(GL11.GL_TEXTURE_2D);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void drawScene(Region region, Scene scene)
|
|
{
|
|
for (int z = 0; z < Region.Z; ++z)
|
|
{
|
|
SceneTileModel[][] sceneTileModels = scene.getSceneTiles()[z];
|
|
SceneTilePaint[][] sceneTilePaint = scene.getSceneTilePaint()[z];
|
|
|
|
for (int x = 0; x < Region.X; ++x)
|
|
{
|
|
for (int y = 0; y < Region.Y; ++y)
|
|
{
|
|
drawSceneTileModel(region, x, y, z, sceneTileModels[x][y]);
|
|
drawSceneTilePaint(region, x, y, z, sceneTilePaint[x][y]);
|
|
}
|
|
}
|
|
}
|
|
drawLocations(region);
|
|
|
|
}
|
|
|
|
private static void drawSceneTilePaint(Region region, int regionX, int regionY, int z, SceneTilePaint sceneTilePaint)
|
|
{
|
|
if (sceneTilePaint == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
int glTexture = -1;
|
|
|
|
Color color;
|
|
|
|
if (sceneTilePaint.texture > -1)
|
|
{
|
|
color = Color.WHITE;
|
|
|
|
Texture texture = getTexture(sceneTilePaint.texture);
|
|
glTexture = texture.getOpenglId();
|
|
assert glTexture > -1;
|
|
|
|
GL11.glEnable(GL11.GL_TEXTURE_2D);
|
|
GL11.glBindTexture(GL11.GL_TEXTURE_2D, glTexture);
|
|
}
|
|
else
|
|
{
|
|
color = new Color(RS2HSB_to_RGB(sceneTilePaint.color));
|
|
}
|
|
|
|
|
|
GL11.glBegin(GL11.GL_TRIANGLES);
|
|
|
|
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
|
|
if (glTexture > -1)
|
|
{
|
|
GL11.glTexCoord2f(0, 0);
|
|
}
|
|
GL11.glVertex3i(x, z1, -y);
|
|
if (glTexture > -1)
|
|
{
|
|
GL11.glTexCoord2f(1, 0);
|
|
}
|
|
GL11.glVertex3i(x + TILE_SCALE, z2, -y);
|
|
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));
|
|
if (glTexture > -1)
|
|
{
|
|
GL11.glTexCoord2f(1, 0);
|
|
}
|
|
GL11.glVertex3i(x + TILE_SCALE, z2, -y);
|
|
if (glTexture > -1)
|
|
{
|
|
GL11.glTexCoord2f(1, 1);
|
|
}
|
|
GL11.glVertex3i(x + TILE_SCALE, z4, -(y + TILE_SCALE));
|
|
|
|
GL11.glEnd();
|
|
|
|
if (glTexture > -1)
|
|
{
|
|
GL11.glDisable(GL11.GL_TEXTURE_2D);
|
|
}
|
|
}
|
|
|
|
private static void drawSceneTileModel(Region region, int regionX, int regionY, int z, SceneTileModel sceneTileModel)
|
|
{
|
|
if (sceneTileModel == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (int i = 0; i < sceneTileModel.faceX.length; ++i)
|
|
{
|
|
int vertexA = sceneTileModel.faceX[i];
|
|
int vertexB = sceneTileModel.faceY[i];
|
|
int vertexC = sceneTileModel.faceZ[i];
|
|
|
|
int vertexAx = sceneTileModel.vertexX[vertexA];
|
|
int vertexAy = sceneTileModel.vertexY[vertexA];
|
|
int vertexAz = sceneTileModel.vertexZ[vertexA];
|
|
|
|
int vertexBx = sceneTileModel.vertexX[vertexB];
|
|
int vertexBy = sceneTileModel.vertexY[vertexB];
|
|
int vertexBz = sceneTileModel.vertexZ[vertexB];
|
|
|
|
int vertexCx = sceneTileModel.vertexX[vertexC];
|
|
int vertexCy = sceneTileModel.vertexY[vertexC];
|
|
int vertexCz = sceneTileModel.vertexZ[vertexC];
|
|
|
|
int colorA = sceneTileModel.triangleColorA[i];
|
|
int colorB = sceneTileModel.triangleColorB[i];
|
|
int colorC = sceneTileModel.triangleColorC[i];
|
|
|
|
Color color = null;
|
|
int glTexture = -1;
|
|
|
|
color = new Color(RS2HSB_to_RGB(colorA));
|
|
|
|
GL11.glBegin(GL11.GL_TRIANGLES);
|
|
|
|
if (color != null)
|
|
{
|
|
GL11.glColor3f((float) color.getRed() / 255f, (float) color.getGreen() / 255f, (float) color.getBlue() / 255f);
|
|
}
|
|
|
|
GL11.glVertex3i(vertexAx, -vertexAy, -vertexAz);
|
|
GL11.glVertex3i(vertexBx, -vertexBy, -vertexBz);
|
|
GL11.glVertex3i(vertexCx, -vertexCy, -vertexCz);
|
|
|
|
GL11.glEnd();
|
|
|
|
if (glTexture > -1)
|
|
{
|
|
GL11.glDisable(GL11.GL_TEXTURE_2D);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void drawLocations(Region region)
|
|
{
|
|
for (Location location : region.getLocations())
|
|
{
|
|
int id = location.getId();
|
|
ObjectDefinition object = getObject(id);
|
|
|
|
if (object == null || object.getObjectModels() == null)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
Position objectPos = location.getPosition();
|
|
|
|
int regionX = objectPos.getX() - region.getBaseX();
|
|
int regionY = objectPos.getY() - region.getBaseY();
|
|
int height = -region.getTileHeight(objectPos.getZ(), regionX, regionY); // / HEIGHT_MOD;
|
|
|
|
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));
|
|
|
|
for (int i = 0; i < object.getObjectModels().length; ++i)
|
|
{
|
|
if (object.getObjectTypes() != null && object.getObjectTypes()[i] != location.getType())
|
|
{
|
|
continue;
|
|
}
|
|
|
|
ModelDefinition md = ModelManager.getModel(object.getObjectModels()[i], object, location);
|
|
|
|
if (md == null)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
drawModel(md, object.getRecolorToFind(), object.getRecolorToReplace());
|
|
}
|
|
|
|
GL11.glTranslatef(-regionX * TILE_SCALE - (TILE_SCALE / 2), -(height + (location.getPosition().getZ() * 0)), regionY * TILE_SCALE + (TILE_SCALE / 2));
|
|
GL11.glPopMatrix();
|
|
}
|
|
}
|
|
|
|
private static ObjectDefinition getObject(int id)
|
|
{
|
|
return objectManager.getObject(id);
|
|
}
|
|
|
|
private static Texture getTexture(int id)
|
|
{
|
|
Texture texture = textures.get(id);
|
|
if (texture != null)
|
|
{
|
|
return texture;
|
|
}
|
|
|
|
TextureDefinition textureDefinition = textureManager.findTexture(id);
|
|
|
|
SpriteDefinition spriteDefinition = spriteManager.findSprite(textureDefinition.getFileIds()[0], 0);
|
|
|
|
int width = spriteDefinition.getWidth();
|
|
int height = spriteDefinition.getHeight();
|
|
|
|
int[] rgb = spriteDefinition.getPixels();
|
|
|
|
ByteBuffer buffer = ByteBuffer.allocateDirect(rgb.length * 4);
|
|
for (int i = 0; i < rgb.length; ++i)
|
|
{
|
|
int pixel = rgb[i];
|
|
|
|
// argb -> rgba
|
|
int a = pixel >>> 24;
|
|
int r = (pixel >> 16) & 0xff;
|
|
int g = (pixel >> 8) & 0xff;
|
|
int b = pixel & 0xff;
|
|
|
|
buffer.put((byte) r);
|
|
buffer.put((byte) g);
|
|
buffer.put((byte) b);
|
|
buffer.put((byte) a);
|
|
}
|
|
buffer.position(0);
|
|
|
|
int glTexture = GL11.glGenTextures();
|
|
GL11.glBindTexture(GL11.GL_TEXTURE_2D, glTexture);
|
|
|
|
//Setup filtering, i.e. how OpenGL will interpolate the pixels when scaling up or down
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
|
|
//Setup wrap mode, i.e. how OpenGL will handle pixels outside of the expected range
|
|
//Note: GL_CLAMP_TO_EDGE is part of GL12
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
|
|
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, width, height, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer);
|
|
|
|
GL11.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); // Linear Filtering
|
|
GL11.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); // Linear Filtering
|
|
|
|
texture = new Texture(rgb, width, height, glTexture);
|
|
textures.put(id, texture);
|
|
|
|
return texture;
|
|
}
|
|
|
|
// 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)
|
|
{
|
|
float[] HSB = Color.RGBtoHSB(red, green, blue, null);
|
|
float hue = (HSB[0]);
|
|
float saturation = (HSB[1]);
|
|
float brightness = (HSB[2]);
|
|
int encode_hue = (int) (hue * 63); //to 6-bits
|
|
int encode_saturation = (int) (saturation * 7); //to 3-bits
|
|
int encode_brightness = (int) (brightness * 127); //to 7-bits
|
|
return (encode_hue << 10) + (encode_saturation << 7) + (encode_brightness);
|
|
}
|
|
|
|
public static int RS2HSB_to_RGB(int RS2HSB)
|
|
{
|
|
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);
|
|
}
|
|
}
|