Some work on terrain rendering

This commit is contained in:
Adam
2016-12-26 19:29:34 -05:00
parent d5af1c6fdf
commit c23da5d33a
8 changed files with 388 additions and 160 deletions

View File

@@ -29,6 +29,7 @@
*/
package net.runelite.modelviewer;
import net.runelite.cache.models.Vector3f;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.GL11;
@@ -39,7 +40,7 @@ public class Camera
{
private static final float MAX_X = 89;
public float moveSpeed = 0.20f;
public float moveSpeed = 0.60f;
private float mouseSensitivity = 0.05f;
@@ -196,104 +197,14 @@ public class Camera
return pos;
}
public void setX(float x)
{
pos.x = x;
}
public float getX()
{
return pos.x;
}
public void addToX(float x)
{
pos.x += x;
}
public void setY(float y)
{
pos.y = y;
}
public float getY()
{
return pos.y;
}
public void addToY(float y)
{
pos.y += y;
}
public void setZ(float z)
{
pos.z = z;
}
public float getZ()
{
return pos.z;
}
public void addToZ(float z)
{
pos.z += z;
}
public void setRotation(Vector3f rotation)
{
this.rotation = rotation;
}
public Vector3f getRotation()
{
return rotation;
}
public void setRotationX(float x)
public void setRotation(Vector3f rotation)
{
rotation.x = x;
}
public float getRotationX()
{
return rotation.x;
}
public void addToRotationX(float x)
{
rotation.x += x;
}
public void setRotationY(float y)
{
rotation.y = y;
}
public float getRotationY()
{
return rotation.y;
}
public void addToRotationY(float y)
{
rotation.y += y;
}
public void setRotationZ(float z)
{
rotation.z = z;
}
public float getRotationZ()
{
return rotation.z;
}
public void addToRotationZ(float z)
{
rotation.z += z;
this.rotation = rotation;
}
public void setMouseSensitivity(float mouseSensitivity)

View File

