Add GPU renderer

This commit is contained in:
Adam
2018-11-15 09:19:37 -05:00
parent 3c84d98638
commit 3f5e273349
74 changed files with 6201 additions and 22 deletions

View File

@@ -41,12 +41,15 @@ import java.awt.image.VolatileImage;
import javax.inject.Inject;
import javax.inject.Singleton;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.BufferProvider;
import net.runelite.api.Client;
import net.runelite.api.MainBufferProvider;
import net.runelite.api.RenderOverview;
import net.runelite.api.Renderable;
import net.runelite.api.WorldMapManager;
import net.runelite.api.events.GameTick;
import net.runelite.api.hooks.Callbacks;
import net.runelite.api.hooks.DrawCallbacks;
import net.runelite.api.widgets.Widget;
import static net.runelite.api.widgets.WidgetInfo.WORLD_MAP_VIEW;
import net.runelite.client.Notifier;
@@ -300,6 +303,15 @@ public class Hooks implements Callbacks
// Draw clientUI overlays
clientUi.paintOverlays(graphics2d);
graphics2d.dispose();
if (client.isGpu())
{
// processDrawComplete gets called on GPU by the gpu plugin at the end of its
// drawing cycle, which is later on.
return;
}
// Stretch the game image if the user has that enabled
if (client.isStretchedEnabled())
{
@@ -418,4 +430,36 @@ public class Hooks implements Callbacks
// have been processed is typically more useful.
shouldProcessGameTick = true;
}
public static void renderDraw(Renderable renderable, int orientation, int pitchSin, int pitchCos, int yawSin, int yawCos, int x, int y, int z, long hash)
{
DrawCallbacks drawCallbacks = client.getDrawCallbacks();
if (drawCallbacks != null)
{
drawCallbacks.draw(renderable, orientation, pitchSin, pitchCos, yawSin, yawCos, x, y, z, hash);
}
else
{
renderable.draw(orientation, pitchSin, pitchCos, yawSin, yawCos, x, y, z, hash);
}
}
public static void clearColorBuffer(int x, int y, int width, int height, int color)
{
BufferProvider bp = client.getBufferProvider();
int canvasWidth = bp.getWidth();
int[] pixels = bp.getPixels();
int pixelPos = y * canvasWidth + x;
int pixelJump = canvasWidth - width;
for (int cy = y; cy < y + height; cy++)
{
for (int cx = x; cx < x + width; cx++)
{
pixels[pixelPos++] = 0;
}
pixelPos += pixelJump;
}
}
}

View File

