diff --git a/src/main/java/rs117/hd/HdPlugin.java b/src/main/java/rs117/hd/HdPlugin.java index e08fa46dd5..bf215902de 100644 --- a/src/main/java/rs117/hd/HdPlugin.java +++ b/src/main/java/rs117/hd/HdPlugin.java @@ -128,6 +128,7 @@ import rs117.hd.utils.ResourcePath; import rs117.hd.utils.ShaderRecompile; import rs117.hd.utils.buffer.GLBuffer; +import rs117.hd.utils.buffer.GLTextureBuffer; import rs117.hd.utils.jobs.GenericJob; import rs117.hd.utils.jobs.JobSystem; @@ -901,6 +902,7 @@ public ShaderIncludes getShaderIncludes() { var includes = new ShaderIncludes() .addIncludePath(SHADER_PATH) .addInclude("VERSION_HEADER", OSType.getOSType() == OSType.Linux ? LINUX_VERSION_HEADER : WINDOWS_VERSION_HEADER) + .define("TEXEL_SIZE", GLTextureBuffer.isRGBASupported() ? 4 : 3) .define("UI_SCALING_MODE", config.uiScalingMode()) .define("COLOR_BLINDNESS", config.colorBlindness()) .define("APPLY_COLOR_FILTER", configColorFilter != ColorFilter.NONE) diff --git a/src/main/java/rs117/hd/opengl/shader/SceneShaderProgram.java b/src/main/java/rs117/hd/opengl/shader/SceneShaderProgram.java index 1c75140e78..cb2275a09a 100644 --- a/src/main/java/rs117/hd/opengl/shader/SceneShaderProgram.java +++ b/src/main/java/rs117/hd/opengl/shader/SceneShaderProgram.java @@ -4,6 +4,7 @@ import static rs117.hd.HdPlugin.TEXTURE_UNIT_GAME; import static rs117.hd.HdPlugin.TEXTURE_UNIT_SHADOW_MAP; import static rs117.hd.HdPlugin.TEXTURE_UNIT_TILED_LIGHTING_MAP; +import static rs117.hd.renderer.zone.ZoneRenderer.TEXTURE_UNIT_MODEL_DATA; import static rs117.hd.renderer.zone.ZoneRenderer.TEXTURE_UNIT_TEXTURED_FACES; public class SceneShaderProgram extends ShaderProgram { @@ -11,6 +12,7 @@ public class SceneShaderProgram extends ShaderProgram { protected final UniformTexture uniShadowMap = addUniformTexture("shadowMap"); protected final UniformTexture uniTiledLightingTextureArray = addUniformTexture("tiledLightingArray"); protected final UniformTexture uniTextureFaces = addUniformTexture("textureFaces"); + protected final UniformTexture uniModelData = addUniformTexture("modelData"); public SceneShaderProgram() { super(t -> t @@ -25,12 +27,14 @@ protected void initialize() { uniShadowMap.set(TEXTURE_UNIT_SHADOW_MAP); uniTiledLightingTextureArray.set(TEXTURE_UNIT_TILED_LIGHTING_MAP); uniTextureFaces.set(TEXTURE_UNIT_TEXTURED_FACES); + uniModelData.set(TEXTURE_UNIT_MODEL_DATA); } public static class Legacy extends SceneShaderProgram { Legacy() { shaderTemplate.add(GL_GEOMETRY_SHADER, "scene_geom.glsl"); uniTextureFaces.ignoreMissing = true; + uniModelData.ignoreMissing = true; } } } diff --git a/src/main/java/rs117/hd/opengl/shader/ShadowShaderProgram.java b/src/main/java/rs117/hd/opengl/shader/ShadowShaderProgram.java index 1663800a11..bdd8e42197 100644 --- a/src/main/java/rs117/hd/opengl/shader/ShadowShaderProgram.java +++ b/src/main/java/rs117/hd/opengl/shader/ShadowShaderProgram.java @@ -5,11 +5,13 @@ import static org.lwjgl.opengl.GL33C.*; import static rs117.hd.HdPlugin.TEXTURE_UNIT_GAME; +import static rs117.hd.renderer.zone.ZoneRenderer.TEXTURE_UNIT_MODEL_DATA; import static rs117.hd.renderer.zone.ZoneRenderer.TEXTURE_UNIT_TEXTURED_FACES; public abstract class ShadowShaderProgram extends ShaderProgram { protected final UniformTexture uniTextureArray = addUniformTexture("textureArray"); protected final UniformTexture uniTextureFaces = addUniformTexture("textureFaces"); + protected final UniformTexture uniModelData = addUniformTexture("modelData"); protected ShadowMode mode; @@ -23,6 +25,7 @@ public abstract class ShadowShaderProgram extends ShaderProgram { protected void initialize() { uniTextureArray.set(TEXTURE_UNIT_GAME); uniTextureFaces.set(TEXTURE_UNIT_TEXTURED_FACES); + uniModelData.set(TEXTURE_UNIT_MODEL_DATA); } @Override @@ -47,6 +50,8 @@ public static class Legacy extends ShadowShaderProgram { public Legacy setMode(ShadowMode mode) { this.mode = mode; uniTextureArray.ignoreMissing = mode != ShadowMode.DETAILED; + uniTextureFaces.ignoreMissing = true; + uniModelData.ignoreMissing = true; return this; } diff --git a/src/main/java/rs117/hd/renderer/zone/DynamicModelVAO.java b/src/main/java/rs117/hd/renderer/zone/DynamicModelVAO.java index 5e1dccb3c0..cbdf3d66e0 100644 --- a/src/main/java/rs117/hd/renderer/zone/DynamicModelVAO.java +++ b/src/main/java/rs117/hd/renderer/zone/DynamicModelVAO.java @@ -17,6 +17,7 @@ import static rs117.hd.HdPlugin.NVIDIA_GPU; import static rs117.hd.HdPlugin.SUPPORTS_INDIRECT_DRAW; import static rs117.hd.HdPlugin.SUPPORTS_STORAGE_BUFFERS; +import static rs117.hd.renderer.zone.ZoneRenderer.TEXTURE_UNIT_MODEL_DATA; import static rs117.hd.renderer.zone.ZoneRenderer.TEXTURE_UNIT_TEXTURED_FACES; import static rs117.hd.utils.MathUtils.*; import static rs117.hd.utils.buffer.GLBuffer.STORAGE_IMMUTABLE; @@ -44,13 +45,15 @@ public class DynamicModelVAO implements Destructible { private final GLBuffer vboRender; private final GLBuffer vboStaging; - private final GLTextureBuffer tbo; + private final GLTextureBuffer tboF; + private final GLTextureBuffer tboM; private final ArrayDeque usedViews = new ArrayDeque<>(); private final ArrayDeque freeViews = new ArrayDeque<>(); private final GLMappedBufferIntWriter vboWriter; - private final GLMappedBufferIntWriter tboWriter; + private final GLMappedBufferIntWriter tboFWriter; + private final GLMappedBufferIntWriter tboMWriter; private boolean isMapped = false; private int[] drawOffsets = new int[16]; @@ -81,15 +84,18 @@ public class DynamicModelVAO implements Destructible { } this.vboWriter = new GLMappedBufferIntWriter(this.vboStaging); - this.tbo = new GLTextureBuffer("VAO::TBO::" + name, GL_STREAM_DRAW, STORAGE_PERSISTENT | STORAGE_IMMUTABLE | STORAGE_WRITE); - this.tboWriter = new GLMappedBufferIntWriter(this.tbo); + this.tboF = new GLTextureBuffer("VAO::TexturedFaces::" + name, GL_STREAM_DRAW, STORAGE_PERSISTENT | STORAGE_IMMUTABLE | STORAGE_WRITE); + this.tboM = new GLTextureBuffer("VAO::ModelData::" + name, GL_STREAM_DRAW, STORAGE_PERSISTENT | STORAGE_IMMUTABLE | STORAGE_WRITE); + this.tboFWriter = new GLMappedBufferIntWriter(this.tboF); + this.tboMWriter = new GLMappedBufferIntWriter(this.tboM); } public boolean hasStagingBuffer() { return vboRender != vboStaging; } void initialize() { vao = glGenVertexArrays(); - tbo.initialize(INITIAL_SIZE); + tboF.initialize(INITIAL_SIZE); + tboM.initialize(INITIAL_SIZE); vboRender.initialize(INITIAL_SIZE); if (vboRender != vboStaging) vboStaging.initialize(INITIAL_SIZE); @@ -143,7 +149,8 @@ void bindRenderVAO() { void map() { vboWriter.map(false); - tboWriter.map(false); + tboFWriter.map(false); + tboMWriter.map(false); reset(); isMapped = true; @@ -152,7 +159,8 @@ void map() { synchronized void unmap(boolean coalesce) { final int renderVBOId = vboRender.id; long vboWrittenBytes = vboWriter.flush(); - tboWriter.flush(); + tboFWriter.flush(); + tboMWriter.flush(); if (drawRangeCount > 0) { mergeRanges(); @@ -192,10 +200,12 @@ synchronized void unmap(boolean coalesce) { @Override public void destroy() { vboWriter.destroy(); - tboWriter.destroy(); + tboFWriter.destroy(); + tboMWriter.destroy(); vboRender.destroy(); vboStaging.destroy(); - tbo.destroy(); + tboF.destroy(); + tboM.destroy(); if (vao != 0) glDeleteVertexArrays(vao); @@ -231,9 +241,11 @@ public synchronized View beginDraw(int drawIdx, int faceCount) { if (view == null) view = new View(); view.vbo = vboWriter.reserve(faceCount * 3 * VERT_SIZE_INTS); - view.tbo = tboWriter.reserve(faceCount * 9); + view.tboF = tboFWriter.reserve(faceCount * 4); + view.tboM = tboMWriter.reserve(4); view.vao = vao; - view.tboTexId = tbo.getTexId(); + view.tboFId = tboF.getTexId(); + view.tboMId = tboM.getTexId(); view.drawIdx = drawIdx; return view; @@ -252,7 +264,7 @@ private synchronized void endDraw(View view) { // Clear ReservedViews before returning to pool view.vbo = null; - view.tbo = null; + view.tboF = null; usedViews.add(view); } @@ -280,7 +292,8 @@ void draw(CommandBuffer cmd) { return; cmd.BindVertexArray(vao); - cmd.BindTextureUnit(GL_TEXTURE_BUFFER, tbo.getTexId(), TEXTURE_UNIT_TEXTURED_FACES); + cmd.BindTextureUnit(GL_TEXTURE_BUFFER, tboF.getTexId(), TEXTURE_UNIT_TEXTURED_FACES); + cmd.BindTextureUnit(GL_TEXTURE_BUFFER, tboM.getTexId(), TEXTURE_UNIT_MODEL_DATA); if (drawRangeCount == 1) { if (GL_CAPS.OpenGL40 && SUPPORTS_INDIRECT_DRAW) { @@ -307,9 +320,11 @@ void reset() { public final class View { public ReservedView vbo; - public ReservedView tbo; + public ReservedView tboF; + public ReservedView tboM; public int vao; - public int tboTexId; + public int tboFId; + public int tboMId; private int drawIdx; public int getStartOffset() { diff --git a/src/main/java/rs117/hd/renderer/zone/ModelStreamingManager.java b/src/main/java/rs117/hd/renderer/zone/ModelStreamingManager.java index 7b9a941558..54533d0dec 100644 --- a/src/main/java/rs117/hd/renderer/zone/ModelStreamingManager.java +++ b/src/main/java/rs117/hd/renderer/zone/ModelStreamingManager.java @@ -328,12 +328,15 @@ private void uploadTempModel( (!sceneManager.isRoot(ctx) || zone.inShadowFrustum) ) { final DynamicModelVAO.View shadowView = ctx.beginDraw(VAO_SHADOW, culledFaces.length); + int shadowModelIdx = SceneUploader.writeModelData(shadowView.tboM.getBuffer(), x, y, z, m, modelOverride); sceneUploader.uploadTempModel( culledFaces, m, modelOverride, preOrientation, orientation, + shadowModelIdx, + shadowModelIdx, true, shadowView, shadowView @@ -351,12 +354,17 @@ private void uploadTempModel( final DynamicModelVAO.View opaqueView = ctx.beginDraw(isPlayer ? VAO_PLAYER : VAO_OPAQUE, drawIndex, opaqueFaceCount); final DynamicModelVAO.View alphaView = alphaFaceCount > 0 ? ctx.beginDraw(VAO_ALPHA, alphaFaceCount) : opaqueView; + final int opaqueModelIdx = SceneUploader.writeModelData(opaqueView.tboM.getBuffer(), x, y, z, m, modelOverride); + final int alphaModelIdx = alphaFaceCount > 0 ? SceneUploader.writeModelData(alphaView.tboM.getBuffer(), x, y, z, m, modelOverride) : opaqueModelIdx; + sceneUploader.uploadTempModel( visibleFaces, m, modelOverride, preOrientation, orientation, + opaqueModelIdx, + alphaModelIdx, isSquashed, opaqueView, alphaView @@ -590,12 +598,15 @@ private void uploadDynamicModel( (!sceneManager.isRoot(ctx) || zone.inShadowFrustum) ) { final DynamicModelVAO.View shadowView = ctx.beginDraw(VAO_SHADOW, culledFaces.length); + final int shadowModelIdx = SceneUploader.writeModelData(shadowView.tboM.getBuffer(), x, y, z, m, modelOverride); sceneUploader.uploadTempModel( culledFaces, m, modelOverride, preOrientation, orient, + shadowModelIdx, + shadowModelIdx, true, shadowView, shadowView @@ -610,12 +621,17 @@ private void uploadDynamicModel( final DynamicModelVAO.View opaqueView = ctx.beginDraw(VAO_OPAQUE, drawIndex, opaqueFaceCount); final DynamicModelVAO.View alphaView = alphaFaceCount > 0 ? ctx.beginDraw(VAO_ALPHA, alphaFaceCount) : opaqueView; + final int opaqueModelIdx = SceneUploader.writeModelData(opaqueView.tboM.getBuffer(), x, y, z, m, modelOverride); + final int alphaModelIdx = alphaFaceCount > 0 ? SceneUploader.writeModelData(alphaView.tboM.getBuffer(), x, y, z, m, modelOverride) : opaqueModelIdx; + sceneUploader.uploadTempModel( visibleFaces, m, modelOverride, preOrientation, orient, + opaqueModelIdx, + alphaModelIdx, isSquashed, opaqueView, alphaView diff --git a/src/main/java/rs117/hd/renderer/zone/SceneUploader.java b/src/main/java/rs117/hd/renderer/zone/SceneUploader.java index 160bab014e..637b3b5616 100644 --- a/src/main/java/rs117/hd/renderer/zone/SceneUploader.java +++ b/src/main/java/rs117/hd/renderer/zone/SceneUploader.java @@ -24,6 +24,7 @@ */ package rs117.hd.renderer.zone; +import java.nio.IntBuffer; import java.util.HashSet; import java.util.Set; import javax.inject.Inject; @@ -196,7 +197,8 @@ public void uploadZone(ZoneSceneContext ctx, Zone zone, int mzx, int mzz) throws var vb = zone.vboO != null ? new GpuIntBuffer(zone.vboO.mapped()) : null; var ab = zone.vboA != null ? new GpuIntBuffer(zone.vboA.mapped()) : null; var fb = zone.tboF != null ? new GpuIntBuffer(zone.tboF.mapped()) : null; - assert fb != null; + var md = zone.tboF != null ? new GpuIntBuffer(zone.tboM.mapped()) : null; + assert fb != null && md != null; roofIds.clear(); for (int level = 0; level <= 3; ++level) { @@ -217,13 +219,13 @@ public void uploadZone(ZoneSceneContext ctx, Zone zone, int mzx, int mzz) throws this.level = z; if (z == 0) { - uploadZoneLevel(ctx, zone, mzx, mzz, 0, false, roofIds, vb, ab, fb); - uploadZoneLevel(ctx, zone, mzx, mzz, 0, true, roofIds, vb, ab, fb); - uploadZoneLevel(ctx, zone, mzx, mzz, 1, true, roofIds, vb, ab, fb); - uploadZoneLevel(ctx, zone, mzx, mzz, 2, true, roofIds, vb, ab, fb); - uploadZoneLevel(ctx, zone, mzx, mzz, 3, true, roofIds, vb, ab, fb); + uploadZoneLevel(ctx, zone, mzx, mzz, 0, false, roofIds, vb, ab, fb, md); + uploadZoneLevel(ctx, zone, mzx, mzz, 0, true, roofIds, vb, ab, fb, md); + uploadZoneLevel(ctx, zone, mzx, mzz, 1, true, roofIds, vb, ab, fb, md); + uploadZoneLevel(ctx, zone, mzx, mzz, 2, true, roofIds, vb, ab, fb, md); + uploadZoneLevel(ctx, zone, mzx, mzz, 3, true, roofIds, vb, ab, fb, md); } else { - uploadZoneLevel(ctx, zone, mzx, mzz, z, false, roofIds, vb, ab, fb); + uploadZoneLevel(ctx, zone, mzx, mzz, z, false, roofIds, vb, ab, fb, md); } if (vb != null) { @@ -249,7 +251,8 @@ private void uploadZoneLevel( Set roofIds, GpuIntBuffer vb, GpuIntBuffer ab, - GpuIntBuffer fb + GpuIntBuffer fb, + GpuIntBuffer md ) throws InterruptedException { int ridx = 0; @@ -257,7 +260,7 @@ private void uploadZoneLevel( for (int id : roofIds) { int pos = vb != null ? vb.position() : 0; - uploadZoneLevelRoof(ctx, zone, mzx, mzz, level, id, visbelow, vb, ab, fb); + uploadZoneLevelRoof(ctx, zone, mzx, mzz, level, id, visbelow, vb, ab, fb, md); int endpos = vb != null ? vb.position() : 0; @@ -270,7 +273,7 @@ private void uploadZoneLevel( } // upload everything else - uploadZoneLevelRoof(ctx, zone, mzx, mzz, level, 0, visbelow, vb, ab, fb); + uploadZoneLevelRoof(ctx, zone, mzx, mzz, level, 0, visbelow, vb, ab, fb, md); } private void uploadZoneLevelRoof( @@ -283,7 +286,8 @@ private void uploadZoneLevelRoof( boolean visbelow, GpuIntBuffer vb, GpuIntBuffer ab, - GpuIntBuffer fb + GpuIntBuffer fb, + GpuIntBuffer md ) throws InterruptedException { this.basex = (mzx - (ctx.sceneOffset >> 3)) << 10; this.basez = (mzz - (ctx.sceneOffset >> 3)) << 10; @@ -317,7 +321,7 @@ private void uploadZoneLevelRoof( this.rid = rid; if (onBeforeProcessTile != null) onBeforeProcessTile.invoke(t, false); - uploadZoneTile(ctx, zone, t, false, false, vb, ab, fb); + uploadZoneTile(ctx, zone, t, false, false, vb, ab, fb, md); } } } @@ -344,7 +348,7 @@ private void uploadZoneWater( if (t != null) { if (onBeforeProcessTile != null) onBeforeProcessTile.invoke(t, false); - uploadZoneTile(ctx, zone, t, false, true, vb, null, fb); + uploadZoneTile(ctx, zone, t, false, true, vb, null, fb, null); } } } @@ -464,7 +468,8 @@ private void uploadZoneTile( boolean onlyWaterSurface, GpuIntBuffer vertexBuffer, GpuIntBuffer alphaBuffer, - GpuIntBuffer textureBuffer + GpuIntBuffer textureBuffer, + GpuIntBuffer modelBuffer ) { var tilePoint = t.getSceneLocation(); int tileExX = tilePoint.getX() + ctx.sceneOffset; @@ -496,11 +501,11 @@ private void uploadZoneTile( uploadTileModel(ctx, t, model, onlyWaterSurface, tileExX, tileExY, tileZ, basex, basez, vertexBuffer, textureBuffer); if (!onlyWaterSurface) - uploadZoneTileRenderables(ctx, zone, t, vertexBuffer, alphaBuffer, textureBuffer); + uploadZoneTileRenderables(ctx, zone, t, vertexBuffer, alphaBuffer, textureBuffer, modelBuffer); Tile bridge = t.getBridge(); if (bridge != null) - uploadZoneTile(ctx, zone, bridge, true, onlyWaterSurface, vertexBuffer, alphaBuffer, textureBuffer); + uploadZoneTile(ctx, zone, bridge, true, onlyWaterSurface, vertexBuffer, alphaBuffer, textureBuffer, modelBuffer); } private void uploadZoneTileRenderables( @@ -509,7 +514,8 @@ private void uploadZoneTileRenderables( Tile t, GpuIntBuffer vertexBuffer, GpuIntBuffer alphaBuffer, - GpuIntBuffer textureBuffer + GpuIntBuffer textureBuffer, + GpuIntBuffer modelBuffer ) { WallObject wallObject = t.getWallObject(); if (wallObject != null && renderCallbackManager.drawObject(ctx.scene, wallObject)) { @@ -533,7 +539,8 @@ private void uploadZoneTileRenderables( wallObject.getId(), vertexBuffer, alphaBuffer, - textureBuffer + textureBuffer, + modelBuffer ); Renderable renderable2 = wallObject.getRenderable2(); @@ -555,7 +562,8 @@ private void uploadZoneTileRenderables( wallObject.getId(), vertexBuffer, alphaBuffer, - textureBuffer + textureBuffer, + modelBuffer ); } @@ -582,7 +590,8 @@ private void uploadZoneTileRenderables( decorativeObject.getId(), vertexBuffer, alphaBuffer, - textureBuffer + textureBuffer, + modelBuffer ); Renderable renderable2 = decorativeObject.getRenderable2(); @@ -604,7 +613,8 @@ private void uploadZoneTileRenderables( decorativeObject.getId(), vertexBuffer, alphaBuffer, - textureBuffer + textureBuffer, + modelBuffer ); } @@ -626,7 +636,8 @@ private void uploadZoneTileRenderables( groundObject.getId(), vertexBuffer, alphaBuffer, - textureBuffer + textureBuffer, + modelBuffer ); } @@ -659,7 +670,8 @@ private void uploadZoneTileRenderables( gameObject.getId(), vertexBuffer, alphaBuffer, - textureBuffer + textureBuffer, + modelBuffer ); } } @@ -688,6 +700,7 @@ private void estimateRenderableSize(Zone z, Renderable r, ModelOverride modelOve z.sizeA += faceCount; } z.sizeF += faceCount; + z.sizeM++; } private void uploadZoneRenderable( @@ -708,7 +721,8 @@ private void uploadZoneRenderable( int id, GpuIntBuffer opaqueBuffer, GpuIntBuffer alphaBuffer, - GpuIntBuffer textureBuffer + GpuIntBuffer textureBuffer, + GpuIntBuffer modelBuffer ) { Model model; if (r instanceof Model) { @@ -742,7 +756,8 @@ private void uploadZoneRenderable( x - basex, y, z - basez, opaqueBuffer, alphaBuffer, - textureBuffer + textureBuffer, + modelBuffer ); } catch (Throwable ex) { log.warn( @@ -777,6 +792,7 @@ private void uploadZoneRenderable( materialManager, zone.glVaoA, zone.tboF.getTexId(), + zone.tboM.getTexId(), model, modelOverride, alphaStart, alphaEnd, x - basex, y, z - basez, lx, lz, ux, uz, @@ -1341,6 +1357,19 @@ private void uploadTileModel( } } + public static final int MODEL_DATA_SIZE = 4; + + public static int writeModelData(IntBuffer modelBuffer, int x, int y, int z, Model model, ModelOverride override) { + int modelIdx = modelBuffer.position() / MODEL_DATA_SIZE; + modelBuffer + .put(x) + .put(y) + .put(z) + .put(model.getModelHeight()); + assert modelBuffer.position() % MODEL_DATA_SIZE == 0; + return modelIdx + 1; + } + // scene upload private int uploadStaticModel( ZoneSceneContext ctx, @@ -1352,7 +1381,8 @@ private int uploadStaticModel( int x, int y, int z, GpuIntBuffer opaqueBuffer, GpuIntBuffer alphaBuffer, - GpuIntBuffer textureBuffer + GpuIntBuffer textureBuffer, + GpuIntBuffer modelBuffer ) { if (writeCache == null) writeCache = new VertexWriteCache.Collection(); @@ -1442,6 +1472,8 @@ private int uploadStaticModel( final Material baseMaterial = modelOverride.baseMaterial; final Material textureMaterial = modelOverride.textureMaterial; + final int modelIdx = writeModelData(modelBuffer.getBuffer(), x, y, z, model, modelOverride); + int len = 0; for (int face = 0; face < faceCount; ++face) { int color1 = color1s[face]; @@ -1673,31 +1705,27 @@ private int uploadStaticModel( color2 |= packedAlphaBiasHsl; color3 |= packedAlphaBiasHsl; - final int texturedFaceIdx = tb.putFace( - color1, color2, color3, - materialData, materialData, materialData, - 0, 0, 0 - ); + final int texturedFaceIdx = tb.putModelFace(color1, color2, color3, materialData); vb.putStaticVertex( vx1, vy1, vz1, faceUVs[0], faceUVs[1], faceUVs[2], modelNormals[0], modelNormals[1], modelNormals[2], - texturedFaceIdx + texturedFaceIdx, modelIdx ); vb.putStaticVertex( vx2, vy2, vz2, faceUVs[4], faceUVs[5], faceUVs[6], modelNormals[3], modelNormals[4], modelNormals[5], - texturedFaceIdx + texturedFaceIdx, modelIdx ); vb.putStaticVertex( vx3, vy3, vz3, faceUVs[8], faceUVs[9], faceUVs[10], modelNormals[6], modelNormals[7], modelNormals[8], - texturedFaceIdx + texturedFaceIdx, modelIdx ); len += 3; } @@ -1932,6 +1960,8 @@ public void uploadTempModel( ModelOverride modelOverride, int preOrientation, int orientation, + int opaqueModelIdx, + int alphaModelIdx, boolean isShadow, DynamicModelVAO.View opaqueView, DynamicModelVAO.View alphaView @@ -1941,8 +1971,8 @@ public void uploadTempModel( writeCache.setOutputBuffers( opaqueView.vbo.getBuffer(), alphaView.vbo.getBuffer(), - opaqueView.tbo.getBuffer(), - alphaView.tbo.getBuffer() + opaqueView.tboF.getBuffer(), + alphaView.tboF.getBuffer() ); final int[] indices1 = model.getFaceIndices1(); @@ -2095,29 +2125,26 @@ else if (color3 == -1) color2 |= packedAlphaBiasHsl; color3 |= packedAlphaBiasHsl; - final int texturedFaceIdx = tb.putFace( - color1, color2, color3, - materialData, materialData, materialData, - 0, 0, 0 - ); + final int modelIdx = hasAlpha ? alphaModelIdx : opaqueModelIdx; + final int texturedFaceIdx = tb.putModelFace(color1, color2, color3, materialData); vb.putVertex( modelLocalI[vertexOffsetA], modelLocalI[vertexOffsetA + 1], modelLocalI[vertexOffsetA + 2], faceUVs[0], faceUVs[1], faceUVs[2], faceNormals[0], faceNormals[1], faceNormals[2], - texturedFaceIdx + texturedFaceIdx, modelIdx ); vb.putVertex( modelLocalI[vertexOffsetB], modelLocalI[vertexOffsetB + 1], modelLocalI[vertexOffsetB + 2], faceUVs[4], faceUVs[5], faceUVs[6], faceNormals[3], faceNormals[4], faceNormals[5], - texturedFaceIdx + texturedFaceIdx, modelIdx ); vb.putVertex( modelLocalI[vertexOffsetC], modelLocalI[vertexOffsetC + 1], modelLocalI[vertexOffsetC + 2], faceUVs[8], faceUVs[9], faceUVs[10], faceNormals[6], faceNormals[7], faceNormals[8], - texturedFaceIdx + texturedFaceIdx, modelIdx ); } diff --git a/src/main/java/rs117/hd/renderer/zone/VertexWriteCache.java b/src/main/java/rs117/hd/renderer/zone/VertexWriteCache.java index b72914f70c..6997310538 100644 --- a/src/main/java/rs117/hd/renderer/zone/VertexWriteCache.java +++ b/src/main/java/rs117/hd/renderer/zone/VertexWriteCache.java @@ -38,7 +38,7 @@ private void flushAndGrow() { stagingBuffer = new int[min(stagingBuffer.length * 2, maxCapacity)]; } - public int putFace( + public int putStaticFace( int alphaBiasHslA, int alphaBiasHslB, int alphaBiasHslC, int materialDataA, int materialDataB, int materialDataC, int terrainDataA, int terrainDataB, int terrainDataC @@ -46,7 +46,7 @@ public int putFace( if (stagingPosition + 9 > stagingBuffer.length) flushAndGrow(); - final int textureFaceIdx = (outputBuffer.position() + stagingPosition) / 3; + final int textureFaceIdx = outputBuffer.position() + stagingPosition; final int[] stagingBuffer = this.stagingBuffer; final int stagingPosition = this.stagingPosition; @@ -64,14 +64,32 @@ public int putFace( this.stagingPosition += 9; - return textureFaceIdx; + return textureFaceIdx << 1; + } + + public int putModelFace(int alphaBiasHslA, int alphaBiasHslB, int alphaBiasHslC, int materialData) { + if (stagingPosition + 4 > stagingBuffer.length) + flushAndGrow(); + + final int textureFaceIdx = outputBuffer.position() + stagingPosition; + + final int[] stagingBuffer = this.stagingBuffer; + final int stagingPosition = this.stagingPosition; + + stagingBuffer[stagingPosition] = alphaBiasHslA; + stagingBuffer[stagingPosition + 1] = alphaBiasHslB; + stagingBuffer[stagingPosition + 2] = alphaBiasHslC; + stagingBuffer[stagingPosition + 3] = materialData; + + this.stagingPosition += 4; + return 1 | textureFaceIdx << 1; } public void putVertex( int x, int y, int z, float u, float v, float w, int nx, int ny, int nz, - int textureFaceIdx + int textureFaceIdx, int modelIdx ) { if (stagingPosition + 8 > stagingBuffer.length) flushAndGrow(); @@ -83,9 +101,9 @@ public void putVertex( stagingBuffer[stagingPosition + 1] = y; stagingBuffer[stagingPosition + 2] = z; stagingBuffer[stagingPosition + 3] = float16(v) << 16 | float16(u); - stagingBuffer[stagingPosition + 4] = float16(w); + stagingBuffer[stagingPosition + 4] = modelIdx << 16 | float16(w); stagingBuffer[stagingPosition + 5] = (ny & 0xFFFF) << 16 | nx & 0xFFFF; - stagingBuffer[stagingPosition + 6] = nz & 0xFFFF; + stagingBuffer[stagingPosition + 6] = (modelIdx & 0xFFFF) << 16 | nz & 0xFFFF; stagingBuffer[stagingPosition + 7] = textureFaceIdx; this.stagingPosition += 8; @@ -95,7 +113,7 @@ public void putStaticVertex( int x, int y, int z, float u, float v, float w, int nx, int ny, int nz, - int textureFaceIdx + int textureFaceIdx, int modelIdx ) { if (stagingPosition + 7 > stagingBuffer.length) flushAndGrow(); @@ -109,7 +127,7 @@ public void putStaticVertex( stagingBuffer[stagingPosition + 3] = float16(w); // Unnormalized normals, assumed to be within short max stagingBuffer[stagingPosition + 4] = (ny & 0xFFFF) << 16 | nx & 0xFFFF; - stagingBuffer[stagingPosition + 5] = nz & 0xFFFF; + stagingBuffer[stagingPosition + 5] = (modelIdx & 0xFFFF) << 16 | nz & 0xFFFF; stagingBuffer[stagingPosition + 6] = textureFaceIdx; this.stagingPosition += 7; diff --git a/src/main/java/rs117/hd/renderer/zone/Zone.java b/src/main/java/rs117/hd/renderer/zone/Zone.java index 97f8004142..be926450cd 100644 --- a/src/main/java/rs117/hd/renderer/zone/Zone.java +++ b/src/main/java/rs117/hd/renderer/zone/Zone.java @@ -32,6 +32,7 @@ import static rs117.hd.HdPlugin.GL_CAPS; import static rs117.hd.HdPlugin.SUPPORTS_INDIRECT_DRAW; import static rs117.hd.HdPlugin.checkGLErrors; +import static rs117.hd.renderer.zone.ZoneRenderer.TEXTURE_UNIT_MODEL_DATA; import static rs117.hd.renderer.zone.ZoneRenderer.TEXTURE_UNIT_TEXTURED_FACES; import static rs117.hd.renderer.zone.ZoneRenderer.eboAlpha; import static rs117.hd.utils.MathUtils.*; @@ -53,6 +54,10 @@ public class Zone implements Destructible { // terrainData ivec3 public static final int TEXTURE_SIZE = 36; + // position vec3 + // height float + public static final int MODEL_DATA_SIZE = 16; + // Metadata format // worldViewIndex int int // sceneOffset int vec2(x, y) @@ -67,10 +72,10 @@ public class Zone implements Destructible { public int glVaoA; public int bufLenA; - public int sizeO, sizeA, sizeF; + public int sizeO, sizeA, sizeF, sizeM; @Nullable public GLBuffer vboO, vboA, vboM; - public GLTextureBuffer tboF; + public GLTextureBuffer tboF, tboM; public boolean initialized; // whether the zone vao and vbos are ready public boolean cull; // whether the zone is queued for deletion @@ -97,7 +102,7 @@ public class Zone implements Destructible { final List alphaModels = new ArrayList<>(0); final ConcurrentLinkedQueue pendingModelJobs = new ConcurrentLinkedQueue<>(); - public void initialize(GLBuffer o, GLBuffer a, GLTextureBuffer f) { + public void initialize(GLBuffer o, GLBuffer a, GLTextureBuffer f, GLTextureBuffer m) { assert glVao == 0; assert glVaoA == 0; if (o == null && a == null || f == null) @@ -119,6 +124,7 @@ public void initialize(GLBuffer o, GLBuffer a, GLTextureBuffer f) { } tboF = f; + tboM = m; } public static void freeZones(@Nullable Zone[][] zones) { @@ -160,6 +166,11 @@ public void destroy() { tboF = null; } + if (tboM != null) { + tboM.destroy(); + tboM = null; + } + if (glVao != 0) { glDeleteVertexArrays(glVao); glVao = 0; @@ -218,6 +229,8 @@ public void unmap() { vboA.unmap(); if (tboF != null) tboF.unmap(); + if(tboM != null) + tboM.unmap(); if (vboO != null) { this.bufLen = vboO.mapped().byteView().position() / VERT_SIZE; @@ -372,6 +385,7 @@ void renderOpaque(CommandBuffer cmd, WorldViewContext ctx, boolean roofShadows) lastDrawMode = STATIC_UNSORTED; lastVao = glVao; lastTboF = tboF.getTexId(); + lastTboM = tboM.getTexId(); flush(cmd); } @@ -386,6 +400,7 @@ void renderOpaqueLevel(CommandBuffer cmd, int level) { lastDrawMode = STATIC_UNSORTED; lastVao = glVao; lastTboF = tboF.getTexId(); + lastTboM = tboM.getTexId(); flush(cmd); } @@ -411,6 +426,7 @@ public static class AlphaModel { short rid; int vao; int tboF; + int tboM; byte level; byte lx, lz, ux, uz; // lower/upper zone coords byte zofx, zofz; // for temp alpha models, offset of source zone from target zone @@ -443,7 +459,8 @@ boolean isTemp() { void setView(DynamicModelVAO.View view) { vao = view.vao; - tboF = view.tboTexId; + tboF = view.tboFId; + tboM = view.tboMId; startpos = view.getStartOffset(); endpos = view.getEndOffset(); } @@ -456,6 +473,7 @@ void addAlphaModel( MaterialManager materialManager, int vao, int tboF, + int tboM, Model model, ModelOverride modelOverride, int startpos, @@ -481,6 +499,7 @@ void addAlphaModel( m.z = (short) z; m.vao = vao; m.tboF = tboF; + m.tboM = tboM; m.rid = (short) rid; m.level = (byte) level; if (lx > -1) { @@ -657,6 +676,7 @@ synchronized void postAlphaPass() { private static int lastDrawMode; private static int lastVao; private static int lastTboF; + private static int lastTboM; private static int lastzx, lastzz; private static final class AlphaSortPredicate implements ToIntFunction { @@ -747,6 +767,7 @@ void renderAlpha( if (lastDrawMode != drawMode || lastVao != m.vao || lastTboF != m.tboF || + lastTboM != m.tboM || lastzx != (zx - m.zofx) || lastzz != (zz - m.zofz) ) { @@ -754,6 +775,7 @@ void renderAlpha( lastDrawMode = drawMode; lastVao = m.vao; lastTboF = m.tboF; + lastTboM = m.tboM; lastzx = zx - m.zofx; lastzz = zz - m.zofz; } @@ -797,6 +819,7 @@ private void flush(CommandBuffer cmd) { long byteOffset = 4L * (eboAlphaOffset - vertexCount); cmd.BindVertexArray(lastVao, eboAlpha); cmd.BindTextureUnit(GL_TEXTURE_BUFFER, lastTboF, TEXTURE_UNIT_TEXTURED_FACES); + cmd.BindTextureUnit(GL_TEXTURE_BUFFER, lastTboM, TEXTURE_UNIT_MODEL_DATA); // The EBO & IDO is bound by in ZoneRenderer if (GL_CAPS.OpenGL40 && SUPPORTS_INDIRECT_DRAW) { cmd.DrawElementsIndirect(GL_TRIANGLES, vertexCount, (int) (byteOffset / 4L), ZoneRenderer.indirectDrawCmdsStaging); @@ -809,6 +832,7 @@ private void flush(CommandBuffer cmd) { convertForDraw(lastDrawMode == STATIC_UNSORTED ? VERT_SIZE : DynamicModelVAO.VERT_SIZE); cmd.BindVertexArray(lastVao); cmd.BindTextureUnit(GL_TEXTURE_BUFFER, lastTboF, TEXTURE_UNIT_TEXTURED_FACES); + cmd.BindTextureUnit(GL_TEXTURE_BUFFER, lastTboM, TEXTURE_UNIT_MODEL_DATA); if (drawIdx == 1) { if (GL_CAPS.OpenGL40 && SUPPORTS_INDIRECT_DRAW) { cmd.DrawArraysIndirect(GL_TRIANGLES, drawOff[0], drawEnd[0], ZoneRenderer.indirectDrawCmdsStaging); diff --git a/src/main/java/rs117/hd/renderer/zone/ZoneRenderer.java b/src/main/java/rs117/hd/renderer/zone/ZoneRenderer.java index be35d19b5c..c4daf422c1 100644 --- a/src/main/java/rs117/hd/renderer/zone/ZoneRenderer.java +++ b/src/main/java/rs117/hd/renderer/zone/ZoneRenderer.java @@ -91,6 +91,7 @@ public class ZoneRenderer implements Renderer { private static int TEXTURE_UNIT_COUNT = HdPlugin.TEXTURE_UNIT_COUNT; public static final int TEXTURE_UNIT_TEXTURED_FACES = GL_TEXTURE0 + TEXTURE_UNIT_COUNT++; + public static final int TEXTURE_UNIT_MODEL_DATA = GL_TEXTURE0 + TEXTURE_UNIT_COUNT++; private static int UNIFORM_BLOCK_COUNT = HdPlugin.UNIFORM_BLOCK_COUNT; public static final int UNIFORM_BLOCK_WORLD_VIEWS = UNIFORM_BLOCK_COUNT++; diff --git a/src/main/java/rs117/hd/renderer/zone/ZoneUploadJob.java b/src/main/java/rs117/hd/renderer/zone/ZoneUploadJob.java index e7f41ee7a0..1620e85452 100644 --- a/src/main/java/rs117/hd/renderer/zone/ZoneUploadJob.java +++ b/src/main/java/rs117/hd/renderer/zone/ZoneUploadJob.java @@ -72,12 +72,20 @@ private void mapZoneVertexBuffers() { GLTextureBuffer f = null; sz = zone.sizeF * Zone.TEXTURE_SIZE; if (sz > 0) { - f = new GLTextureBuffer("Zone::TBO", GL_STATIC_DRAW); + f = new GLTextureBuffer("Zone::TexturedFaces", GL_STATIC_DRAW); f.initialize(sz); f.map(MAP_WRITE); } - zone.initialize(o, a, f); + GLTextureBuffer m = null; + sz = zone.sizeM * Zone.MODEL_DATA_SIZE; + if (sz > 0) { + m = new GLTextureBuffer("Zone::ModelData", GL_STATIC_DRAW); + m.initialize(sz); + m.map(MAP_WRITE); + } + + zone.initialize(o, a, f, m); zone.setMetadata(viewContext, sceneContext, x, z); } catch (Throwable ex) { log.warn( diff --git a/src/main/java/rs117/hd/utils/buffer/GLTextureBuffer.java b/src/main/java/rs117/hd/utils/buffer/GLTextureBuffer.java index 1b58183741..713c993c93 100644 --- a/src/main/java/rs117/hd/utils/buffer/GLTextureBuffer.java +++ b/src/main/java/rs117/hd/utils/buffer/GLTextureBuffer.java @@ -1,55 +1,62 @@ package rs117.hd.utils.buffer; import lombok.Getter; +import rs117.hd.HdPlugin; import static org.lwjgl.opengl.GL33C.*; +import static rs117.hd.HdPlugin.GL_CAPS; public class GLTextureBuffer extends GLBuffer { + + public static boolean isRGBASupported() { return HdPlugin.GL_CAPS.GL_ARB_texture_buffer_object; } + @Getter private int texId; + private final int internalFormat; + public GLTextureBuffer(String name, int usage) { this(name, usage, 0); } public GLTextureBuffer(String name, int usage, int storageFlags) { super(name, GL_TEXTURE_BUFFER, usage, storageFlags); + + internalFormat = isRGBASupported() ? GL_RGBA32I : GL_RGB32I; } @Override public GLTextureBuffer initialize(long initialCapacity) { super.initialize(initialCapacity); - // Create texture texId = glGenTextures(); glBindTexture(target, texId); - - // RGB32 signed integer texture buffer - glTexBuffer(target, GL_RGB32I, id); - + glTexBuffer(target, internalFormat, id); glBindTexture(target, 0); + return this; } @Override public boolean ensureCapacity(long byteOffset, long numBytes) { int oldId = id; - boolean resized = super.ensureCapacity(byteOffset, numBytes); + final boolean resized = super.ensureCapacity(byteOffset, numBytes); + if (oldId != id) { glBindTexture(target, texId); - glTexBuffer(target, GL_RGB32I, id); + glTexBuffer(target, internalFormat, id); glBindTexture(target, 0); } + return resized; } @Override public void destroy() { - if (texId != 0) { + if (texId != 0) glDeleteTextures(texId); - texId = 0; - } + texId = 0; super.destroy(); } -} +} \ No newline at end of file diff --git a/src/main/java/rs117/hd/utils/buffer/GpuIntBuffer.java b/src/main/java/rs117/hd/utils/buffer/GpuIntBuffer.java index cdf5c6e79a..c3a543c973 100644 --- a/src/main/java/rs117/hd/utils/buffer/GpuIntBuffer.java +++ b/src/main/java/rs117/hd/utils/buffer/GpuIntBuffer.java @@ -145,7 +145,7 @@ public static int putFace( int materialDataA, int materialDataB, int materialDataC, int terrainDataA, int terrainDataB, int terrainDataC ) { - final int textureFaceIdx = buffer.position() / 3; + final int textureFaceIdx = buffer.position(); buffer.put(alphaBiasHslA); buffer.put(alphaBiasHslB); buffer.put(alphaBiasHslC); @@ -157,7 +157,7 @@ public static int putFace( buffer.put(terrainDataA); // TODO: Remove? buffer.put(terrainDataB); buffer.put(terrainDataC); - return textureFaceIdx; + return textureFaceIdx << 1; } public int position() { diff --git a/src/main/resources/rs117/hd/scene_vert.glsl b/src/main/resources/rs117/hd/scene_vert.glsl index 06b5268582..db45dfd6ab 100644 --- a/src/main/resources/rs117/hd/scene_vert.glsl +++ b/src/main/resources/rs117/hd/scene_vert.glsl @@ -27,20 +27,21 @@ #include #include +#include +#include #include #include +#include layout (location = 0) in vec3 vPosition; #if ZONE_RENDERER layout (location = 1) in vec4 vUv; layout (location = 2) in vec4 vNormal; - layout (location = 3) in int vTextureFaceIdx; + layout (location = 3) in int vPackedTextureFace; layout (location = 6) in int vWorldViewId; layout (location = 7) in ivec2 vSceneBase; - - uniform isamplerBuffer textureFaces; #else layout (location = 1) in vec3 vUv; layout (location = 2) in vec3 vNormal; @@ -67,32 +68,38 @@ layout (location = 0) in vec3 vPosition; } OUT; void main() { + fWorldViewId = vWorldViewId; + int vertex = gl_VertexID % 3; - bool isProvoking = vertex == 2; - int materialData = 0; - int alphaBiasHsl = 0; - - if (isProvoking) { - // Only the Provoking vertex needs to fetch the face data - fAlphaBiasHsl = texelFetch(textureFaces, vTextureFaceIdx).xyz; - fMaterialData = texelFetch(textureFaces, vTextureFaceIdx + 1).xyz; - fTerrainData = texelFetch(textureFaces, vTextureFaceIdx + 2).xyz; - fWorldViewId = vWorldViewId; - alphaBiasHsl = fAlphaBiasHsl[vertex]; - materialData = fMaterialData[vertex]; + int alphaBiasHsl; + int materialData; + + if(isModelFace(vPackedTextureFace)) { + ModelFaceData faceData = getModelFaceData(getFaceOffset(vPackedTextureFace)); + fAlphaBiasHsl = faceData.AlphaBiasHsl; + fMaterialData = ivec3(faceData.MaterialData); + fTerrainData = ivec3(0); + alphaBiasHsl = faceData.AlphaBiasHsl[vertex]; + materialData = faceData.MaterialData; } else { - // All outputs must be written to for macOS compatibility - fAlphaBiasHsl = ivec3(0); - fMaterialData = ivec3(0); - fTerrainData = ivec3(0); - fWorldViewId = 0; - alphaBiasHsl = texelFetch(textureFaces, vTextureFaceIdx)[vertex]; - materialData = texelFetch(textureFaces, vTextureFaceIdx + 1)[vertex]; + StaticFaceData faceData = getStaticFaceData(getFaceOffset(vPackedTextureFace)); + fAlphaBiasHsl = faceData.AlphaBiasHsl; + fMaterialData = faceData.MaterialData; + fTerrainData = faceData.TerrainData; + alphaBiasHsl = faceData.AlphaBiasHsl[vertex]; + materialData = faceData.MaterialData[vertex]; } vec3 sceneOffset = vec3(vSceneBase.x, 0, vSceneBase.y); vec3 worldNormal = vNormal.xyz; vec3 worldPosition = sceneOffset + vPosition; + + int modelIdx = int(vNormal.w); + if(modelIdx > 0) { + //ModelData modelData = getModelData(modelIdx); + + } + if (vWorldViewId != -1) { mat4x3 worldViewProjection = mat4x3(getWorldViewProjection(vWorldViewId)); worldPosition = worldViewProjection * vec4(worldPosition, 1.0); diff --git a/src/main/resources/rs117/hd/shadow_vert.glsl b/src/main/resources/rs117/hd/shadow_vert.glsl index 82ead2102d..b632a38ae5 100644 --- a/src/main/resources/rs117/hd/shadow_vert.glsl +++ b/src/main/resources/rs117/hd/shadow_vert.glsl @@ -28,6 +28,7 @@ #include #include #include +#include #include @@ -35,12 +36,10 @@ layout (location = 0) in vec3 vPosition; #if ZONE_RENDERER layout (location = 1) in vec4 vUv; - layout (location = 3) in int vTextureFaceIdx; + layout (location = 3) in int vPackedTextureFace; layout (location = 6) in int vWorldViewId; layout (location = 7) in ivec2 vSceneBase; - uniform isamplerBuffer textureFaces; - #if SHADOW_MODE == SHADOW_MODE_DETAILED out vec4 fUvw; flat out int fMaterialData; @@ -52,9 +51,22 @@ layout (location = 0) in vec3 vPosition; void main() { int vertex = gl_VertexID % 3; - int alphaBiasHsl = texelFetch(textureFaces, vTextureFaceIdx)[vertex]; - int materialData = texelFetch(textureFaces, vTextureFaceIdx + 1)[vertex]; - int terrainData = texelFetch(textureFaces, vTextureFaceIdx + 2)[vertex]; + int alphaBiasHsl; + int materialData; + int terrainData; + int faceDataOffset; + + if(isModelFace(vPackedTextureFace)) { + ModelFaceData faceData = getModelFaceData(getFaceOffset(vPackedTextureFace)); + alphaBiasHsl = faceData.AlphaBiasHsl[vertex]; + materialData = faceData.MaterialData; + terrainData = 0; + } else { + StaticFaceData faceData = getStaticFaceData(getFaceOffset(vPackedTextureFace)); + alphaBiasHsl = faceData.AlphaBiasHsl[vertex]; + materialData = faceData.MaterialData[vertex]; + terrainData = faceData.TerrainData[vertex]; + } int waterTypeIndex = terrainData >> 3 & 0xFF; float opacity = 1 - (alphaBiasHsl >> 24 & 0xFF) / float(0xFF); diff --git a/src/main/resources/rs117/hd/uniforms/model_data.glsl b/src/main/resources/rs117/hd/uniforms/model_data.glsl new file mode 100644 index 0000000000..a5840f628d --- /dev/null +++ b/src/main/resources/rs117/hd/uniforms/model_data.glsl @@ -0,0 +1,25 @@ +#pragma once + +#include + +#define MODEL_DATA_SIZE 4 +#define PARSER_TARGET_BUFFER modelData + +uniform isamplerBuffer modelData; + +struct ModelData { + ivec3 position; + int height; +}; + + +BEGIN_BUFFER_PARSER(readModelData, ModelData) + READ_IVEC3(position) + READ_INT(height) +END_BUFFER_PARSER() + +ModelData getModelData(int modelIdx) { + return readModelData((modelIdx - 1) * MODEL_DATA_SIZE); +} + +#undef PARSER_TARGET_BUFFER \ No newline at end of file diff --git a/src/main/resources/rs117/hd/uniforms/texture_faces.glsl b/src/main/resources/rs117/hd/uniforms/texture_faces.glsl new file mode 100644 index 0000000000..8801f9ae9d --- /dev/null +++ b/src/main/resources/rs117/hd/uniforms/texture_faces.glsl @@ -0,0 +1,39 @@ +#pragma once + +#include + +#define PARSER_TARGET_BUFFER textureFaces + +uniform isamplerBuffer textureFaces; + +struct StaticFaceData { + ivec3 AlphaBiasHsl; + ivec3 MaterialData; + ivec3 TerrainData; +}; + +struct ModelFaceData { + ivec3 AlphaBiasHsl; + int MaterialData; +}; + +bool isModelFace(int packedFaceData) { + return (packedFaceData & 1) == 1; +} + +int getFaceOffset(int packedFaceData) { + return packedFaceData >> 1; +} + +BEGIN_BUFFER_PARSER(getStaticFaceData,StaticFaceData) + READ_IVEC3(AlphaBiasHsl) + READ_IVEC3(MaterialData) + READ_IVEC3(TerrainData) +END_BUFFER_PARSER() + +BEGIN_BUFFER_PARSER(getModelFaceData,ModelFaceData) + READ_IVEC3(AlphaBiasHsl) + READ_INT(MaterialData) +END_BUFFER_PARSER() + +#undef PARSER_TARGET_BUFFER \ No newline at end of file diff --git a/src/main/resources/rs117/hd/utils/texture_buffer_reader.glsl b/src/main/resources/rs117/hd/utils/texture_buffer_reader.glsl new file mode 100644 index 0000000000..d85e300788 --- /dev/null +++ b/src/main/resources/rs117/hd/utils/texture_buffer_reader.glsl @@ -0,0 +1,187 @@ +#pragma once + +// Number of scalar components per fetched texel. +// Valid range: 1-4. +#include TEXEL_SIZE +#ifndef TEXEL_SIZE + #define TEXEL_SIZE 4 +#endif + +#if TEXEL_SIZE < 1 || TEXEL_SIZE > 4 + #error TEXEL_SIZE must be between 1 and 4 +#endif + +// Sequential reader for tightly-packed scalar data stored in a buffer texture. +// +// Layout assumptions: +// - Data is packed scalar-by-scalar with NO padding. +// - Floats are stored as IEEE-754 bit patterns inside integer components. +// - TEXEL_SIZE defines how many usable components exist per fetched texel. +// +// Example packed stream: +// [int][float][vec3][ivec2]... +// +// This reader caches the currently loaded texel to avoid redundant texelFetch +// calls during sequential access. + +struct TexBufferReader { + // Cached texel data. + // Always ivec4 regardless of TEXEL_SIZE. + ivec4 data; + + // Current scalar position in stream. + int position; + + // Currently cached texel index. + int loadedTexel; +}; + +TexBufferReader buildTexBufferReader( + int position +) { + TexBufferReader reader; + + reader.position = position; + + reader.data = ivec4(0); + reader.loadedTexel = -1; + + return reader; +} + +int readInt(isamplerBuffer buf, inout TexBufferReader reader) { +#if TEXEL_SIZE == 4 + int texelIndex = reader.position >> 2; + int component = reader.position & 3; +#else + int texelIndex = reader.position / TEXEL_SIZE; + int component = reader.position % TEXEL_SIZE; +#endif + + if (texelIndex != reader.loadedTexel) { + reader.data = texelFetch(buf, texelIndex); + reader.loadedTexel = texelIndex; + } + + reader.position++; + + switch (component) { + case 0: return reader.data.x; + case 1: return reader.data.y; + case 2: return reader.data.z; + default: return reader.data.w; + } +} + +uint readUInt(isamplerBuffer buf, inout TexBufferReader reader) { + return uint(readInt(buf, reader)); +} + +float readFloat(isamplerBuffer buf, inout TexBufferReader reader) { + return intBitsToFloat(readInt(buf, reader)); +} + +bool readBool(isamplerBuffer buf, inout TexBufferReader reader) { + return readInt(buf, reader) != 0; +} + +ivec2 readIVec2(isamplerBuffer buf, inout TexBufferReader reader) { + return ivec2( + readInt(buf, reader), + readInt(buf, reader) + ); +} + +ivec3 readIVec3(isamplerBuffer buf, inout TexBufferReader reader) { + return ivec3( + readInt(buf, reader), + readInt(buf, reader), + readInt(buf, reader) + ); +} + +ivec4 readIVec4(isamplerBuffer buf, inout TexBufferReader reader) { + return ivec4( + readInt(buf, reader), + readInt(buf, reader), + readInt(buf, reader), + readInt(buf, reader) + ); +} + +uvec2 readUVec2(isamplerBuffer buf, inout TexBufferReader reader) { + return uvec2( + readUInt(buf, reader), + readUInt(buf, reader) + ); +} + +uvec3 readUVec3(isamplerBuffer buf, inout TexBufferReader reader) { + return uvec3( + readUInt(buf, reader), + readUInt(buf, reader), + readUInt(buf, reader) + ); +} + +uvec4 readUVec4(isamplerBuffer buf, inout TexBufferReader reader) { + return uvec4( + readUInt(buf, reader), + readUInt(buf, reader), + readUInt(buf, reader), + readUInt(buf, reader) + ); +} + +vec2 readVec2(isamplerBuffer buf, inout TexBufferReader reader) { + return vec2( + readFloat(buf, reader), + readFloat(buf, reader) + ); +} + +vec3 readVec3(isamplerBuffer buf, inout TexBufferReader reader) { + return vec3( + readFloat(buf, reader), + readFloat(buf, reader), + readFloat(buf, reader) + ); +} + +vec4 readVec4(isamplerBuffer buf, inout TexBufferReader reader) { + return vec4( + readFloat(buf, reader), + readFloat(buf, reader), + readFloat(buf, reader), + readFloat(buf, reader) + ); +} + +void skipScalars(inout TexBufferReader reader, int count) { + reader.position += count; +} + +void rewindReader(inout TexBufferReader reader, int position) { + reader.position = position; +} + +#define BEGIN_BUFFER_PARSER(FuncName, StructType) \ +StructType FuncName(int offset) { \ + TexBufferReader reader = \ + buildTexBufferReader(offset); \ + \ + StructType data; + +#define END_BUFFER_PARSER() \ + return data; \ +} + +#define READ_INT(field) data.field = readInt(PARSER_TARGET_BUFFER, reader); +#define READ_FLOAT(field) data.field = readFloat(PARSER_TARGET_BUFFER, reader); +#define READ_BOOL(field) data.field = readBool(PARSER_TARGET_BUFFER, reader); +#define READ_IVEC2(field) data.field = readIVec2(PARSER_TARGET_BUFFER, reader); +#define READ_IVEC3(field) data.field = readIVec3(PARSER_TARGET_BUFFER, reader); +#define READ_IVEC4(field) data.field = readIVec4(PARSER_TARGET_BUFFER, reader); +#define READ_VEC2(field) data.field = readVec2(PARSER_TARGET_BUFFER, reader); +#define READ_VEC3(field) data.field = readVec3(PARSER_TARGET_BUFFER, reader); +#define READ_VEC4(field) data.field = readVec4(PARSER_TARGET_BUFFER, reader); \ No newline at end of file