@@ -33,43 +33,59 @@ import com.google.gson.Gson;
import java.awt.Color;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import net.runelite.cache.definitions.ModelDefinition;
import net.runelite.cache.definitions.NpcDefinition;
import net.runelite.cache.definitions.OverlayDefinition;
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.Region;
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.apache.commons.compress.utils.IOUtils;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
import static org.lwjgl.opengl.GL11.glRotatef;
public class ModelViewer
{
private static final int NUM_UNDERLAYS = 150;
private static final int NUM_OVERLAYS = 174;
private static UnderlayDefinition[] underlays = new UnderlayDefinition[NUM_UNDERLAYS];
private static OverlayDefinition[] overlays = new OverlayDefinition[NUM_OVERLAYS];
public static void main(String[] args) throws Exception
{
Options options = new Options();
options.addOption(null, "npcdir", true, "npc directory");
options.addOption(null, "modeldir", true, "model directory");
options.addOption(null, "mapdir", true, "maps directory");
options.addOption(null, "npc", true, "npc to render");
options.addOption(null, "model", true, "model to render");
options.addOption(null, "map", true, "map region to render");
CommandLineParser parser = new DefaultParser();
CommandLine cmd = parser.parse(options, args);
String npcdir = cmd.getOptionValue("npcdir");
String modeldir = cmd.getOptionValue("modeldir");
String mapdir = cmd.getOptionValue("mapdir");
NpcDefinition npcdef = null;
List<ModelDefinition> models = new ArrayList<>();
Region region = null;
if (cmd.hasOption("model"))
{
@@ -81,7 +97,7 @@ public class ModelViewer
ModelDefinition md = loader.load(b);
models.add(md);
}
else if (cmd.hasOption("npc"))
if (cmd.hasOption("npc"))
{
String npc = cmd.getOptionValue("npc");
@@ -98,10 +114,23 @@ public class ModelViewer
models.add(md);
}
}
else
if (cmd.hasOption("map"))
{
System.out.println("Must specify model or npc");
return;
String map = cmd.getOptionValue("map");
String[] s = map.split(",");
int x = Integer.parseInt(s[0]), y = Integer.parseInt(s[1]);
region = new Region(x, y);
try (FileInputStream fin = new FileInputStream(mapdir + "/m" + x + "_" + y + ".dat"))
{
byte[] b = IOUtils.toByteArray(fin);
region.loadTerrain(b);
}
loadUnderlays();
loadOverlays();
}
Display.setDisplayMode(new DisplayMode(800, 600));
@@ -113,7 +142,7 @@ public class ModelViewer
GL11.glLoadIdentity();
double aspect = 1;
double near = 1; // near should be chosen as far into the scene as possible
double far = 1000;
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);
@@ -121,7 +150,6 @@ public class ModelViewer
GL11.glCullFace(GL11.GL_BACK);
GL11.glEnable(GL11.GL_CULL_FACE);
long last = 0;
Camera camera = new Camera();
@@ -136,6 +164,8 @@ public class ModelViewer
drawModel(npcdef, def);
}
drawRegion(region);
Display.update();
Display.sync(50); // fps
@@ -224,6 +254,129 @@ public class ModelViewer
GL11.glEnd();
}
private static void drawRegion(Region region)
{
if (region == null)
{
return;
}
GL11.glBegin(GL11.GL_TRIANGLES);
for (int regionX = 0; regionX < Region.X; ++regionX)
{
for (int regionY = 0; regionY < Region.Y; ++regionY)
{
int x = regionX;
int y = regionY;
int TILE_SCALE = 16;
x *= TILE_SCALE;
y *= TILE_SCALE;
/*
Split into two triangles with verticies
x,y,z1 x+1,y,z2 x,y+1,z3
x,y+1,z3 x+1,y,z2 x+1,y+1,z4
z1 = height
z2 = height of tile x+1
z3 = height of tile y-1
in rs 0,0 (x,y) is the bottom left with
y increasing going further from you
in opengl, 0,0 (x,z) is the bottom left
with z decreasing going further from you
in rs, height is also negative
so we do rs(x,y,z) -> opengl(x,-z,-y)
*/
int z1 = -region.getTileHeight(0, regionX, regionY);
int z2 = regionX + 1 < Region.X ? -region.getTileHeight(0, regionX + 1, regionY) : z1;
int z3 = regionY + 1 < Region.Y ? -region.getTileHeight(0, regionX, regionY + 1) : z1;
int z4 = regionX + 1 < Region.X && regionY + 1 < Region.Y ? -region.getTileHeight(0, regionX + 1, regionY + 1) : z1;
// scale down height (I randomally picked this)
z1 /= 4;
z2 /= 4;
z3 /= 4;
z4 /= 4;
int underlayId = region.getUnderlayId(0, regionX, regionY);
int overlayId = region.getOverlayId(0, regionX, regionY);
Color color = null;
if (underlayId > 0)
{
UnderlayDefinition ud = underlays[underlayId - 1];
color = new Color(ud.getColor());
}
if (overlayId > 0)
{
OverlayDefinition od = overlays[overlayId - 1];
color = new Color(od.getRgbColor());
if (od.getSecondaryRgbColor() > -1)
{
color = new Color(od.getSecondaryRgbColor());
}
if (od.getTexture() > -1)
{
// textures?
}
}
if (color != null)
{
GL11.glColor3f((float) color.getRed() / 255f, (float) color.getGreen() / 255f, (float) color.getBlue() / 255f);
}
GL11.glVertex3i(x, z1, -y);
GL11.glVertex3i(x + TILE_SCALE, z2, -y);
GL11.glVertex3i(x, z3, -(y + TILE_SCALE));
GL11.glVertex3i(x, z3, -(y + TILE_SCALE));
GL11.glVertex3i(x + TILE_SCALE, z2, -y);
GL11.glVertex3i(x + TILE_SCALE, z4, -(y + TILE_SCALE));
}
}
GL11.glEnd();
}
private static void loadUnderlays() throws IOException
{
for (int i = 0; i < NUM_UNDERLAYS; ++i)
{
try (FileInputStream fin = new FileInputStream("underlays/" + i + ".json"))
{
UnderlayDefinition underlay = new Gson().fromJson(new InputStreamReader(fin), UnderlayDefinition.class);
underlays[i] = underlay;
}
catch (FileNotFoundException ex)
{
}
}
}
private static void loadOverlays() throws IOException
{
for (int i = 0; i < NUM_UNDERLAYS; ++i)
{
try (FileInputStream fin = new FileInputStream("overlays/" + i + ".json"))
{
OverlayDefinition overlay = new Gson().fromJson(new InputStreamReader(fin), OverlayDefinition.class);
overlays[i] = overlay;
}
catch (FileNotFoundException ex)
{
}
}
}
// 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)
{

View File

@@ -1,49 +0,0 @@
/*
* Copyright (c) 2016, 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Adam <Adam@sigterm.info>
* 4. Neither the name of the Adam <Adam@sigterm.info> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY Adam <Adam@sigterm.info> ''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 Adam <Adam@sigterm.info> 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 Vector3f
{
public float x, y, z;
public Vector3f(float x, float y, float z)
{
this.x = x;
this.y = y;
this.z = z;
}
@Override
public String toString()
{
return "Vector3f{" + "x=" + x + ", y=" + y + ", z=" + z + '}';
}
}