@@ -0,0 +1,180 @@
/*
* Copyright (c) 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.client.plugins.gpu;
import com.jogamp.opengl.GL4;
import java.io.InputStream;
import java.util.Scanner;
import lombok.extern.slf4j.Slf4j;
@Slf4j
class GLUtil
{
private static final int ERR_LEN = 1024;
private static final int[] buf = new int[1];
static int glGetInteger(GL4 gl, int pname)
{
gl.glGetIntegerv(pname, buf, 0);
return buf[0];
}
static int glGetShader(GL4 gl, int shader, int pname)
{
gl.glGetShaderiv(shader, pname, buf, 0);
assert buf[0] > -1;
return buf[0];
}
static int glGetProgram(GL4 gl, int program, int pname)
{
gl.glGetProgramiv(program, pname, buf, 0);
assert buf[0] > -1;
return buf[0];
}
static String glGetShaderInfoLog(GL4 gl, int shader)
{
byte[] err = new byte[ERR_LEN];
gl.glGetShaderInfoLog(shader, ERR_LEN, buf, 0, err, 0);
return new String(err);
}
static String glGetProgramInfoLog(GL4 gl, int program)
{
byte[] err = new byte[ERR_LEN];
gl.glGetProgramInfoLog(program, ERR_LEN, buf, 0, err, 0);
return new String(err);
}
static int glGenVertexArrays(GL4 gl)
{
gl.glGenVertexArrays(1, buf, 0);
return buf[0];
}
static void glDeleteVertexArrays(GL4 gl, int vertexArray)
{
buf[0] = vertexArray;
gl.glDeleteVertexArrays(1, buf, 0);
}
static int glGenBuffers(GL4 gl)
{
gl.glGenBuffers(1, buf, 0);
return buf[0];
}
static void glDeleteBuffer(GL4 gl, int buffer)
{
buf[0] = buffer;
gl.glDeleteBuffers(1, buf, 0);
}
static int glGenTexture(GL4 gl)
{
gl.glGenTextures(1, buf, 0);
return buf[0];
}
static void glDeleteTexture(GL4 gl, int texture)
{
buf[0] = texture;
gl.glDeleteTextures(1, buf, 0);
}
static void loadShaders(GL4 gl, int glProgram, int glVertexShader, int glGeometryShader, int glFragmentShader,
String vertexShaderStr, String geomShaderStr, String fragShaderStr) throws ShaderException
{
compileAndAttach(gl, glProgram, glVertexShader, vertexShaderStr);
if (glGeometryShader != -1)
{
compileAndAttach(gl, glProgram, glGeometryShader, geomShaderStr);
}
compileAndAttach(gl, glProgram, glFragmentShader, fragShaderStr);
gl.glLinkProgram(glProgram);
if (glGetProgram(gl, glProgram, gl.GL_LINK_STATUS) == gl.GL_FALSE)
{
String err = glGetProgramInfoLog(gl, glProgram);
throw new ShaderException(err);
}
gl.glValidateProgram(glProgram);
if (glGetProgram(gl, glProgram, gl.GL_VALIDATE_STATUS) == gl.GL_FALSE)
{
String err = glGetProgramInfoLog(gl, glProgram);
throw new ShaderException(err);
}
}
static void loadComputeShader(GL4 gl, int glProgram, int glComputeShader, String str) throws ShaderException
{
compileAndAttach(gl, glProgram, glComputeShader, str);
gl.glLinkProgram(glProgram);
if (glGetProgram(gl, glProgram, gl.GL_LINK_STATUS) == gl.GL_FALSE)
{
String err = glGetProgramInfoLog(gl, glProgram);
throw new ShaderException(err);
}
gl.glValidateProgram(glProgram);
if (glGetProgram(gl, glProgram, gl.GL_VALIDATE_STATUS) == gl.GL_FALSE)
{
String err = glGetProgramInfoLog(gl, glProgram);
throw new ShaderException(err);
}
}
private static void compileAndAttach(GL4 gl, int program, int shader, String source) throws ShaderException
{
gl.glShaderSource(shader, 1, new String[]{source}, null);
gl.glCompileShader(shader);
if (glGetShader(gl, shader, gl.GL_COMPILE_STATUS) == gl.GL_TRUE)
{
gl.glAttachShader(program, shader);
}
else
{
String err = glGetShaderInfoLog(gl, shader);
throw new ShaderException(err);
}
}
static String inputStreamToString(InputStream in)
{
Scanner scanner = new Scanner(in).useDelimiter("\\A");
return scanner.next();
}
}

View File

@@ -0,0 +1,72 @@
/*
* Copyright (c) 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.client.plugins.gpu;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
class GpuFloatBuffer
{
private FloatBuffer buffer = allocateDirect(65536);
void put(float texture, float u, float v, float pad)
{
buffer.put(texture).put(u).put(v).put(pad);
}
void flip()
{
buffer.flip();
}
void clear()
{
buffer.clear();
}
void ensureCapacity(int size)
{
while (buffer.remaining() < size)
{
FloatBuffer newB = allocateDirect(buffer.capacity() * 2);
buffer.flip();
newB.put(buffer);
buffer = newB;
}
}
FloatBuffer getBuffer()
{
return buffer;
}
static FloatBuffer allocateDirect(int size)
{
return ByteBuffer.allocateDirect(size * Float.BYTES)
.order(ByteOrder.nativeOrder())
.asFloatBuffer();
}
}

View File

@@ -0,0 +1,77 @@
/*
* Copyright (c) 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.client.plugins.gpu;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
class GpuIntBuffer
{
private IntBuffer buffer = allocateDirect(65536);
void put(int x, int y, int z)
{
buffer.put(x).put(y).put(z);
}
void put(int x, int y, int z, int c)
{
buffer.put(x).put(y).put(z).put(c);
}
void flip()
{
buffer.flip();
}
void clear()
{
buffer.clear();
}
void ensureCapacity(int size)
{
while (buffer.remaining() < size)
{
IntBuffer newB = allocateDirect(buffer.capacity() * 2);
buffer.flip();
newB.put(buffer);
buffer = newB;
}
}
IntBuffer getBuffer()
{
return buffer;
}
static IntBuffer allocateDirect(int size)
{
return ByteBuffer.allocateDirect(size * Integer.BYTES)
.order(ByteOrder.nativeOrder())
.asIntBuffer();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,43 @@
/*
* Copyright (c) 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.client.plugins.gpu;
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
@ConfigGroup("gpu")
public interface GpuPluginConfig extends Config
{
@ConfigItem(
keyName = "drawDistance",
name = "Draw Distance",
description = "Draw distance"
)
default int drawDistance()
{
return 25;
}
}

View File

@@ -0,0 +1,549 @@
/*
* Copyright (c) 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.client.plugins.gpu;
import javax.inject.Inject;
import javax.inject.Singleton;
import net.runelite.api.Client;
import net.runelite.api.Constants;
import net.runelite.api.DecorativeObject;
import net.runelite.api.GameObject;
import net.runelite.api.GroundObject;
import net.runelite.api.Model;
import net.runelite.api.Perspective;
import net.runelite.api.Point;
import net.runelite.api.Renderable;
import net.runelite.api.Scene;
import net.runelite.api.SceneTileModel;
import net.runelite.api.SceneTilePaint;
import net.runelite.api.Tile;
import net.runelite.api.WallObject;
@Singleton
class SceneUploader
{
@Inject
private Client client;
int sceneId = (int) (System.currentTimeMillis() / 1000L);
private int offset;
private int uvoffset;
void upload(Scene scene, GpuIntBuffer vertexbuffer, GpuFloatBuffer uvBuffer)
{
++sceneId;
offset = 0;
uvoffset = 0;
vertexbuffer.clear();
uvBuffer.clear();
for (int z = 0; z < Constants.MAX_Z; ++z)
{
for (int x = 0; x < Constants.SCENE_SIZE; ++x)
{
for (int y = 0; y < Constants.SCENE_SIZE; ++y)
{
Tile tile = scene.getTiles()[z][x][y];
if (tile != null)
{
reset(tile);
}
}
}
}
for (int z = 0; z < Constants.MAX_Z; ++z)
{
for (int x = 0; x < Constants.SCENE_SIZE; ++x)
{
for (int y = 0; y < Constants.SCENE_SIZE; ++y)
{
Tile tile = scene.getTiles()[z][x][y];
if (tile != null)
{
upload(tile, vertexbuffer, uvBuffer);
}
}
}
}
}
private void reset(Tile tile)
{
Tile bridge = tile.getBridge();
if (bridge != null)
{
reset(bridge);
}
SceneTilePaint sceneTilePaint = tile.getSceneTilePaint();
if (sceneTilePaint != null)
{
sceneTilePaint.setBufferOffset(-1);
}
SceneTileModel sceneTileModel = tile.getSceneTileModel();
if (sceneTileModel != null)
{
sceneTileModel.setBufferOffset(-1);
}
WallObject wallObject = tile.getWallObject();
if (wallObject != null)
{
if (wallObject.getRenderable1() instanceof Model)
{
((Model) wallObject.getRenderable1()).setBufferOffset(-1);
}
if (wallObject.getRenderable2() instanceof Model)
{
((Model) wallObject.getRenderable2()).setBufferOffset(-1);
}
}
GroundObject groundObject = tile.getGroundObject();
if (groundObject != null)
{
if (groundObject.getRenderable() instanceof Model)
{
((Model) groundObject.getRenderable()).setBufferOffset(-1);
}
}
DecorativeObject decorativeObject = tile.getDecorativeObject();
if (decorativeObject != null)
{
if (decorativeObject.getRenderable() instanceof Model)
{
((Model) decorativeObject.getRenderable()).setBufferOffset(-1);
}
}
GameObject[] gameObjects = tile.getGameObjects();
for (GameObject gameObject : gameObjects)
{
if (gameObject == null)
{
continue;
}
if (gameObject.getRenderable() instanceof Model)
{
((Model) gameObject.getRenderable()).setBufferOffset(-1);
}
}
}
private void upload(Tile tile, GpuIntBuffer vertexBuffer, GpuFloatBuffer uvBuffer)
{
Tile bridge = tile.getBridge();
if (bridge != null)
{
upload(bridge, vertexBuffer, uvBuffer);
}
SceneTilePaint sceneTilePaint = tile.getSceneTilePaint();
if (sceneTilePaint != null)
{
sceneTilePaint.setBufferOffset(offset);
if (sceneTilePaint.getTexture() != -1)
{
sceneTilePaint.setUvBufferOffset(uvoffset);
}
else
{
sceneTilePaint.setUvBufferOffset(-1);
}
Point tilePoint = tile.getSceneLocation();
int len = upload(sceneTilePaint, tile.getRenderLevel(), tilePoint.getX(), tilePoint.getY(), vertexBuffer, uvBuffer);
sceneTilePaint.setBufferLen(len);
offset += len;
if (sceneTilePaint.getTexture() != -1)
{
uvoffset += len;
}
}
SceneTileModel sceneTileModel = tile.getSceneTileModel();
if (sceneTileModel != null)
{
sceneTileModel.setBufferOffset(offset);
if (sceneTileModel.getTriangleTextureId() != null)
{
sceneTileModel.setUvBufferOffset(uvoffset);
}
else
{
sceneTileModel.setUvBufferOffset(-1);
}
Point tilePoint = tile.getSceneLocation();
int len = upload(sceneTileModel, tilePoint.getX(), tilePoint.getY(), vertexBuffer, uvBuffer);
sceneTileModel.setBufferLen(len);
offset += len;
if (sceneTileModel.getTriangleTextureId() != null)
{
uvoffset += len;
}
}
WallObject wallObject = tile.getWallObject();
if (wallObject != null)
{
Renderable renderable1 = wallObject.getRenderable1();
if (renderable1 instanceof Model)
{
uploadModel((Model) renderable1, vertexBuffer, uvBuffer);
}
Renderable renderable2 = wallObject.getRenderable2();
if (renderable2 instanceof Model)
{
uploadModel((Model) renderable2, vertexBuffer, uvBuffer);
}
}
GroundObject groundObject = tile.getGroundObject();
if (groundObject != null)
{
Renderable renderable = groundObject.getRenderable();
if (renderable instanceof Model)
{
uploadModel((Model) renderable, vertexBuffer, uvBuffer);
}
}
DecorativeObject decorativeObject = tile.getDecorativeObject();
if (decorativeObject != null)
{
Renderable renderable = decorativeObject.getRenderable();
if (renderable instanceof Model)
{
uploadModel((Model) renderable, vertexBuffer, uvBuffer);
}
Renderable renderable2 = decorativeObject.getRenderable2();
if (renderable2 instanceof Model)
{
uploadModel((Model) renderable2, vertexBuffer, uvBuffer);
}
}
GameObject[] gameObjects = tile.getGameObjects();
for (GameObject gameObject : gameObjects)
{
if (gameObject == null)
{
continue;
}
Renderable renderable = gameObject.getRenderable();
if (renderable instanceof Model)
{
uploadModel((Model) gameObject.getRenderable(), vertexBuffer, uvBuffer);
}
}
}
private int upload(SceneTilePaint tile, int tileZ, int tileX, int tileY, GpuIntBuffer vertexBuffer, GpuFloatBuffer uvBuffer)
{
final int[][][] tileHeights = client.getTileHeights();
final int localX = 0;
final int localY = 0;
int swHeight = tileHeights[tileZ][tileX][tileY];
int seHeight = tileHeights[tileZ][tileX + 1][tileY];
int neHeight = tileHeights[tileZ][tileX + 1][tileY + 1];
int nwHeight = tileHeights[tileZ][tileX][tileY + 1];
final int neColor = tile.getNeColor();
final int nwColor = tile.getNwColor();
final int seColor = tile.getSeColor();
final int swColor = tile.getSwColor();
if (neColor == 12345678)
{
return 0;
}
vertexBuffer.ensureCapacity(24);
uvBuffer.ensureCapacity(24);
// 0,0
int vertexDx = localX;
int vertexDy = localY;
int vertexDz = swHeight;
final int c1 = swColor;
// 1,0
int vertexCx = localX + Perspective.LOCAL_TILE_SIZE;
int vertexCy = localY;
int vertexCz = seHeight;
final int c2 = nwColor;
// 1,1
int vertexAx = localX + Perspective.LOCAL_TILE_SIZE;
int vertexAy = localY + Perspective.LOCAL_TILE_SIZE;
int vertexAz = neHeight;
final int c3 = neColor;
// 0,1
int vertexBx = localX;
int vertexBy = localY + Perspective.LOCAL_TILE_SIZE;
int vertexBz = nwHeight;
final int c4 = seColor;
vertexBuffer.put(vertexAx, vertexAz, vertexAy, c3);
vertexBuffer.put(vertexBx, vertexBz, vertexBy, c4);
vertexBuffer.put(vertexCx, vertexCz, vertexCy, c2);
vertexBuffer.put(vertexDx, vertexDz, vertexDy, c1);
vertexBuffer.put(vertexCx, vertexCz, vertexCy, c2);
vertexBuffer.put(vertexBx, vertexBz, vertexBy, c4);
if (tile.getTexture() != -1)
{
float tex = tile.getTexture();
uvBuffer.put(tex, 1.0f + 1f, 1.0f + 1f, 0f);
uvBuffer.put(tex, 0.0f + 1f, 1.0f + 1f, 0f);
uvBuffer.put(tex, 1.0f + 1f, 0.0f + 1f, 0f);
uvBuffer.put(tex, 0.0f + 1f, 0.0f + 1f, 0f);
uvBuffer.put(tex, 1.0f + 1f, 0.0f + 1f, 0f);
uvBuffer.put(tex, 0.0f + 1f, 1.0f + 1f, 0f);
}
return 6;
}
private int upload(SceneTileModel sceneTileModel, int tileX, int tileY, GpuIntBuffer vertexBuffer, GpuFloatBuffer uvBuffer)
{
final int[] faceX = sceneTileModel.getFaceX();
final int[] faceY = sceneTileModel.getFaceY();
final int[] faceZ = sceneTileModel.getFaceZ();
final int[] vertexX = sceneTileModel.getVertexX();
final int[] vertexY = sceneTileModel.getVertexY();
final int[] vertexZ = sceneTileModel.getVertexZ();
final int[] triangleColorA = sceneTileModel.getTriangleColorA();
final int[] triangleColorB = sceneTileModel.getTriangleColorB();
final int[] triangleColorC = sceneTileModel.getTriangleColorC();
final int[] triangleTextures = sceneTileModel.getTriangleTextureId();
final int faceCount = faceX.length;
vertexBuffer.ensureCapacity(faceCount * 12);
uvBuffer.ensureCapacity(faceCount * 12);
int baseX = Perspective.LOCAL_TILE_SIZE * tileX;
int baseY = Perspective.LOCAL_TILE_SIZE * tileY;
int cnt = 0;
for (int i = 0; i < faceCount; ++i)
{
final int triangleA = faceX[i];
final int triangleB = faceY[i];
final int triangleC = faceZ[i];
final int colorA = triangleColorA[i];
final int colorB = triangleColorB[i];
final int colorC = triangleColorC[i];
if (colorA == 12345678)
{
continue;
}
cnt += 3;
int vertexXA = vertexX[triangleA] - baseX;
int vertexZA = vertexZ[triangleA] - baseY;
int vertexXB = vertexX[triangleB] - baseX;
int vertexZB = vertexZ[triangleB] - baseY;
int vertexXC = vertexX[triangleC] - baseX;
int vertexZC = vertexZ[triangleC] - baseY;
vertexBuffer.put(vertexXA, vertexY[triangleA], vertexZA, colorA);
vertexBuffer.put(vertexXB, vertexY[triangleB], vertexZB, colorB);
vertexBuffer.put(vertexXC, vertexY[triangleC], vertexZC, colorC);
if (triangleTextures != null)
{
if (triangleTextures[i] != -1)
{
float tex = triangleTextures[i];
uvBuffer.put(tex, vertexXA / 128f + 1f, vertexZA / 128f + 1f, 0f);
uvBuffer.put(tex, vertexXB / 128f + 1f, vertexZB / 128f + 1f, 0f);
uvBuffer.put(tex, vertexXC / 128f + 1f, vertexZC / 128f + 1f, 0f);
}
else
{
uvBuffer.put(0, 0, 0, 0f);
uvBuffer.put(0, 0, 0, 0f);
uvBuffer.put(0, 0, 0, 0f);
}
}
}
return cnt;
}
private void uploadModel(Model model, GpuIntBuffer vertexBuffer, GpuFloatBuffer uvBuffer)
{
if (model.getBufferOffset() > 0)
{
return;
}
model.setBufferOffset(offset);
if (model.getFaceTextures() != null)
{
model.setUvBufferOffset(uvoffset);
}
else
{
model.setUvBufferOffset(-1);
}
model.setSceneId(sceneId);
vertexBuffer.ensureCapacity(model.getTrianglesCount() * 12);
uvBuffer.ensureCapacity(model.getTrianglesCount() * 12);
final int triangleCount = model.getTrianglesCount();
int len = 0;
for (int i = 0; i < triangleCount; ++i)
{
len += pushFace(model, i, vertexBuffer, uvBuffer);
}
offset += len;
if (model.getFaceTextures() != null)
{
uvoffset += len;
}
}
int pushFace(Model model, int face, GpuIntBuffer vertexBuffer, GpuFloatBuffer uvBuffer)
{
final int[] vertexX = model.getVerticesX();
final int[] vertexY = model.getVerticesY();
final int[] vertexZ = model.getVerticesZ();
final int[] trianglesX = model.getTrianglesX();
final int[] trianglesY = model.getTrianglesY();
final int[] trianglesZ = model.getTrianglesZ();
final int[] color1s = model.getFaceColors1();
final int[] color2s = model.getFaceColors2();
final int[] color3s = model.getFaceColors3();
final byte[] transparencies = model.getTriangleTransparencies();
final short[] faceTextures = model.getFaceTextures();
final byte[] facePriorities = model.getFaceRenderPriorities();
int triangleA = trianglesX[face];
int triangleB = trianglesY[face];
int triangleC = trianglesZ[face];
int color1 = color1s[face];
int color2 = color2s[face];
int color3 = color3s[face];
int alpha = 0;
if (transparencies != null)
{
alpha = (transparencies[face] & 0xFF) << 24;
}
int priority = 0;
if (facePriorities != null)
{
priority = (facePriorities[face] & 0xff) << 16;
}
if (color3 == -1)
{
color2 = color3 = color1;
}
else if (color3 == -2)
{
vertexBuffer.put(0, 0, 0, 0);
vertexBuffer.put(0, 0, 0, 0);
vertexBuffer.put(0, 0, 0, 0);
if (faceTextures != null)
{
uvBuffer.put(0, 0, 0, 0f);
uvBuffer.put(0, 0, 0, 0f);
uvBuffer.put(0, 0, 0, 0f);
}
return 3;
}
int a, b, c;
a = vertexX[triangleA];
b = vertexY[triangleA];
c = vertexZ[triangleA];
vertexBuffer.put(a, b, c, alpha | priority | color1);
a = vertexX[triangleB];
b = vertexY[triangleB];
c = vertexZ[triangleB];
vertexBuffer.put(a, b, c, alpha | priority | color2);
a = vertexX[triangleC];
b = vertexY[triangleC];
c = vertexZ[triangleC];
vertexBuffer.put(a, b, c, alpha | priority | color3);
float[][] u = model.getFaceTextureUCoordinates();
float[][] v = model.getFaceTextureVCoordinates();
float[] uf, vf;
if (faceTextures != null)
{
if (u != null && v != null && (uf = u[face]) != null && (vf = v[face]) != null)
{
final short texture = faceTextures[face];
uvBuffer.put(texture, 1f + uf[0], 1f + vf[0], 0f);
uvBuffer.put(texture, 1f + uf[1], 1f + vf[1], 0f);
uvBuffer.put(texture, 1f + uf[2], 1f + vf[2], 0f);
}
else
{
uvBuffer.put(0f, 0f, 0f, 0f);
uvBuffer.put(0f, 0f, 0f, 0f);
uvBuffer.put(0f, 0f, 0f, 0f);
}
}
return 3;
}
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright (c) 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.client.plugins.gpu;
class ShaderException extends Exception
{
ShaderException(String message)
{
super(message);
}
}

View File

@@ -0,0 +1,235 @@
/*
* Copyright (c) 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.client.plugins.gpu;
import com.jogamp.opengl.GL4;
import java.nio.ByteBuffer;
import javax.inject.Singleton;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Texture;
import net.runelite.api.TextureProvider;
@Singleton
@Slf4j
class TextureManager
{
private static final float PERC_64 = 1f / 64f;
private static final float PERC_128 = 1f / 128f;
private static final int SMALL_TEXTURE_SIZE = 64;
private static final int TEXTURE_SIZE = 128;
int initTextureArray(TextureProvider textureProvider, GL4 gl)
{
if (!allTexturesLoaded(textureProvider))
{
return -1;
}
Texture[] textures = textureProvider.getTextures();
int textureArrayId = GLUtil.glGenTexture(gl);
gl.glBindTexture(gl.GL_TEXTURE_2D_ARRAY, textureArrayId);
gl.glTexStorage3D(gl.GL_TEXTURE_2D_ARRAY, 1, gl.GL_RGBA8, TEXTURE_SIZE, TEXTURE_SIZE, textures.length);
gl.glTexParameteri(gl.GL_TEXTURE_2D_ARRAY, gl.GL_TEXTURE_MIN_FILTER, gl.GL_NEAREST);
gl.glTexParameteri(gl.GL_TEXTURE_2D_ARRAY, gl.GL_TEXTURE_MAG_FILTER, gl.GL_NEAREST);
gl.glTexParameteri(gl.GL_TEXTURE_2D_ARRAY, gl.GL_TEXTURE_WRAP_S, gl.GL_CLAMP_TO_EDGE);
// Set brightness to 1.0d to upload unmodified textures to GPU
double save = textureProvider.getBrightness();
textureProvider.setBrightness(1.0d);
updateTextures(textureProvider, gl, textureArrayId);
textureProvider.setBrightness(save);
gl.glActiveTexture(gl.GL_TEXTURE1);
gl.glBindTexture(gl.GL_TEXTURE_2D_ARRAY, textureArrayId);
gl.glActiveTexture(gl.GL_TEXTURE0);
return textureArrayId;
}
void freeTextureArray(GL4 gl, int textureArrayId)
{
GLUtil.glDeleteTexture(gl, textureArrayId);
}
/**
* Check if all textures have been loaded and cached yet.
*
* @param textureProvider
* @return
*/
private boolean allTexturesLoaded(TextureProvider textureProvider)
{
Texture[] textures = textureProvider.getTextures();
if (textures == null || textures.length == 0)
{
return false;
}
for (int textureId = 0; textureId < textures.length; textureId++)
{
Texture texture = textures[textureId];
if (texture != null)
{
int[] pixels = textureProvider.load(textureId);
if (pixels == null)
{
return false;
}
}
}
return true;
}
private void updateTextures(TextureProvider textureProvider, GL4 gl, int textureArrayId)
{
Texture[] textures = textureProvider.getTextures();
gl.glBindTexture(gl.GL_TEXTURE_2D_ARRAY, textureArrayId);
int cnt = 0;
for (int textureId = 0; textureId < textures.length; textureId++)
{
Texture texture = textures[textureId];
if (texture != null)
{
int[] srcPixels = textureProvider.load(textureId);
if (srcPixels == null)
{
log.warn("No pixels for texture {}!", textureId);
continue; // this can't happen
}
++cnt;
int srcSize = srcPixels.length == 4096 ? SMALL_TEXTURE_SIZE : TEXTURE_SIZE;
byte[] pixels = convertPixels(srcPixels, srcSize, srcSize, TEXTURE_SIZE, TEXTURE_SIZE);
ByteBuffer pixelBuffer = ByteBuffer.wrap(pixels);
gl.glTexSubImage3D(gl.GL_TEXTURE_2D_ARRAY, 0, 0, 0, textureId, TEXTURE_SIZE, TEXTURE_SIZE,
1, gl.GL_RGBA, gl.GL_UNSIGNED_BYTE, pixelBuffer);
}
}
log.debug("Uploaded textures {}", cnt);
}
private static byte[] convertPixels(int[] srcPixels, int width, int height, int textureWidth, int textureHeight)
{
byte[] pixels = new byte[textureWidth * textureHeight * 4];
int pixelIdx = 0;
int srcPixelIdx = 0;
int offset = (textureWidth - width) * 4;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
int rgb = srcPixels[srcPixelIdx++];
if (rgb != 0)
{
pixels[pixelIdx++] = (byte) (rgb >> 16);
pixels[pixelIdx++] = (byte) (rgb >> 8);
pixels[pixelIdx++] = (byte) rgb;
pixels[pixelIdx++] = (byte) -1;
}
else
{
pixelIdx += 4;
}
}
pixelIdx += offset;
}
return pixels;
}
/**
* Animate the given texture
*
* @param texture
* @param diff Number of elapsed client ticks since last animation
*/
void animate(Texture texture, int diff)
{
final int[] pixels = texture.getPixels();
if (pixels == null)
{
return;
}
final int animationSpeed = texture.getAnimationSpeed();
final float uvdiff = pixels.length == 4096 ? PERC_64 : PERC_128;
float u = texture.getU();
float v = texture.getV();
int offset = animationSpeed * diff;
float d = (float) offset * uvdiff;
switch (texture.getAnimationDirection())
{
case 1:
v -= d;
if (v < 0f)
{
v += 1f;
}
break;
case 3:
v += d;
if (v > 1f)
{
v -= 1f;
}
break;
case 2:
u -= d;
if (u < 0f)
{
u += 1f;
}
break;
case 4:
u += d;
if (u > 1f)
{
u -= 1f;
}
break;
default:
return;
}
texture.setU(u);
texture.setV(v);
}
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright (c) 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.client.plugins.gpu.template;
import java.util.function.Function;
public class Template
{
private final Function<String, String> resourceLoader;
public Template(Function<String, String> resourceLoader)
{
this.resourceLoader = resourceLoader;
}
public String process(String str)
{
StringBuilder sb = new StringBuilder();
for (String line : str.split("\r?\n"))
{
if (line.startsWith("#include "))
{
String resource = line.substring(9);
String resourceStr = resourceLoader.apply(resource);
sb.append(process(resourceStr));
}
else
{
sb.append(line).append('\n');
}
}
return sb.toString();
}
}

