From 035c119f8551268b878c853e23d57bb4baebeff6 Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 20 Apr 2020 10:30:50 -0400 Subject: [PATCH] gpu: add option to disable compute shaders This still gives a noticible performance boost over software rendering as the rasterizing is entirely done on GPU --- .../client/plugins/gpu/GpuPlugin.java | 204 +++++++++++++----- .../client/plugins/gpu/GpuPluginConfig.java | 11 + .../client/plugins/gpu/SceneUploader.java | 90 ++++++-- 3 files changed, 233 insertions(+), 72 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPlugin.java index f5de69b6d8..d7fc8f56d0 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPlugin.java @@ -24,6 +24,7 @@ */ package net.runelite.client.plugins.gpu; +import com.google.common.primitives.Ints; import com.google.inject.Provides; import com.jogamp.nativewindow.awt.AWTGraphicsConfiguration; import com.jogamp.nativewindow.awt.JAWTWindow; @@ -74,7 +75,17 @@ import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.plugins.PluginInstantiationException; import net.runelite.client.plugins.PluginManager; -import static net.runelite.client.plugins.gpu.GLUtil.*; +import static net.runelite.client.plugins.gpu.GLUtil.glDeleteBuffer; +import static net.runelite.client.plugins.gpu.GLUtil.glDeleteFrameBuffer; +import static net.runelite.client.plugins.gpu.GLUtil.glDeleteRenderbuffers; +import static net.runelite.client.plugins.gpu.GLUtil.glDeleteTexture; +import static net.runelite.client.plugins.gpu.GLUtil.glDeleteVertexArrays; +import static net.runelite.client.plugins.gpu.GLUtil.glGenBuffers; +import static net.runelite.client.plugins.gpu.GLUtil.glGenFrameBuffer; +import static net.runelite.client.plugins.gpu.GLUtil.glGenRenderbuffer; +import static net.runelite.client.plugins.gpu.GLUtil.glGenTexture; +import static net.runelite.client.plugins.gpu.GLUtil.glGenVertexArrays; +import static net.runelite.client.plugins.gpu.GLUtil.glGetInteger; import net.runelite.client.plugins.gpu.config.AntiAliasingMode; import net.runelite.client.plugins.gpu.config.UIScalingMode; import net.runelite.client.plugins.gpu.template.Template; @@ -94,6 +105,7 @@ public class GpuPlugin extends Plugin implements DrawCallbacks private static final int MAX_TRIANGLE = 4096; private static final int SMALL_TRIANGLE_COUNT = 512; private static final int FLAG_SCENE_BUFFER = Integer.MIN_VALUE; + private static final int DEFAULT_DISTANCE = 25; static final int MAX_DISTANCE = 90; static final int MAX_FOG_DEPTH = 100; @@ -118,6 +130,8 @@ public class GpuPlugin extends Plugin implements DrawCallbacks @Inject private PluginManager pluginManager; + private boolean useComputeShaders; + private Canvas canvas; private JAWTWindow jawtWindow; private GL4 gl; @@ -231,6 +245,10 @@ public class GpuPlugin extends Plugin implements DrawCallbacks private int centerY; private int yaw; private int pitch; + // fields for non-compute draw + private boolean drawingModel; + private int modelX, modelY, modelZ; + private int modelOrientation; // Uniforms private int uniUseFog; @@ -259,6 +277,7 @@ public class GpuPlugin extends Plugin implements DrawCallbacks { bufferId = uvBufferId = uniformBufferId = tmpBufferId = tmpUvBufferId = tmpModelBufferId = tmpModelBufferSmallId = tmpModelBufferUnorderedId = tmpOutBufferId = tmpOutUvBufferId = -1; unorderedModels = smallModels = largeModels = 0; + drawingModel = false; canvas = client.getCanvas(); @@ -267,6 +286,8 @@ public class GpuPlugin extends Plugin implements DrawCallbacks return false; } + useComputeShaders = config.useComputeShaders(); + canvas.setIgnoreRepaint(true); vertexBuffer = new GpuIntBuffer(); @@ -461,11 +482,15 @@ public class GpuPlugin extends Plugin implements DrawCallbacks template.addInclude(GpuPlugin.class); glProgram = PROGRAM.compile(gl, template); - glComputeProgram = COMPUTE_PROGRAM.compile(gl, template); - glSmallComputeProgram = SMALL_COMPUTE_PROGRAM.compile(gl, template); - glUnorderedComputeProgram = UNORDERED_COMPUTE_PROGRAM.compile(gl, template); glUiProgram = UI_PROGRAM.compile(gl, template); + if (useComputeShaders) + { + glComputeProgram = COMPUTE_PROGRAM.compile(gl, template); + glSmallComputeProgram = SMALL_COMPUTE_PROGRAM.compile(gl, template); + glUnorderedComputeProgram = UNORDERED_COMPUTE_PROGRAM.compile(gl, template); + } + initUniforms(); } @@ -738,8 +763,7 @@ public class GpuPlugin extends Plugin implements DrawCallbacks pitch = client.getCameraPitch(); final Scene scene = client.getScene(); - final int drawDistance = Math.max(0, Math.min(MAX_DISTANCE, config.drawDistance())); - scene.setDrawDistance(drawDistance); + scene.setDrawDistance(getDrawDistance()); } @Override @@ -747,7 +771,17 @@ public class GpuPlugin extends Plugin implements DrawCallbacks SceneTilePaint paint, int tileZ, int tileX, int tileY, int zoom, int centerX, int centerY) { - if (paint.getBufferLen() > 0) + if (!useComputeShaders) + { + targetBufferOffset += sceneUploader.upload(paint, + tileZ, tileX, tileY, + vertexBuffer, uvBuffer, + Perspective.LOCAL_TILE_SIZE * tileX, + Perspective.LOCAL_TILE_SIZE * tileY, + true + ); + } + else if (paint.getBufferLen() > 0) { x = tileX * Perspective.LOCAL_TILE_SIZE; y = 0; @@ -774,7 +808,14 @@ public class GpuPlugin extends Plugin implements DrawCallbacks SceneTileModel model, int tileZ, int tileX, int tileY, int zoom, int centerX, int centerY) { - if (model.getBufferLen() > 0) + if (!useComputeShaders) + { + targetBufferOffset += sceneUploader.upload(model, + tileX, tileY, + vertexBuffer, uvBuffer, + tileX << Perspective.LOCAL_COORD_BITS, tileY << Perspective.LOCAL_COORD_BITS, true); + } + else if (model.getBufferLen() > 0) { x = tileX * Perspective.LOCAL_TILE_SIZE; y = 0; @@ -913,7 +954,7 @@ public class GpuPlugin extends Plugin implements DrawCallbacks null, gl.GL_STREAM_DRAW); - // UBO + // UBO. Only the first 32 bytes get modified here, the rest is the constant sin/cos table. gl.glBindBuffer(gl.GL_UNIFORM_BUFFER, uniformBufferId); uniformBuffer.clear(); uniformBuffer @@ -930,60 +971,63 @@ public class GpuPlugin extends Plugin implements DrawCallbacks gl.glBufferSubData(gl.GL_UNIFORM_BUFFER, 0, uniformBuffer.limit() * Integer.BYTES, uniformBuffer); gl.glBindBuffer(gl.GL_UNIFORM_BUFFER, 0); + gl.glBindBufferBase(gl.GL_UNIFORM_BUFFER, 0, uniformBufferId); + // Draw 3d scene final TextureProvider textureProvider = client.getTextureProvider(); if (textureProvider != null) { - gl.glUniformBlockBinding(glSmallComputeProgram, uniBlockSmall, 0); - gl.glUniformBlockBinding(glComputeProgram, uniBlockLarge, 0); + if (useComputeShaders) + { + gl.glUniformBlockBinding(glSmallComputeProgram, uniBlockSmall, 0); + gl.glUniformBlockBinding(glComputeProgram, uniBlockLarge, 0); - gl.glBindBufferBase(gl.GL_UNIFORM_BUFFER, 0, uniformBufferId); + /* + * Compute is split into two separate programs 'small' and 'large' to + * save on GPU resources. Small will sort <= 512 faces, large will do <= 4096. + */ - /* - * Compute is split into two separate programs 'small' and 'large' to - * save on GPU resources. Small will sort <= 512 faces, large will do <= 4096. - */ + // unordered + gl.glUseProgram(glUnorderedComputeProgram); - // unordered - gl.glUseProgram(glUnorderedComputeProgram); + gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 0, tmpModelBufferUnorderedId); + gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 1, this.bufferId); + gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 2, tmpBufferId); + gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 3, tmpOutBufferId); + gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 4, tmpOutUvBufferId); + gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 5, this.uvBufferId); + gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 6, tmpUvBufferId); - gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 0, tmpModelBufferUnorderedId); - gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 1, this.bufferId); - gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 2, tmpBufferId); - gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 3, tmpOutBufferId); - gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 4, tmpOutUvBufferId); - gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 5, this.uvBufferId); - gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 6, tmpUvBufferId); + gl.glDispatchCompute(unorderedModels, 1, 1); - gl.glDispatchCompute(unorderedModels, 1, 1); + // small + gl.glUseProgram(glSmallComputeProgram); - // small - gl.glUseProgram(glSmallComputeProgram); + gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 0, tmpModelBufferSmallId); + gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 1, this.bufferId); + gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 2, tmpBufferId); + gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 3, tmpOutBufferId); + gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 4, tmpOutUvBufferId); + gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 5, this.uvBufferId); + gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 6, tmpUvBufferId); - gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 0, tmpModelBufferSmallId); - gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 1, this.bufferId); - gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 2, tmpBufferId); - gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 3, tmpOutBufferId); - gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 4, tmpOutUvBufferId); - gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 5, this.uvBufferId); - gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 6, tmpUvBufferId); + gl.glDispatchCompute(smallModels, 1, 1); - gl.glDispatchCompute(smallModels, 1, 1); + // large + gl.glUseProgram(glComputeProgram); - // large - gl.glUseProgram(glComputeProgram); + gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 0, tmpModelBufferId); + gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 1, this.bufferId); + gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 2, tmpBufferId); + gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 3, tmpOutBufferId); + gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 4, tmpOutUvBufferId); + gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 5, this.uvBufferId); + gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 6, tmpUvBufferId); - gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 0, tmpModelBufferId); - gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 1, this.bufferId); - gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 2, tmpBufferId); - gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 3, tmpOutBufferId); - gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 4, tmpOutUvBufferId); - gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 5, this.uvBufferId); - gl.glBindBufferBase(gl.GL_SHADER_STORAGE_BUFFER, 6, tmpUvBufferId); + gl.glDispatchCompute(largeModels, 1, 1); - gl.glDispatchCompute(largeModels, 1, 1); - - gl.glMemoryBarrier(gl.GL_SHADER_STORAGE_BARRIER_BIT); + gl.glMemoryBarrier(gl.GL_SHADER_STORAGE_BARRIER_BIT); + } if (textureArrayId == -1) { @@ -1023,7 +1067,7 @@ public class GpuPlugin extends Plugin implements DrawCallbacks gl.glUseProgram(glProgram); - final int drawDistance = Math.max(0, Math.min(MAX_DISTANCE, config.drawDistance())); + final int drawDistance = getDrawDistance(); final int fogDepth = config.fogDepth(); gl.glUniform1i(uniUseFog, fogDepth > 0 ? 1 : 0); gl.glUniform4f(uniFogColor, (sky >> 16 & 0xFF) / 255f, (sky >> 8 & 0xFF) / 255f, (sky & 0xFF) / 255f, 1f); @@ -1061,15 +1105,17 @@ public class GpuPlugin extends Plugin implements DrawCallbacks gl.glEnable(gl.GL_BLEND); gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA); - // Draw output of compute shaders + // Draw buffers gl.glBindVertexArray(vaoHandle); + // When using compute shaders, draw using the output buffer of the compute. Otherwise + // only use the temporary buffers, which will contain the full scene. gl.glEnableVertexAttribArray(0); - gl.glBindBuffer(gl.GL_ARRAY_BUFFER, tmpOutBufferId); + gl.glBindBuffer(gl.GL_ARRAY_BUFFER, useComputeShaders ? tmpOutBufferId : tmpBufferId); gl.glVertexAttribIPointer(0, 4, gl.GL_INT, 0, 0); gl.glEnableVertexAttribArray(1); - gl.glBindBuffer(gl.GL_ARRAY_BUFFER, tmpOutUvBufferId); + gl.glBindBuffer(gl.GL_ARRAY_BUFFER, useComputeShaders ? tmpOutUvBufferId : tmpUvBufferId); gl.glVertexAttribPointer(1, 4, gl.GL_FLOAT, false, 0, 0); gl.glDrawArrays(gl.GL_TRIANGLES, 0, targetBufferOffset); @@ -1236,7 +1282,7 @@ public class GpuPlugin extends Plugin implements DrawCallbacks @Subscribe public void onGameStateChanged(GameStateChanged gameStateChanged) { - if (gameStateChanged.getGameState() != GameState.LOGGED_IN) + if (!useComputeShaders || gameStateChanged.getGameState() != GameState.LOGGED_IN) { return; } @@ -1328,8 +1374,38 @@ public class GpuPlugin extends Plugin implements DrawCallbacks @Override public void draw(Renderable renderable, int orientation, int pitchSin, int pitchCos, int yawSin, int yawCos, int x, int y, int z, long hash) { + if (!useComputeShaders) + { + Model model = renderable instanceof Model ? (Model) renderable : renderable.getModel(); + if (model != null) + { + model.calculateBoundsCylinder(); + model.calculateExtreme(orientation); + + if (!isVisible(model, orientation, pitchSin, pitchCos, yawSin, yawCos, x, y, z, hash)) + { + return; + } + + client.checkClickbox(model, orientation, pitchSin, pitchCos, yawSin, yawCos, x, y, z, hash); + + modelX = x + client.getCameraX2(); + modelY = y + client.getCameraY2(); + modelZ = z + client.getCameraZ2(); + modelOrientation = orientation; + int triangleCount = model.getTrianglesCount(); + vertexBuffer.ensureCapacity(12 * triangleCount); + uvBuffer.ensureCapacity(12 * triangleCount); + + drawingModel = true; + + renderable.draw(orientation, pitchSin, pitchCos, yawSin, yawCos, x, y, z, hash); + + drawingModel = false; + } + } // Model may be in the scene buffer - if (renderable instanceof Model && ((Model) renderable).getSceneId() == sceneUploader.sceneId) + else if (renderable instanceof Model && ((Model) renderable).getSceneId() == sceneUploader.sceneId) { Model model = (Model) renderable; @@ -1386,7 +1462,7 @@ public class GpuPlugin extends Plugin implements DrawCallbacks int len = 0; for (int i = 0; i < faces; ++i) { - len += sceneUploader.pushFace(model, i, vertexBuffer, uvBuffer); + len += sceneUploader.pushFace(model, i, false, vertexBuffer, uvBuffer, 0, 0, 0, 0); } GpuIntBuffer b = bufferForTriangles(faces); @@ -1411,6 +1487,18 @@ public class GpuPlugin extends Plugin implements DrawCallbacks } } + @Override + public boolean drawFace(Model model, int face) + { + if (!drawingModel) + { + return false; + } + + targetBufferOffset += sceneUploader.pushFace(model, face, true, vertexBuffer, uvBuffer, modelX, modelY, modelZ, modelOrientation); + return true; + } + /** * returns the correct buffer based on triangle count and updates model count * @@ -1445,4 +1533,10 @@ public class GpuPlugin extends Plugin implements DrawCallbacks getScaledValue(t.getScaleX(), width), getScaledValue(t.getScaleY(), height)); } + + private int getDrawDistance() + { + final int limit = useComputeShaders ? MAX_DISTANCE : DEFAULT_DISTANCE; + return Ints.constrainToRange(config.drawDistance(), 0, limit); + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPluginConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPluginConfig.java index bc37634f41..29396dfb11 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPluginConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPluginConfig.java @@ -96,4 +96,15 @@ public interface GpuPluginConfig extends Config { return 0; } + + @ConfigItem( + keyName = "useComputeShaders", + name = "Compute Shaders", + description = "Offloads face sorting to GPU, enabling extended draw distance. Requires plugin restart.", + position = 6 + ) + default boolean useComputeShaders() + { + return true; + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/SceneUploader.java b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/SceneUploader.java index 445f6c60d1..dc11fbc846 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/SceneUploader.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/SceneUploader.java @@ -176,7 +176,10 @@ class SceneUploader sceneTilePaint.setUvBufferOffset(-1); } Point tilePoint = tile.getSceneLocation(); - int len = upload(sceneTilePaint, tile.getRenderLevel(), tilePoint.getX(), tilePoint.getY(), vertexBuffer, uvBuffer); + int len = upload(sceneTilePaint, + tile.getRenderLevel(), tilePoint.getX(), tilePoint.getY(), + vertexBuffer, uvBuffer, + 0, 0, false); sceneTilePaint.setBufferLen(len); offset += len; if (sceneTilePaint.getTexture() != -1) @@ -198,7 +201,10 @@ class SceneUploader sceneTileModel.setUvBufferOffset(-1); } Point tilePoint = tile.getSceneLocation(); - int len = upload(sceneTileModel, tilePoint.getX(), tilePoint.getY(), vertexBuffer, uvBuffer); + int len = upload(sceneTileModel, + tilePoint.getX(), tilePoint.getY(), + vertexBuffer, uvBuffer, + 0, 0, false); sceneTileModel.setBufferLen(len); offset += len; if (sceneTileModel.getTriangleTextureId() != null) @@ -265,12 +271,13 @@ class SceneUploader } } - private int upload(SceneTilePaint tile, int tileZ, int tileX, int tileY, GpuIntBuffer vertexBuffer, GpuFloatBuffer uvBuffer) + int upload(SceneTilePaint tile, int tileZ, int tileX, int tileY, GpuIntBuffer vertexBuffer, GpuFloatBuffer uvBuffer, + int offsetX, int offsetY, boolean padUvs) { final int[][][] tileHeights = client.getTileHeights(); - final int localX = 0; - final int localY = 0; + final int localX = offsetX; + final int localY = offsetY; int swHeight = tileHeights[tileZ][tileX][tileY]; int seHeight = tileHeights[tileZ][tileX + 1][tileY]; @@ -322,7 +329,7 @@ class SceneUploader vertexBuffer.put(vertexCx, vertexCz, vertexCy, c2); vertexBuffer.put(vertexBx, vertexBz, vertexBy, c4); - if (tile.getTexture() != -1) + if (padUvs || tile.getTexture() != -1) { float tex = tile.getTexture() + 1f; uvBuffer.put(tex, 1.0f, 1.0f, 0f); @@ -337,7 +344,8 @@ class SceneUploader return 6; } - private int upload(SceneTileModel sceneTileModel, int tileX, int tileY, GpuIntBuffer vertexBuffer, GpuFloatBuffer uvBuffer) + int upload(SceneTileModel sceneTileModel, int tileX, int tileY, GpuIntBuffer vertexBuffer, GpuFloatBuffer uvBuffer, + int offsetX, int offsetY, boolean padUvs) { final int[] faceX = sceneTileModel.getFaceX(); final int[] faceY = sceneTileModel.getFaceY(); @@ -379,6 +387,7 @@ class SceneUploader cnt += 3; + // vertexes are stored in scene local, convert to tile local int vertexXA = vertexX[triangleA] - baseX; int vertexZA = vertexZ[triangleA] - baseY; @@ -388,13 +397,13 @@ class SceneUploader 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); + vertexBuffer.put(vertexXA + offsetX, vertexY[triangleA], vertexZA + offsetY, colorA); + vertexBuffer.put(vertexXB + offsetX, vertexY[triangleB], vertexZB + offsetY, colorB); + vertexBuffer.put(vertexXC + offsetX, vertexY[triangleC], vertexZC + offsetY, colorC); - if (triangleTextures != null) + if (padUvs || triangleTextures != null) { - if (triangleTextures[i] != -1) + if (triangleTextures != null && triangleTextures[i] != -1) { float tex = triangleTextures[i] + 1f; uvBuffer.put(tex, vertexXA / 128f, vertexZA / 128f, 0f); @@ -438,7 +447,7 @@ class SceneUploader int len = 0; for (int i = 0; i < triangleCount; ++i) { - len += pushFace(model, i, vertexBuffer, uvBuffer); + len += pushFace(model, i, false, vertexBuffer, uvBuffer, 0, 0, 0, 0); } offset += len; @@ -448,7 +457,8 @@ class SceneUploader } } - int pushFace(Model model, int face, GpuIntBuffer vertexBuffer, GpuFloatBuffer uvBuffer) + int pushFace(Model model, int face, boolean padUvs, GpuIntBuffer vertexBuffer, GpuFloatBuffer uvBuffer, + int xOffset, int yOffset, int zOffset, int orientation) { final int[] vertexX = model.getVerticesX(); final int[] vertexY = model.getVerticesY(); @@ -485,6 +495,13 @@ class SceneUploader priority = (facePriorities[face] & 0xff) << 16; } + int sin = 0, cos = 0; + if (orientation != 0) + { + sin = Perspective.SINE[orientation]; + cos = Perspective.COSINE[orientation]; + } + if (color3 == -1) { color2 = color3 = color1; @@ -495,7 +512,7 @@ class SceneUploader vertexBuffer.put(0, 0, 0, 0); vertexBuffer.put(0, 0, 0, 0); - if (faceTextures != null) + if (padUvs || faceTextures != null) { uvBuffer.put(0, 0, 0, 0f); uvBuffer.put(0, 0, 0, 0f); @@ -510,26 +527,65 @@ class SceneUploader b = vertexY[triangleA]; c = vertexZ[triangleA]; + if (orientation != 0) + { + int x = c * sin + a * cos >> 16; + int z = c * cos - a * sin >> 16; + + a = x; + c = z; + } + + a += xOffset; + b += yOffset; + c += zOffset; + vertexBuffer.put(a, b, c, alpha | priority | color1); a = vertexX[triangleB]; b = vertexY[triangleB]; c = vertexZ[triangleB]; + if (orientation != 0) + { + int x = c * sin + a * cos >> 16; + int z = c * cos - a * sin >> 16; + + a = x; + c = z; + } + + a += xOffset; + b += yOffset; + c += zOffset; + vertexBuffer.put(a, b, c, alpha | priority | color2); a = vertexX[triangleC]; b = vertexY[triangleC]; c = vertexZ[triangleC]; + if (orientation != 0) + { + int x = c * sin + a * cos >> 16; + int z = c * cos - a * sin >> 16; + + a = x; + c = z; + } + + a += xOffset; + b += yOffset; + c += zOffset; + vertexBuffer.put(a, b, c, alpha | priority | color3); float[][] u = model.getFaceTextureUCoordinates(); float[][] v = model.getFaceTextureVCoordinates(); float[] uf, vf; - if (faceTextures != null) + if (padUvs || faceTextures != null) { - if (u != null && v != null && (uf = u[face]) != null && (vf = v[face]) != null) + if (faceTextures != null && u != null && v != null && (uf = u[face]) != null && (vf = v[face]) != null) { float texture = faceTextures[face] + 1f; uvBuffer.put(texture, uf[0], vf[0], 0f);