From 619887ec4bf91200a59f8d20316d4736a43583a4 Mon Sep 17 00:00:00 2001 From: Anuken Date: Mon, 21 Jul 2025 20:32:44 -0400 Subject: [PATCH] Packed uv and positions for floor and editor renderer --- .../{MapRenderer.java => EditorRenderer.java} | 10 +- .../mindustry/editor/EditorSpriteCache.java | 51 +++++----- core/src/mindustry/editor/MapEditor.java | 2 +- .../src/mindustry/graphics/FloorRenderer.java | 94 ++++++++++--------- .../blocks/environment/ColoredFloor.java | 3 +- gradle.properties | 2 +- 6 files changed, 87 insertions(+), 75 deletions(-) rename core/src/mindustry/editor/{MapRenderer.java => EditorRenderer.java} (93%) diff --git a/core/src/mindustry/editor/MapRenderer.java b/core/src/mindustry/editor/EditorRenderer.java similarity index 93% rename from core/src/mindustry/editor/MapRenderer.java rename to core/src/mindustry/editor/EditorRenderer.java index f943117b36..8770003eb7 100644 --- a/core/src/mindustry/editor/MapRenderer.java +++ b/core/src/mindustry/editor/EditorRenderer.java @@ -13,13 +13,15 @@ import mindustry.world.*; import static mindustry.Vars.*; -public class MapRenderer implements Disposable{ +public class EditorRenderer implements Disposable{ + private static final float packPad = tilesize * 10f; private static final int chunkSize = 60; private static final Seq tmpTiles = new Seq<>(); private EditorSpriteCache[][] chunks; private IntSet recacheChunks = new IntSet(); private int width, height; + private float packWidth, packHeight; private Shader shader; @@ -31,6 +33,8 @@ public class MapRenderer implements Disposable{ this.width = width; this.height = height; + packWidth = width * tilesize + packPad * 2; + packHeight = height * tilesize + packPad * 2; recache(); } @@ -111,7 +115,7 @@ public class MapRenderer implements Disposable{ } shader.bind(); - shader.setUniformMatrix4("u_projTrans", Core.camera.mat); + shader.setUniformMatrix4("u_projTrans", Tmp.m1.set(Core.camera.mat).translate(-packPad, -packPad).scale(packWidth, packHeight)); for(int x = 0; x < chunks.length; x++){ for(int y = 0; y < chunks[0].length; y++){ @@ -160,7 +164,7 @@ public class MapRenderer implements Disposable{ chunks[cx][cy] = null; } - EditorSpriteCache cache = new EditorSpriteCache(renderer.blocks.floor.getVertexBuffer()); + EditorSpriteCache cache = new EditorSpriteCache(renderer.blocks.floor.getVertexBuffer(), packPad, packPad, packWidth, packHeight); TextureRegion teamRegion = Core.atlas.find("block-border"); diff --git a/core/src/mindustry/editor/EditorSpriteCache.java b/core/src/mindustry/editor/EditorSpriteCache.java index 26cfc652ec..f659b6b84f 100644 --- a/core/src/mindustry/editor/EditorSpriteCache.java +++ b/core/src/mindustry/editor/EditorSpriteCache.java @@ -8,12 +8,13 @@ import arc.struct.*; import arc.util.*; public class EditorSpriteCache implements Disposable{ - //xy + color + uv - static final int vertexSize = 2 + 1 + 2; + //packed xy + color + packed uv + static final int vertexSize = 1 + 1 + 1; private @Nullable Mesh mesh; private final Seq textures = new Seq<>(8); private final IntSeq counts = new IntSeq(8); + private final float packX, packY, packW, packH; private float[] tmpVertices; @@ -21,8 +22,12 @@ public class EditorSpriteCache implements Disposable{ private int index; /** @param tmpVertices Temporary buffer to hold vertices while building up sprites. Should be large enough to hold all sprite data this cache will contain. */ - public EditorSpriteCache(float[] tmpVertices){ + public EditorSpriteCache(float[] tmpVertices, float packX, float packY, float packW, float packH){ this.tmpVertices = tmpVertices; + this.packX = packX; + this.packY = packY; + this.packW = packW; + this.packH = packH; } /** @return whether anything was added to the cache. */ @@ -41,9 +46,9 @@ public class EditorSpriteCache implements Disposable{ if(mesh != null) mesh.dispose(); mesh = new Mesh(true, index / vertexSize, 0, - VertexAttribute.position, + VertexAttribute.packedPosition, VertexAttribute.color, - VertexAttribute.texCoords + VertexAttribute.packedTexCoords ); mesh.indices = indices; mesh.setVertices(tmpVertices, 0, index); @@ -111,29 +116,21 @@ public class EditorSpriteCache implements Disposable{ float[] verts = tmpVertices; Texture texture = region.texture; - verts[idx + 0] = x1; - verts[idx + 1] = y1; - verts[idx + 2] = colorPacked; - verts[idx + 3] = u; - verts[idx + 4] = v; + verts[idx + 0] = pack(x1, y1); + verts[idx + 1] = colorPacked; + verts[idx + 2] = Pack.packUv(u, v); - verts[idx + 5] = x2; - verts[idx + 6] = y2; + verts[idx + 3] = pack(x2, y2); + verts[idx + 4] = colorPacked; + verts[idx + 5] = Pack.packUv(u, v2); + + verts[idx + 6] = pack(x3, y3); verts[idx + 7] = colorPacked; - verts[idx + 8] = u; - verts[idx + 9] = v2; + verts[idx + 8] = Pack.packUv(u2, v2); - verts[idx + 10] = x3; - verts[idx + 11] = y3; - verts[idx + 12] = colorPacked; - verts[idx + 13] = u2; - verts[idx + 14] = v2; - - verts[idx + 15] = x4; - verts[idx + 16] = y4; - verts[idx + 17] = colorPacked; - verts[idx + 18] = u2; - verts[idx + 19] = v; + verts[idx + 9] = pack(x4, y4); + verts[idx + 10] = colorPacked; + verts[idx + 11] = Pack.packUv(u2, v); int lastIndex = textures.size - 1; if(lastIndex < 0 || textures.get(lastIndex) != texture){ @@ -146,6 +143,10 @@ public class EditorSpriteCache implements Disposable{ index += vertexSize * 4; } + private float pack(float x, float y){ + return Pack.packUv((x + packX) / packW, (y + packY) / packH); + } + /** Renders the cached mesh. The shader must already have the correct view matrix set as a uniform. */ public void render(Shader shader){ if(mesh == null) throw new IllegalStateException("Cache is empty, call build() first."); diff --git a/core/src/mindustry/editor/MapEditor.java b/core/src/mindustry/editor/MapEditor.java index bb5ff4b102..95add660b2 100644 --- a/core/src/mindustry/editor/MapEditor.java +++ b/core/src/mindustry/editor/MapEditor.java @@ -20,7 +20,7 @@ public class MapEditor{ public static final float[] brushSizes = {1, 1.5f, 2, 3, 4, 5, 9, 15, 20}; public StringMap tags = new StringMap(); - public MapRenderer renderer = new MapRenderer(); + public EditorRenderer renderer = new EditorRenderer(); private final Context context = new Context(); private OperationStack stack = new OperationStack(); diff --git a/core/src/mindustry/graphics/FloorRenderer.java b/core/src/mindustry/graphics/FloorRenderer.java index 31922c8877..27bb65b5aa 100644 --- a/core/src/mindustry/graphics/FloorRenderer.java +++ b/core/src/mindustry/graphics/FloorRenderer.java @@ -30,13 +30,14 @@ import static mindustry.Vars.*; * * */ public class FloorRenderer{ - private static final VertexAttribute[] attributes = {VertexAttribute.position, VertexAttribute.color, VertexAttribute.texCoords}; + private static final VertexAttribute[] attributes = {VertexAttribute.packedPosition, VertexAttribute.color, VertexAttribute.packedTexCoords}; private static final int chunksize = 30, //todo 32? chunkunits = chunksize * tilesize, - vertexSize = 2 + 1 + 2, + vertexSize = 1 + 1 + 1, spriteSize = vertexSize * 4, maxSprites = chunksize * chunksize * 9; + private static final float packPad = tilesize * 8f; private static final float pad = tilesize/2f; //if true, chunks are rendered on-demand; this causes small lag spikes and is generally not needed for most maps private static final boolean dynamic = false; @@ -45,6 +46,7 @@ public class FloorRenderer{ private int vidx; private FloorRenderBatch batch = new FloorRenderBatch(); private Shader shader; + private Mat combinedMat = new Mat(); private Texture texture; private TextureRegion error; @@ -55,6 +57,8 @@ public class FloorRenderer{ private IntSeq drawnLayers = new IntSeq(); private ObjectSet used = new ObjectSet<>(); + private float packWidth, packHeight; + private Seq underwaterDraw = new Seq<>(Runnable.class); //alpha value of pixels cannot exceed the alpha of the surface they're being drawn on private Blending underwaterBlend = new Blending( @@ -87,6 +91,7 @@ public class FloorRenderer{ attribute vec4 a_position; attribute vec4 a_color; attribute vec2 a_texCoord0; + uniform mat4 u_projectionViewMatrix; varying vec4 v_color; varying vec2 v_texCoords; @@ -212,7 +217,8 @@ public class FloorRenderer{ Draw.flush(); shader.bind(); - shader.setUniformMatrix4("u_projectionViewMatrix", Core.camera.mat); + //coordinates of geometry are normalized to [0, 1] based on map size (normWidth/normHeight), so the matrix needs to be updated accordingly + shader.setUniformMatrix4("u_projectionViewMatrix", combinedMat.set(Core.camera.mat).translate(-packPad, -packPad).scale(packWidth, packHeight)); //only ever use the base environment texture texture.bind(0); @@ -370,6 +376,9 @@ public class FloorRenderer{ texture = Core.atlas.find("grass1").texture; error = Core.atlas.find("env-error"); + packWidth = world.unitWidth() + packPad *2f; + packHeight = world.unitHeight() + packPad *2f; + //pre-cache chunks if(!dynamic){ Time.mark(); @@ -449,29 +458,21 @@ public class FloorRenderer{ float color = this.colorPacked; - verts[idx] = x1; - verts[idx + 1] = y1; - verts[idx + 2] = color; - verts[idx + 3] = u; - verts[idx + 4] = v; + verts[idx] = pack(x1, y1); + verts[idx + 1] = color; + verts[idx + 2] = Pack.packUv(u, v); - verts[idx + 5] = x2; - verts[idx + 6] = y2; + verts[idx + 3] = pack(x2, y2); + verts[idx + 4] = color; + verts[idx + 5] = Pack.packUv(u, v2); + + verts[idx + 6] = pack(x3, y3); verts[idx + 7] = color; - verts[idx + 8] = u; - verts[idx + 9] = v2; + verts[idx + 8] = Pack.packUv(u2, v2); - verts[idx + 10] = x3; - verts[idx + 11] = y3; - verts[idx + 12] = color; - verts[idx + 13] = u2; - verts[idx + 14] = v2; - - verts[idx + 15] = x4; - verts[idx + 16] = y4; - verts[idx + 17] = color; - verts[idx + 18] = u2; - verts[idx + 19] = v; + verts[idx + 9] = pack(x4, y4); + verts[idx + 10] = color; + verts[idx + 11] = Pack.packUv(u2, v); }else{ float fx2 = x + width; float fy2 = y + height; @@ -482,33 +483,29 @@ public class FloorRenderer{ float color = this.colorPacked; - verts[idx] = x; - verts[idx + 1] = y; - verts[idx + 2] = color; - verts[idx + 3] = u; - verts[idx + 4] = v; + verts[idx] = pack(x, y); + verts[idx + 1] = color; + verts[idx + 2] = Pack.packUv(u, v); - verts[idx + 5] = x; - verts[idx + 6] = fy2; + verts[idx + 3] = pack(x, fy2); + verts[idx + 4] = color; + verts[idx + 5] = Pack.packUv(u, v2); + + verts[idx + 6] = pack(fx2, fy2); verts[idx + 7] = color; - verts[idx + 8] = u; - verts[idx + 9] = v2; + verts[idx + 8] = Pack.packUv(u2, v2); - verts[idx + 10] = fx2; - verts[idx + 11] = fy2; - verts[idx + 12] = color; - verts[idx + 13] = u2; - verts[idx + 14] = v2; - - verts[idx + 15] = fx2; - verts[idx + 16] = y; - verts[idx + 17] = color; - verts[idx + 18] = u2; - verts[idx + 19] = v; + verts[idx + 9] = pack(fx2, y); + verts[idx + 10] = color; + verts[idx + 11] = Pack.packUv(u2, v); } } + float pack(float x, float y){ + return Pack.packUv((x + packPad) / packWidth, (y + packPad) / packHeight); + } + @Override public void flush(){ @@ -526,8 +523,17 @@ public class FloorRenderer{ } float[] verts = vertices; + float[] src = spriteVertices; int idx = vidx; - System.arraycopy(spriteVertices, offset, verts, idx, spriteSize); + int sidx = offset; + + //convert 5-float format to internal packed 3-float format + for(int i = 0; i < 4; i++){ + verts[idx++] = pack(src[sidx++], src[sidx++]); + verts[idx++] = src[sidx++]; + verts[idx++] = Pack.packUv(src[sidx++], src[sidx++]); + } + vidx += spriteSize; } } diff --git a/core/src/mindustry/world/blocks/environment/ColoredFloor.java b/core/src/mindustry/world/blocks/environment/ColoredFloor.java index 0a9ca1fe27..37552f5d7e 100644 --- a/core/src/mindustry/world/blocks/environment/ColoredFloor.java +++ b/core/src/mindustry/world/blocks/environment/ColoredFloor.java @@ -20,7 +20,8 @@ public class ColoredFloor extends Floor{ /** If the alpha value of the color is set to this value, colors are interpolated across corners. This is essentially linear filtering for the whole "image". */ public static final int flagSmoothBlend = 2; - private static final float[] verts = new float[20]; + //4x (pos2 color uv2) + private static final float[] verts = new float[4 * 5]; public Color defaultColor = Color.white; protected int defaultColorRgba; diff --git a/gradle.properties b/gradle.properties index fcd8e8dc79..28c36ef491 100644 --- a/gradle.properties +++ b/gradle.properties @@ -26,4 +26,4 @@ org.gradle.caching=true org.gradle.internal.http.socketTimeout=100000 org.gradle.internal.http.connectionTimeout=100000 android.enableR8.fullMode=false -archash=15709e19de +archash=324275bb33