View File

@@ -0,0 +1,166 @@
/*
* Copyright (c) 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.
*/
#include to_screen.glsl
/*
* Rotate a vertex by a given orientation in JAU
*/
ivec4 rotate(ivec4 vertex, int orientation) {
int s = int(65536.0f * sin(orientation * UNIT));
int c = int(65536.0f * cos(orientation * UNIT));
int x = vertex.z * s + vertex.x * c >> 16;
int z = vertex.z * c - vertex.x * s >> 16;
return ivec4(x, vertex.y, z, vertex.w);
}
/*
* Calculate the distance to a vertex given the camera angle
*/
int distance(ivec4 vertex, int cameraYaw, int cameraPitch) {
int yawSin = int(65536.0f * sin(cameraYaw * UNIT));
int yawCos = int(65536.0f * cos(cameraYaw * UNIT));
int pitchSin = int(65536.0f * sin(cameraPitch * UNIT));
int pitchCos = int(65536.0f * cos(cameraPitch * UNIT));
int j = vertex.z * yawCos - vertex.x * yawSin >> 16;
int l = vertex.y * pitchSin + j * pitchCos >> 16;
return l;
}
/*
* Calculate the distance to a face
*/
int face_distance(ivec4 vA, ivec4 vB, ivec4 vC, int cameraYaw, int cameraPitch) {
int dvA = distance(vA, cameraYaw, cameraPitch);
int dvB = distance(vB, cameraYaw, cameraPitch);
int dvC = distance(vC, cameraYaw, cameraPitch);
int faceDistance = (dvA + dvB + dvC) / 3;
return faceDistance;
}
/*
* Test if a face is visible (not backward facing)
*/
bool face_visible(ivec4 vA, ivec4 vB, ivec4 vC, ivec4 position, int cameraYaw, int cameraPitch, int centerX, int centerY, int zoom) {
vA += position;
vB += position;
vC += position;
ivec3 sA = toScreen(vA.xyz, cameraYaw, cameraPitch, centerX, centerY, zoom);
ivec3 sB = toScreen(vB.xyz, cameraYaw, cameraPitch, centerX, centerY, zoom);
ivec3 sC = toScreen(vC.xyz, cameraYaw, cameraPitch, centerX, centerY, zoom);
return (sA.x - sB.x) * (sC.y - sB.y) - (sC.x - sB.x) * (sA.y - sB.y) > 0;
}
// Calculate adjusted priority for a face with a given priority, distance, and
// model global min10 and face distance averages. This allows positioning faces
// with priorities 10/11 into the correct 'slots' resulting in 18 possible
// adjusted priorities
int priority_map(int p, int distance, int _min10, int avg1, int avg2, int avg3) {
// (10, 11) 0 1 2 (10, 11) 3 4 (10, 11) 5 6 7 8 9 (10, 11)
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
switch (p) {
case 0: return 2;
case 1: return 3;
case 2: return 4;
case 3: return 7;
case 4: return 8;
case 5: return 11;
case 6: return 12;
case 7: return 13;
case 8: return 14;
case 9: return 15;
case 10:
if (distance > avg1) {
return 0;
} else if (distance > avg2) {
return 5;
} else if (distance > avg3) {
return 9;
} else {
return 16;
}
case 11:
if (distance > avg1 && _min10 > avg1) {
return 1;
} else if (distance > avg2 && (_min10 > avg1 || _min10 > avg2)) {
return 6;
} else if (distance > avg3 && (_min10 > avg1 || _min10 > avg2 || _min10 > avg3)) {
return 10;
} else {
return 17;
}
default:
return -1;
}
}
// calculate the number of faces with a lower adjusted priority than
// the given adjusted priority
int count_prio_offset(int priority) {
int total = 0;
switch (priority) {
case 17:
total += totalMappedNum[16];
case 16:
total += totalMappedNum[15];
case 15:
total += totalMappedNum[14];
case 14:
total += totalMappedNum[13];
case 13:
total += totalMappedNum[12];
case 12:
total += totalMappedNum[11];
case 11:
total += totalMappedNum[10];
case 10:
total += totalMappedNum[9];
case 9:
total += totalMappedNum[8];
case 8:
total += totalMappedNum[7];
case 7:
total += totalMappedNum[6];
case 6:
total += totalMappedNum[5];
case 5:
total += totalMappedNum[4];
case 4:
total += totalMappedNum[3];
case 3:
total += totalMappedNum[2];
case 2:
total += totalMappedNum[1];
case 1:
total += totalMappedNum[0];
case 0:
return total;
}
}

View File

@@ -0,0 +1,150 @@
/*
* Copyright (c) 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.
*/
#version 430 core
#define PI 3.1415926535897932384626433832795f
#define UNIT PI / 1024.0f
layout(std140) uniform uniforms {
int cameraYaw;
int cameraPitch;
int centerX;
int centerY;
int zoom;
};
shared int totalNum[12]; // number of faces with a given priority
shared int totalDistance[12]; // sum of distances to faces of a given priority
shared int totalMappedNum[18]; // number of faces with a given adjusted priority
shared int min10; // minimum distance to a face of priority 10
shared int dfs[4096]; // packed face id and distance
struct modelinfo {
int offset; // offset into buffer
int uvOffset; // offset into uv buffer
int length; // length in faces
int idx; // write idx in target buffer
int flags; // radius, orientation
int x; // scene position x
int y; // scene position y
int z; // scene position z
};
layout(std430, binding = 0) readonly buffer modelbuffer_in {
modelinfo ol[];
};
layout(std430, binding = 1) readonly buffer vertexbuffer_in {
ivec4 vb[];
};
layout(std430, binding = 2) readonly buffer tempvertexbuffer_in {
ivec4 tempvb[];
};
layout(std430, binding = 3) writeonly buffer vertex_out {
ivec4 vout[];
};
layout(std430, binding = 4) writeonly buffer uv_out {
vec4 uvout[];
};
layout(std430, binding = 5) readonly buffer uvbuffer_in {
vec4 uv[];
};
layout(std430, binding = 6) readonly buffer tempuvbuffer_in {
vec4 tempuv[];
};
layout(local_size_x = 1024) in;
#include common.glsl
#include priority_render.glsl
void main() {
uint groupId = gl_WorkGroupID.x;
uint localId = gl_LocalInvocationID.x * 4;
modelinfo minfo = ol[groupId];
int length = minfo.length;
if (localId == 0) {
min10 = 1600;
for (int i = 0; i < 12; ++i) {
totalNum[i] = 0;
totalDistance[i] = 0;
}
for (int i = 0; i < 18; ++i) {
totalMappedNum[i] = 0;
}
}
memoryBarrierShared();
barrier();
int prio1, dis1, prio1Adj;
ivec4 vA1, vA2, vA3;
int prio2, dis2, prio2Adj;
ivec4 vB1, vB2, vB3;
int prio3, dis3, prio3Adj;
ivec4 vC1, vC2, vC3;
int prio4, dis4, prio4Adj;
ivec4 vD1, vD2, vD3;
get_face(localId, minfo, cameraYaw, cameraPitch, centerX, centerY, zoom, prio1, dis1, vA1, vA2, vA3);
get_face(localId + 1, minfo, cameraYaw, cameraPitch, centerX, centerY, zoom, prio2, dis2, vB1, vB2, vB3);
get_face(localId + 2, minfo, cameraYaw, cameraPitch, centerX, centerY, zoom, prio3, dis3, vC1, vC2, vC3);
get_face(localId + 3, minfo, cameraYaw, cameraPitch, centerX, centerY, zoom, prio4, dis4, vD1, vD2, vD3);
memoryBarrierShared();
barrier();
int idx1 = map_face_priority(localId, minfo, prio1, dis1, prio1Adj);
int idx2 = map_face_priority(localId + 1, minfo, prio2, dis2, prio2Adj);
int idx3 = map_face_priority(localId + 2, minfo, prio3, dis3, prio3Adj);
int idx4 = map_face_priority(localId + 3, minfo, prio4, dis4, prio4Adj);
memoryBarrierShared();
barrier();
insert_dfs(localId , minfo, prio1Adj, dis1, idx1);
insert_dfs(localId + 1, minfo, prio2Adj, dis2, idx2);
insert_dfs(localId + 2, minfo, prio3Adj, dis3, idx3);
insert_dfs(localId + 3, minfo, prio4Adj, dis4, idx4);
memoryBarrierShared();
barrier();
sort_and_insert(localId , minfo, prio1Adj, dis1, vA1, vA2, vA3);
sort_and_insert(localId + 1, minfo, prio2Adj, dis2, vB1, vB2, vB3);
sort_and_insert(localId + 2, minfo, prio3Adj, dis3, vC1, vC2, vC3);
sort_and_insert(localId + 3, minfo, prio4Adj, dis4, vD1, vD2, vD3);
}

View File

@@ -0,0 +1,128 @@
/*
* Copyright (c) 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.
*/
#version 430 core
#define PI 3.1415926535897932384626433832795f
#define UNIT PI / 1024.0f
layout(std140) uniform uniforms {
int cameraYaw;
int cameraPitch;
int centerX;
int centerY;
int zoom;
};
shared int totalNum[12]; // number of faces with a given priority
shared int totalDistance[12]; // sum of distances to faces of a given priority
shared int totalMappedNum[18]; // number of faces with a given adjusted priority
shared int min10; // minimum distance to a face of priority 10
shared int dfs[512]; // packed face id and distance
struct modelinfo {
int offset; // offset into buffer
int uvOffset; // offset into uv buffer
int length; // length in faces
int idx; // write idx in target buffer
int flags; // radius, orientation
int x; // scene position x
int y; // scene position y
int z; // scene position z
};
layout(std430, binding = 0) readonly buffer modelbuffer_in {
modelinfo ol[];
};
layout(std430, binding = 1) readonly buffer vertexbuffer_in {
ivec4 vb[];
};
layout(std430, binding = 2) readonly buffer tempvertexbuffer_in {
ivec4 tempvb[];
};
layout(std430, binding = 3) writeonly buffer vertex_out {
ivec4 vout[];
};
layout(std430, binding = 4) writeonly buffer uv_out {
vec4 uvout[];
};
layout(std430, binding = 5) readonly buffer uvbuffer_in {
vec4 uv[];
};
layout(std430, binding = 6) readonly buffer tempuvbuffer_in {
vec4 tempuv[];
};
layout(local_size_x = 512) in;
#include common.glsl
#include priority_render.glsl
void main() {
uint groupId = gl_WorkGroupID.x;
uint localId = gl_LocalInvocationID.x;
modelinfo minfo = ol[groupId];
if (localId == 0) {
min10 = 1600;
for (int i = 0; i < 12; ++i) {
totalNum[i] = 0;
totalDistance[i] = 0;
}
for (int i = 0; i < 18; ++i) {
totalMappedNum[i] = 0;
}
}
memoryBarrierShared();
barrier();
int prio1, dis1, prio1Adj;
ivec4 vA1, vA2, vA3;
get_face(localId, minfo, cameraYaw, cameraPitch, centerX, centerY, zoom, prio1, dis1, vA1, vA2, vA3);
memoryBarrierShared();
barrier();
int idx1 = map_face_priority(localId, minfo, prio1, dis1, prio1Adj);
memoryBarrierShared();
barrier();
insert_dfs(localId, minfo, prio1Adj, dis1, idx1);
memoryBarrierShared();
barrier();
sort_and_insert(localId, minfo, prio1Adj, dis1, vA1, vA2, vA3);
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright (c) 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.
*/
#version 400
uniform sampler2DArray textures;
uniform vec2 textureOffsets[64];
uniform float brightness;
in vec4 Color;
in vec4 fUv;
out vec4 FragColor;
void main() {
float n = fUv.x;
float u = fUv.y;
float v = fUv.z;
if (u > 0.0f && v > 0.0f) {
int textureIdx = int(n);
vec2 uv = vec2(u - 1, v - 1);
vec2 animatedUv = uv + textureOffsets[textureIdx];
vec4 textureColor = texture(textures, vec3(animatedUv, n));
vec4 textureColorBrightness = pow(textureColor, vec4(brightness, brightness, brightness, 1.0f));
FragColor = textureColorBrightness * Color;
} else {
FragColor = Color;
}
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright (c) 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.
*/
#version 330
uniform sampler2D tex;
in vec2 TexCoord;
out vec4 FragColor;
void main() {
vec4 c = texture(tex, TexCoord);
FragColor = c;
}

View File

@@ -0,0 +1,82 @@
/*
* Copyright (c) 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.
*/
#version 400
#define PI 3.1415926535897932384626433832795f
#define UNIT PI / 1024.0f
layout(triangles) in;
layout(triangle_strip, max_vertices = 3) out;
layout(std140) uniform Uniforms {
int cameraYaw;
int cameraPitch;
int centerX;
int centerY;
int zoom;
};
uniform mat4 projectionMatrix;
in ivec3 vPosition[];
in vec4 vColor[];
in vec4 vUv[];
out vec4 Color;
out vec4 fUv;
#include to_screen.glsl
void main() {
ivec3 screenA = toScreen(vPosition[0], cameraYaw, cameraPitch, centerX, centerY, zoom);
ivec3 screenB = toScreen(vPosition[1], cameraYaw, cameraPitch, centerX, centerY, zoom);
ivec3 screenC = toScreen(vPosition[2], cameraYaw, cameraPitch, centerX, centerY, zoom);
if (-screenA.z < 50 || -screenB.z < 50 || -screenC.z < 50) {
// the client does not draw a triangle if any vertex distance is <50
return;
}
vec4 tmp = vec4(screenA.xyz, 1.0);
Color = vColor[0];
fUv = vUv[0];
gl_Position = projectionMatrix * tmp;
EmitVertex();
tmp = vec4(screenB.xyz, 1.0);
Color = vColor[1];
fUv = vUv[1];
gl_Position = projectionMatrix * tmp;
EmitVertex();
tmp = vec4(screenC.xyz, 1.0);
Color = vColor[2];
fUv = vUv[2];
gl_Position = projectionMatrix * tmp;
EmitVertex();
EndPrimitive();
}

View File

@@ -0,0 +1,205 @@
/*
* Copyright (c) 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.
*/
void get_face(uint localId, modelinfo minfo, int cameraYaw, int cameraPitch, int centerX, int centerY, int zoom,
out int prio, out int dis, out ivec4 o1, out ivec4 o2, out ivec4 o3) {
int offset = minfo.offset;
int length = minfo.length;
int flags = minfo.flags;
int radius = (flags & 0x7fffffff) >> 12;
int orientation = flags & 0x7ff;
ivec4 pos = ivec4(minfo.x, minfo.y, minfo.z, 0);
uint ssboOffset;
if (localId < length) {
ssboOffset = localId;
} else {
ssboOffset = 0;
}
ivec4 thisA;
ivec4 thisB;
ivec4 thisC;
// Grab triangle vertices from the correct buffer
if (flags < 0) {
thisA = vb[offset + ssboOffset * 3 ];
thisB = vb[offset + ssboOffset * 3 + 1];
thisC = vb[offset + ssboOffset * 3 + 2];
} else {
thisA = tempvb[offset + ssboOffset * 3 ];
thisB = tempvb[offset + ssboOffset * 3 + 1];
thisC = tempvb[offset + ssboOffset * 3 + 2];
}
ivec4 thisrvA;
ivec4 thisrvB;
ivec4 thisrvC;
int thisPriority, thisDistance;
if (localId < length) {
// rotate for model orientation
thisrvA = rotate(thisA, orientation);
thisrvB = rotate(thisB, orientation);
thisrvC = rotate(thisC, orientation);
// calculate distance to face
thisPriority = (thisA.w >> 16) & 0xff; // all vertices on the face have the same priority
if (radius == 0) {
thisDistance = 0;
} else {
thisDistance = face_distance(thisrvA, thisrvB, thisrvC, cameraYaw, cameraPitch) + radius;
}
// if the face is not culled, it is calculated into priority distance averages
if (face_visible(thisrvA, thisrvB, thisrvC, pos, cameraYaw, cameraPitch, centerX, centerY, zoom)) {
atomicAdd(totalNum[thisPriority], 1);
atomicAdd(totalDistance[thisPriority], thisDistance);
// calculate minimum distance to any face of priority 10 for positioning the 11 faces later
if (thisPriority == 10) {
atomicMin(min10, thisDistance);
}
}
o1 = thisrvA;
o2 = thisrvB;
o3 = thisrvC;
prio = thisPriority;
dis = thisDistance;
} else {
prio = 0;
dis = 0;
}
}
int map_face_priority(uint localId, modelinfo minfo, int thisPriority, int thisDistance, out int prio) {
int length = minfo.length;
// Compute average distances for 0/2, 3/4, and 6/8
int adjPrio;
int prioIdx;
if (localId < length) {
int avg1 = 0;
int avg2 = 0;
int avg3 = 0;
if (totalNum[1] > 0 || totalNum[2] > 0) {
avg1 = (totalDistance[1] + totalDistance[2]) / (totalNum[1] + totalNum[2]);
}
if (totalNum[3] > 0 || totalNum[4] > 0) {
avg2 = (totalDistance[3] + totalDistance[4]) / (totalNum[3] + totalNum[4]);
}
if (totalNum[6] > 0 || totalNum[8] > 0) {
avg3 = (totalDistance[6] + totalDistance[8]) / (totalNum[6] + totalNum[8]);
}
int _min10 = min10;
adjPrio = priority_map(thisPriority, thisDistance, _min10, avg1, avg2, avg3);
int prioIdx = atomicAdd(totalMappedNum[adjPrio], 1);
prio = adjPrio;
return prioIdx;
}
return 0;
}
void insert_dfs(uint localId, modelinfo minfo, int adjPrio, int distance, int prioIdx) {
int length = minfo.length;
if (localId < length) {
// calculate base offset into dfs based on number of faces with a lower priority
int baseOff = count_prio_offset(adjPrio);
// store into face array offset array by unique index
dfs[baseOff + prioIdx] = (int(localId) << 16) | distance;
}
}
void sort_and_insert(uint localId, modelinfo minfo, int thisPriority, int thisDistance, ivec4 thisrvA, ivec4 thisrvB, ivec4 thisrvC) {
/* compute face distance */
int length = minfo.length;
int outOffset = minfo.idx;
int uvOffset = minfo.uvOffset;
int flags = minfo.flags;
ivec4 pos = ivec4(minfo.x, minfo.y, minfo.z, 0);
int start, end, myOffset;
if (localId < length) {
const int priorityOffset = count_prio_offset(thisPriority);
const int numOfPriority = totalMappedNum[thisPriority];
start = priorityOffset; // index of first face with this priority
end = priorityOffset + numOfPriority; // index of last face with this priority
myOffset = priorityOffset;
} else {
start = end = myOffset = 0;
}
if (localId < length) {
// we only have to order faces against others of the same priority
// calculate position this face will be in
for (int i = start; i < end; ++i) {
int d1 = dfs[i];
int theirId = d1 >> 16;
int theirDistance = d1 & 0xffff;
// the closest faces draw last, so have the highest index
// if two faces have the same distance, the one with the
// higher id draws last
if ((theirDistance > thisDistance)
|| (theirDistance == thisDistance && theirId < localId)) {
++myOffset;
}
}
// position vertices in scene and write to out buffer
vout[outOffset + myOffset * 3] = pos + thisrvA;
vout[outOffset + myOffset * 3 + 1] = pos + thisrvB;
vout[outOffset + myOffset * 3 + 2] = pos + thisrvC;
if (uvOffset < 0) {
uvout[outOffset + myOffset * 3] = vec4(0, 0, 0, 0);
uvout[outOffset + myOffset * 3 + 1] = vec4(0, 0, 0, 0);
uvout[outOffset + myOffset * 3 + 2] = vec4(0, 0, 0, 0);
} else if (flags >= 0) {
uvout[outOffset + myOffset * 3] = tempuv[uvOffset + localId * 3];
uvout[outOffset + myOffset * 3 + 1] = tempuv[uvOffset + localId * 3 + 1];
uvout[outOffset + myOffset * 3 + 2] = tempuv[uvOffset + localId * 3 + 2];
} else {
uvout[outOffset + myOffset * 3] = uv[uvOffset + localId * 3];
uvout[outOffset + myOffset * 3 + 1] = uv[uvOffset + localId * 3 + 1];
uvout[outOffset + myOffset * 3 + 2] = uv[uvOffset + localId * 3 + 2];
}
}
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright (c) 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.
*/
/*
* Convert a vertex to screen space
*/
ivec3 toScreen(ivec3 vertex, int cameraYaw, int cameraPitch, int centerX, int centerY, int zoom) {
int yawSin = int(65536.0f * sin(cameraYaw * UNIT));
int yawCos = int(65536.0f * cos(cameraYaw * UNIT));
int pitchSin = int(65536.0f * sin(cameraPitch * UNIT));
int pitchCos = int(65536.0f * cos(cameraPitch * UNIT));
int rotatedX = ((vertex.z * yawSin) + (vertex.x * yawCos)) >> 16;
int rotatedZ = ((vertex.z * yawCos) - (vertex.x * yawSin)) >> 16;
int var13 = ((vertex.y * pitchCos) - (rotatedZ * pitchSin)) >> 16;
int var12 = ((vertex.y * pitchSin) + (rotatedZ * pitchCos)) >> 16;
int x = rotatedX * zoom / var12 + centerX;
int y = var13 * zoom / var12 + centerY;
int z = -var12; // in OpenGL depth is negative
return ivec3(x, y, z);
}

View File

@@ -0,0 +1,125 @@
/*
* Copyright (c) 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.
*/
#version 400
layout (location = 0) in ivec4 VertexPosition;
layout (location = 1) in vec4 uv;
uniform float brightness;
out ivec3 vPosition;
out vec4 vColor;
out vec4 vUv;
vec3 hslToRgb(int hsl) {
int var5 = hsl/128;
float var6 = float(var5 >> 3) / 64.0f + 0.0078125f;
float var8 = float(var5 & 7) / 8.0f + 0.0625f;
int var10 = hsl % 128;
float var11 = float(var10) / 128.0f;
float var13 = var11;
float var15 = var11;
float var17 = var11;
if(var8 != 0.0f) {
float var19;
if(var11 < 0.5f) {
var19 = var11 * (1.0f + var8);
} else {
var19 = var11 + var8 - var11 * var8;
}
float var21 = 2.0f * var11 - var19;
float var23 = var6 + 0.3333333333333333f;
if(var23 > 1.0f) {
var23 -= 1.f;
}
float var27 = var6 - 0.3333333333333333f;
if(var27 < 0.0f) {
var27 += 1.f;
}
if(6.0f * var23 < 1.0f) {
var13 = var21 + (var19 - var21) * 6.0f * var23;
} else if(2.0f * var23 < 1.0f) {
var13 = var19;
} else if(3.0f * var23 < 2.0f) {
var13 = var21 + (var19 - var21) * (0.6666666666666666f - var23) * 6.0f;
} else {
var13 = var21;
}
if(6.0f * var6 < 1.0f) {
var15 = var21 + (var19 - var21) * 6.0f * var6;
} else if(2.0f * var6 < 1.0f) {
var15 = var19;
} else if(3.0f * var6 < 2.0f) {
var15 = var21 + (var19 - var21) * (0.6666666666666666f - var6) * 6.0f;
} else {
var15 = var21;
}
if(6.0f * var27 < 1.0f) {
var17 = var21 + (var19 - var21) * 6.0f * var27;
} else if(2.0f * var27 < 1.0f) {
var17 = var19;
} else if(3.0f * var27 < 2.0f) {
var17 = var21 + (var19 - var21) * (0.6666666666666666f - var27) * 6.0f;
} else {
var17 = var21;
}
}
vec3 rgb = vec3(
pow(var13, brightness),
pow(var15, brightness),
pow(var17, brightness)
);
// I don't think we actually need this
if (rgb == vec3(0, 0, 0)) {
rgb = vec3(0, 0, 1/255.f);
}
return rgb;
}
void main()
{
ivec3 vertex = VertexPosition.xyz;
int ahsl = VertexPosition.w;
int hsl = ahsl & 0xffff;
float a = float(ahsl >> 24 & 0xff) / 255.f;
vec3 rgb = hslToRgb(hsl);
vPosition = vertex;
vColor = vec4(rgb, 1.f - a);
vUv = uv;
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright (c) 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.
*/
#version 330
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;
out vec2 TexCoord;
void main()
{
gl_Position = vec4(aPos, 1.0);
TexCoord = aTexCoord;
}

View File

@@ -0,0 +1,172 @@
/*
* Copyright (c) 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.client.plugins.gpu;
import com.jogamp.nativewindow.AbstractGraphicsConfiguration;
import com.jogamp.nativewindow.NativeWindowFactory;
import com.jogamp.nativewindow.awt.AWTGraphicsConfiguration;
import com.jogamp.nativewindow.awt.JAWTWindow;
import com.jogamp.opengl.GL4;
import com.jogamp.opengl.GLCapabilities;
import com.jogamp.opengl.GLContext;
import com.jogamp.opengl.GLDrawable;
import com.jogamp.opengl.GLDrawableFactory;
import com.jogamp.opengl.GLProfile;
import java.awt.Canvas;
import java.util.function.Function;
import javax.swing.JFrame;
import static net.runelite.client.plugins.gpu.GLUtil.inputStreamToString;
import net.runelite.client.plugins.gpu.template.Template;
import static org.junit.Assert.fail;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
public class ShaderTest
{
private static final String VERTEX_SHADER = "" +
"void main() {" +
" gl_Position = vec4(1.0, 1.0, 1.0, 1.0);" +
"}";
private GL4 gl;
@Before
public void before()
{
Canvas canvas = new Canvas();
JFrame frame = new JFrame();
frame.setSize(100, 100);
frame.add(canvas);
frame.setVisible(true);
GLProfile glProfile = GLProfile.getMaxFixedFunc(true);
GLCapabilities glCaps = new GLCapabilities(glProfile);
AbstractGraphicsConfiguration config = AWTGraphicsConfiguration.create(canvas.getGraphicsConfiguration(),
glCaps, glCaps);
JAWTWindow jawtWindow = (JAWTWindow) NativeWindowFactory.getNativeWindow(canvas, config);
GLDrawableFactory glDrawableFactory = GLDrawableFactory.getFactory(glProfile);
GLDrawable glDrawable = glDrawableFactory.createGLDrawable(jawtWindow);
glDrawable.setRealized(true);
GLContext glContext = glDrawable.createContext(null);
int res = glContext.makeCurrent();
if (res == GLContext.CONTEXT_NOT_CURRENT)
{
fail("error making context current");
}
gl = glContext.getGL().getGL4();
}
@Test
@Ignore
public void testSmall() throws ShaderException
{
int glComputeProgram = gl.glCreateProgram();
int glComputeShader = gl.glCreateShader(gl.GL_COMPUTE_SHADER);
try
{
Function<String, String> func = (s) -> inputStreamToString(getClass().getResourceAsStream(s));
Template template = new Template(func);
String source = template.process(func.apply("comp_small.glsl"));
int line = 0;
for (String str : source.split("\\n"))
{
System.out.println(++line + " " + str);
}
GLUtil.loadComputeShader(gl, glComputeProgram, glComputeShader, source);
}
finally
{
gl.glDeleteShader(glComputeShader);
gl.glDeleteProgram(glComputeProgram);
}
}
@Test
@Ignore
public void testComp() throws ShaderException
{
int glComputeProgram = gl.glCreateProgram();
int glComputeShader = gl.glCreateShader(gl.GL_COMPUTE_SHADER);
try
{
Function<String, String> func = (s) -> inputStreamToString(getClass().getResourceAsStream(s));
Template template = new Template(func);
String source = template.process(func.apply("comp.glsl"));
int line = 0;
for (String str : source.split("\\n"))
{
System.out.println(++line + " " + str);
}
GLUtil.loadComputeShader(gl, glComputeProgram, glComputeShader, source);
}
finally
{
gl.glDeleteShader(glComputeShader);
gl.glDeleteProgram(glComputeProgram);
}
}
@Test
@Ignore
public void testGeom() throws ShaderException
{
int glComputeProgram = gl.glCreateProgram();
int glVertexShader = gl.glCreateShader(gl.GL_VERTEX_SHADER);
int glGeometryShader = gl.glCreateShader(gl.GL_GEOMETRY_SHADER);
int glFragmentShader = gl.glCreateShader(gl.GL_FRAGMENT_SHADER);
try
{
Function<String, String> func = (s) -> inputStreamToString(getClass().getResourceAsStream(s));
Template template = new Template(func);
String source = template.process(func.apply("geom.glsl"));
int line = 0;
for (String str : source.split("\\n"))
{
System.out.println(++line + " " + str);
}
GLUtil.loadShaders(gl, glComputeProgram, glVertexShader, glGeometryShader, glFragmentShader, VERTEX_SHADER, source, "");
}
finally
{
gl.glDeleteShader(glVertexShader);
gl.glDeleteShader(glGeometryShader);
gl.glDeleteShader(glFragmentShader);
gl.glDeleteProgram(glComputeProgram);
}
}
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright (c) 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.client.plugins.gpu.template;
import java.util.function.Function;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
public class TemplateTest
{
private static final String FILE1 = "" +
"test1\n" +
"#include file2\n" +
"test3\n";
private static final String FILE2 = "" +
"test4\n" +
"test5\n";
private static final String RESULT = "" +
"test1\n" +
"test4\n" +
"test5\n" +
"test3\n";
@Test
public void testProcess()
{
Function<String, String> func = (String resource) ->
{
switch (resource)
{
case "file2":
return FILE2;
default:
throw new RuntimeException("unknown resource");
}
};
String out = new Template(func).process(FILE1);
assertEquals(RESULT, out);
}
}