diff --git a/core/src/mindustry/editor/DrawOperation.java b/core/src/mindustry/editor/DrawOperation.java index 163546bfc3..903b38a588 100755 --- a/core/src/mindustry/editor/DrawOperation.java +++ b/core/src/mindustry/editor/DrawOperation.java @@ -70,7 +70,7 @@ public class DrawOperation{ } } case opBlock -> { - tile.getLinkedTiles(t -> editor.renderer.updatePoint(t.x, t.y)); + tile.getLinkedTiles(t -> editor.renderer.updateStatic(t.x, t.y)); Block block = content.block(to); tile.setBlock(block, tile.team(), tile.build == null ? 0 : tile.build.rotation); @@ -78,7 +78,7 @@ public class DrawOperation{ tile.build.enabled = true; } - tile.getLinkedTiles(t -> editor.renderer.updatePoint(t.x, t.y)); + tile.getLinkedTiles(t -> editor.renderer.updateStatic(t.x, t.y)); } case opRotation -> { if(tile.build != null) tile.build.rotation = to; @@ -86,7 +86,7 @@ public class DrawOperation{ case opTeam -> tile.setTeam(Team.get(to)); } }); - editor.renderer.updatePoint(tile.x, tile.y); + editor.renderer.updateStatic(tile.x, tile.y); } @Struct diff --git a/core/src/mindustry/editor/EditorSpriteCache.java b/core/src/mindustry/editor/EditorSpriteCache.java new file mode 100644 index 0000000000..6fe1faeea1 --- /dev/null +++ b/core/src/mindustry/editor/EditorSpriteCache.java @@ -0,0 +1,171 @@ +package mindustry.editor; + +import arc.graphics.*; +import arc.graphics.g2d.*; +import arc.graphics.gl.*; +import arc.math.*; +import arc.struct.*; +import arc.util.*; + +public class EditorSpriteCache implements Disposable{ + //xy + color + uv + static final int vertexSize = 2 + 1 + 2; + + private @Nullable Mesh mesh; + private final Seq textures = new Seq<>(8); + private final IntSeq counts = new IntSeq(8); + + private float[] tmpVertices; + + /** Index in tmpVertices of current vertex data. */ + 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){ + this.tmpVertices = tmpVertices; + } + + /** @return whether anything was added to the cache. */ + public boolean isEmpty(){ + return index == 0; + } + + /** + * Builds this cache into a mesh that can be used for rendering. Use after calling {@link #draw(TextureRegion, float, float, float, float, float, float, float, float)}. + * Until this method is called, no mesh is created. + * + * @param indices The shared index data in standard quad format, as seen in SpriteBatch. + * Since this data is static, it should be the same across all caches, and be large enough to accommodate all sprites. + * */ + public void build(IndexData indices){ + if(mesh != null) mesh.dispose(); + + mesh = new Mesh(true, index / vertexSize, 0, + VertexAttribute.position, + VertexAttribute.color, + VertexAttribute.texCoords + ); + mesh.indices = indices; + mesh.setVertices(tmpVertices, 0, index); + } + + /** Adds the specified region to the cache. */ + public void draw(TextureRegion region, float x, float y, float originX, float originY, float width, float height, float rotation, float colorPacked){ + if(mesh != null) throw new IllegalStateException("This cache is already built. Call #clear() before drawing new sprites."); + + // bottom left and top right corner points relative to origin + final float worldOriginX = x + originX; + final float worldOriginY = y + originY; + float fx = -originX; + float fy = -originY; + float fx2 = width - originX; + float fy2 = height - originY; + + float x1, y1, x2, y2, x3, y3, x4, y4; + + // rotate + if(rotation != 0){ + final float cos = Mathf.cosDeg(rotation); + final float sin = Mathf.sinDeg(rotation); + + x1 = cos * fx - sin * fy; + y1 = sin * fx + cos * fy; + + x2 = cos * fx - sin * fy2; + y2 = sin * fx + cos * fy2; + + x3 = cos * fx2 - sin * fy2; + y3 = sin * fx2 + cos * fy2; + + x4 = x1 + (x3 - x2); + y4 = y3 - (y2 - y1); + }else{ + x1 = fx; + y1 = fy; + + x2 = fx; + y2 = fy2; + + x3 = fx2; + y3 = fy2; + + x4 = fx2; + y4 = fy; + } + + x1 += worldOriginX; + y1 += worldOriginY; + x2 += worldOriginX; + y2 += worldOriginY; + x3 += worldOriginX; + y3 += worldOriginY; + x4 += worldOriginX; + y4 += worldOriginY; + + final float u = region.u; + final float v = region.v2; + final float u2 = region.u2; + final float v2 = region.v; + + int idx = index; + 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 + 5] = x2; + verts[idx + 6] = y2; + verts[idx + 7] = colorPacked; + verts[idx + 8] = u; + verts[idx + 9] = 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; + + int lastIndex = textures.size - 1; + if(lastIndex < 0 || textures.get(lastIndex) != texture){ + textures.add(texture); + counts.add(6); + }else{ + counts.incr(lastIndex, 6); + } + + index += vertexSize * 4; + } + + /** Renders the cached mesh. The shader must already have the correct view matrix (usually u_projectionViewMatrix) set as a uniform. */ + public void render(Shader shader){ + if(mesh == null) throw new IllegalStateException("Cache is empty, call build() first."); + + int offset = 0; + + for(int i = 0; i < textures.size; i++){ + int count = counts.items[i]; + textures.get(i).bind(); + + mesh.render(shader, Gl.triangles, offset, count); + offset += count; + } + } + + @Override + public void dispose(){ + if(mesh != null){ + mesh.dispose(); + mesh = null; + } + } +} \ No newline at end of file diff --git a/core/src/mindustry/editor/EditorTile.java b/core/src/mindustry/editor/EditorTile.java index 2c662cecf6..47a5aee534 100644 --- a/core/src/mindustry/editor/EditorTile.java +++ b/core/src/mindustry/editor/EditorTile.java @@ -4,6 +4,7 @@ import arc.func.*; import mindustry.content.*; import mindustry.game.*; import mindustry.gen.*; +import mindustry.graphics.*; import mindustry.world.*; import mindustry.world.blocks.environment.*; import mindustry.world.modules.*; @@ -46,13 +47,16 @@ public class EditorTile extends Tile{ @Override public void setBlock(Block type, Team team, int rotation, Prov entityprov){ + Block prev = this.block; + Tile prevCenter = (build == null ? this : build.tile); + if(skip()){ super.setBlock(type, team, rotation, entityprov); return; } if(this.block == type && (build == null || build.rotation == rotation)){ - update(); + updateStatic(); return; } @@ -61,7 +65,7 @@ public class EditorTile extends Tile{ cen.op(DrawOperation.opRotation, (byte)build.rotation); cen.op(DrawOperation.opTeam, (byte)build.team.id); cen.op(DrawOperation.opBlock, block.id); - update(); + updateStatic(); }else{ if(build != null) op(DrawOperation.opRotation, (byte)build.rotation); if(build != null) op(DrawOperation.opTeam, (byte)build.team.id); @@ -70,7 +74,20 @@ public class EditorTile extends Tile{ super.setBlock(type, team, rotation, entityprov); - renderer.blocks.updateShadowTile(this); + if(requiresBlockUpdate(type) || requiresBlockUpdate(prev)){ + if(prev.size > 1){ + prevCenter.getLinkedTilesAs(prev, tile -> { + editor.renderer.updateBlock(tile.x, tile.y); + renderer.blocks.updateShadowTile(tile); + }); + } + getLinkedTiles(tile -> { + editor.renderer.updateBlock(tile.x, tile.y); + renderer.blocks.updateShadowTile(tile); + }); + }else{ + renderer.blocks.updateShadowTile(this); + } } @Override @@ -84,7 +101,7 @@ public class EditorTile extends Tile{ op(DrawOperation.opTeam, (byte)getTeamID()); super.setTeam(team); - getLinkedTiles(t -> editor.renderer.updatePoint(t.x, t.y)); + getLinkedTiles(t -> editor.renderer.updateStatic(t.x, t.y)); } @Override @@ -105,7 +122,7 @@ public class EditorTile extends Tile{ if(skip()){ super.fireChanged(); }else{ - update(); + updateStatic(); } } @@ -114,7 +131,7 @@ public class EditorTile extends Tile{ if(skip()){ super.firePreChanged(); }else{ - update(); + updateStatic(); } } @@ -159,8 +176,12 @@ public class EditorTile extends Tile{ return skip() && super.isDarkened(); } - private void update(){ - editor.renderer.updatePoint(x, y); + private boolean requiresBlockUpdate(Block block){ + return block != Blocks.air && block.cacheLayer == CacheLayer.normal; + } + + private void updateStatic(){ + editor.renderer.updateStatic(x, y); } private boolean skip(){ diff --git a/core/src/mindustry/editor/MapEditor.java b/core/src/mindustry/editor/MapEditor.java index 7df7f67ea6..e663e7d8cc 100644 --- a/core/src/mindustry/editor/MapEditor.java +++ b/core/src/mindustry/editor/MapEditor.java @@ -374,7 +374,7 @@ public class MapEditor{ if(currentOp == null) currentOp = new DrawOperation(); currentOp.addOperation(data); - renderer.updatePoint(TileOp.x(data), TileOp.y(data)); + renderer.updateStatic(TileOp.x(data), TileOp.y(data)); } class Context implements WorldContext{ diff --git a/core/src/mindustry/editor/MapEditorDialog.java b/core/src/mindustry/editor/MapEditorDialog.java index 2ab5c0759f..f1755db39d 100644 --- a/core/src/mindustry/editor/MapEditorDialog.java +++ b/core/src/mindustry/editor/MapEditorDialog.java @@ -303,7 +303,7 @@ public class MapEditorDialog extends Dialog implements Disposable{ state.rules = (lastSavedRules == null ? new Rules() : lastSavedRules); lastSavedRules = null; saved = false; - editor.renderer.updateAll(); + editor.renderer.recache(); } private void editInGame(){ diff --git a/core/src/mindustry/editor/MapGenerateDialog.java b/core/src/mindustry/editor/MapGenerateDialog.java index bb04261baf..19d435a6ac 100644 --- a/core/src/mindustry/editor/MapGenerateDialog.java +++ b/core/src/mindustry/editor/MapGenerateDialog.java @@ -185,7 +185,7 @@ public class MapGenerateDialog extends BaseDialog{ } //reset undo stack as generation... messes things up - editor.renderer.updateAll(); + editor.renderer.recache(); editor.clearOp(); } diff --git a/core/src/mindustry/editor/MapProcessorsDialog.java b/core/src/mindustry/editor/MapProcessorsDialog.java index 8867c2df13..9c687f08a8 100644 --- a/core/src/mindustry/editor/MapProcessorsDialog.java +++ b/core/src/mindustry/editor/MapProcessorsDialog.java @@ -41,7 +41,7 @@ public class MapProcessorsDialog extends BaseDialog{ foundAny = true; tile.setNet(Blocks.worldProcessor, Team.sharded, 0); if(ui.editor.isShown()){ - Vars.editor.renderer.updatePoint(x, y); + Vars.editor.renderer.updateStatic(x, y); } break outer; } diff --git a/core/src/mindustry/editor/MapRenderer.java b/core/src/mindustry/editor/MapRenderer.java index fa0abee70c..9e3938fedc 100644 --- a/core/src/mindustry/editor/MapRenderer.java +++ b/core/src/mindustry/editor/MapRenderer.java @@ -3,228 +3,178 @@ package mindustry.editor; import arc.*; import arc.graphics.*; import arc.graphics.g2d.*; -import arc.math.*; +import arc.graphics.gl.*; +import arc.math.geom.*; import arc.struct.*; import arc.util.*; import mindustry.content.*; import mindustry.graphics.*; import mindustry.world.*; -import mindustry.world.blocks.environment.*; import static mindustry.Vars.*; public class MapRenderer implements Disposable{ - private static final int chunkSize = 62; - private IndexedRenderer[][] chunks; - private IntSet updates = new IntSet(); - private IntSet delayedUpdates = new IntSet(); - private TextureRegion clearEditor; + private static final int chunkSize = 60; + private EditorSpriteCache[][] chunks; + private IntSet recacheChunks = new IntSet(); private int width, height; + private Shader shader; + public void resize(int width, int height){ - updates.clear(); - delayedUpdates.clear(); - if(chunks != null){ - for(int x = 0; x < chunks.length; x++){ - for(int y = 0; y < chunks[0].length; y++){ - chunks[x][y].dispose(); - } - } - } + dispose(); - chunks = new IndexedRenderer[(int)Math.ceil((float)width / chunkSize)][(int)Math.ceil((float)height / chunkSize)]; + recacheChunks.clear(); + chunks = new EditorSpriteCache[(int)Math.ceil((float)width / chunkSize)][(int)Math.ceil((float)height / chunkSize)]; - for(int x = 0; x < chunks.length; x++){ - for(int y = 0; y < chunks[0].length; y++){ - chunks[x][y] = new IndexedRenderer(chunkSize * chunkSize * 2); - } - } this.width = width; this.height = height; - updateAll(); - renderer.blocks.floor.clearTiles(); - renderer.blocks.reload(); + recache(); } - public void draw(float tx, float ty, float tw, float th, float zoom){ + public void draw(float tx, float ty, float tw, float th){ + if(shader == null){ + shader = new Shader( + """ + attribute vec4 a_position; + attribute vec4 a_color; + attribute vec2 a_texCoord0; + uniform mat4 u_projTrans; + varying vec4 v_color; + varying vec2 v_texCoords; + void main(){ + v_color = a_color; + v_color.a = v_color.a * (255.0/254.0); + v_texCoords = a_texCoord0; + gl_Position = u_projTrans * a_position; + } + """, + + """ + varying lowp vec4 v_color; + varying vec2 v_texCoords; + uniform sampler2D u_texture; + + void main(){ + gl_FragColor = v_color * texture2D(u_texture, v_texCoords); + } + """ + ); + } + Draw.flush(); - //TODO properly integrate this later - if(true){ - updates.each(i -> renderer.blocks.floor.recacheTile(i % width, i / width)); - updates.clear(); + renderer.blocks.floor.checkChanges(); - updates.addAll(delayedUpdates); - delayedUpdates.clear(); + boolean prev = renderer.animateWater; + renderer.animateWater = false; - renderer.blocks.floor.checkChanges(); + Core.camera.position.set(world.width()/2f * tilesize, world.height()/2f * tilesize); + Core.camera.width = 999999f; + Core.camera.height = 999999f; + Core.camera.mat.set(Draw.proj()).mul(Tmp.m3.setToTranslation(tx, ty).scale(tw / (width * tilesize), th / (height * tilesize)).translate(4f, 4f)); + renderer.blocks.floor.drawFloor(); - boolean prev = renderer.animateWater; - renderer.animateWater = false; + Tmp.m2.set(Draw.proj()); - Core.camera.position.set(world.width()/2f * tilesize, world.height()/2f * tilesize); - Core.camera.width = 999999f; - Core.camera.height = 999999f; - Core.camera.mat.set(Draw.proj()).mul(Tmp.m3.setToTranslation(tx, ty).scale(tw / (width * tilesize), th / (height * tilesize)).translate(4f, 4f)); - renderer.blocks.floor.drawFloor(); + //scissors are always enabled because this is drawn clipped in UI, make sure they don't interfere with drawing shadow events + Gl.disable(Gl.scissorTest); - Tmp.m2.set(Draw.proj()); + renderer.blocks.processShadows(); - //this sure is awful! - Gl.disable(Gl.scissorTest); + Gl.enable(Gl.scissorTest); - renderer.blocks.processShadows(); + Draw.proj(Core.camera.mat); - Gl.enable(Gl.scissorTest); + Draw.shader(Shaders.darkness); + Draw.rect(Draw.wrap(renderer.blocks.getShadowBuffer().getTexture()), world.width() * tilesize/2f - tilesize/2f, world.height() * tilesize/2f - tilesize/2f, world.width() * tilesize, -world.height() * tilesize); + Draw.shader(); - Draw.proj(Core.camera.mat); + Draw.proj(Tmp.m2); - Draw.shader(Shaders.darkness); - Draw.rect(Draw.wrap(renderer.blocks.getShadowBuffer().getTexture()), world.width() * tilesize/2f - tilesize/2f, world.height() * tilesize/2f - tilesize/2f, world.width() * tilesize, -world.height() * tilesize); - Draw.shader(); + renderer.blocks.floor.beginDraw(); + renderer.blocks.floor.drawLayer(CacheLayer.walls); + renderer.animateWater = prev; - Draw.proj(Tmp.m2); + if(chunks == null) return; - renderer.blocks.floor.beginDraw(); - renderer.blocks.floor.drawLayer(CacheLayer.walls); - renderer.animateWater = prev; - return; - } + recacheChunks.each(i -> recacheChunk(Point2.x(i), Point2.y(i))); + recacheChunks.clear(); - clearEditor = Core.atlas.find("clear-editor"); - - updates.each(i -> render(i % width, i / width)); - updates.clear(); - - updates.addAll(delayedUpdates); - delayedUpdates.clear(); - - //???? - if(chunks == null){ - return; - } - - var texture = clearEditor.texture; + shader.bind(); + shader.setUniformMatrix4("u_projTrans", Core.camera.mat); for(int x = 0; x < chunks.length; x++){ for(int y = 0; y < chunks[0].length; y++){ - IndexedRenderer mesh = chunks[x][y]; + EditorSpriteCache mesh = chunks[x][y]; - if(mesh == null){ - continue; + if(mesh == null) continue; + + mesh.render(shader); + } + } + } + + void updateStatic(int x, int y){ + renderer.blocks.floor.recacheTile(x, y); + } + + void updateBlock(int x, int y){ + recacheChunks.add(Point2.pack(x / chunkSize, y / chunkSize)); + } + + void recache(){ + renderer.blocks.floor.clearTiles(); + renderer.blocks.reload(); + + for(int x = 0; x < chunks.length; x++){ + for(int y = 0; y < chunks[0].length; y++){ + recacheChunk(x, y); + } + } + } + + void recacheChunk(int cx, int cy){ + if(chunks[cx][cy] != null){ + chunks[cx][cy].dispose(); + chunks[cx][cy] = null; + } + + EditorSpriteCache cache = new EditorSpriteCache(renderer.blocks.floor.getVertexBuffer()); + + for(int x = cx * chunkSize; x < (cx + 1) * chunkSize; x++){ + for(int y = cy * chunkSize; y < (cy + 1) * chunkSize; y++){ + Tile tile = world.tile(x, y); + + if(tile != null && tile.block() != Blocks.air && tile.block().cacheLayer == CacheLayer.normal && tile.isCenter()){ + Block block = tile.block(); + + TextureRegion region = block.fullIcon; + + float width = region.width * region.scl(), height = region.height * region.scl(); + + cache.draw(block.fullIcon, + x * tilesize + block.offset - width / 2f, + y * tilesize + block.offset - height / 2f, + width/2f, height/2f, + width, height, + tile.build == null || !block.rotate ? 0 : tile.build.rotdeg(), + Color.whiteFloatBits); } - - mesh.getTransformMatrix().setToTranslation(tx, ty).scale(tw / (width * tilesize), th / (height * tilesize)); - mesh.setProjectionMatrix(Draw.proj()); - - mesh.render(texture); } } - } - public void updatePoint(int x, int y){ - updates.add(x + y * width); - } - - public void updateAll(){ - clearEditor = Core.atlas.find("clear-editor"); - for(int x = 0; x < width; x++){ - for(int y = 0; y < height; y++){ - render(x, y); - } + if(!cache.isEmpty()){ + cache.build(renderer.blocks.floor.getIndexData()); + chunks[cx][cy] = cache; } } - private TextureRegion getIcon(Block wall, int index){ - return !wall.fullIcon.found() ? - clearEditor : wall.variants > 0 ? - wall.variantRegions()[Mathf.randomSeed(index, 0, wall.variantRegions().length - 1)] : - wall.fullIcon; - } - - private void render(int wx, int wy){ - int x = wx / chunkSize, y = wy / chunkSize; - if(x >= chunks.length || y >= chunks[0].length) return; - IndexedRenderer mesh = chunks[x][y]; - Tile tile = editor.tiles().getn(wx, wy); - - Floor floor = tile.floor(); - Floor overlay = tile.overlay(); - Block wall = tile.block(); - - TextureRegion region; - - int idxWall = (wx % chunkSize) + (wy % chunkSize) * chunkSize; - int idxDecal = (wx % chunkSize) + (wy % chunkSize) * chunkSize + chunkSize * chunkSize; - boolean useSyntheticWall = overlay.wallOre; - - //draw synthetic wall or floor OR standard wall if wall ore - if(wall != Blocks.air && useSyntheticWall){ - region = getIcon(wall, idxWall); - - float width = region.width * region.scl(), height = region.height * region.scl(), ox = wall.offset + (tilesize - width) / 2f, oy = wall.offset + (tilesize - height) / 2f; - - //force fit to tile - if(overlay.wallOre && !wall.synthetic()){ - width = height = tilesize; - ox = oy = 0f; - } - - mesh.draw(idxWall, region, - wx * tilesize + ox, - wy * tilesize + oy, - width, height, - tile.build == null || !wall.rotate ? 0 : tile.build.rotdeg()); - }else{ - if(floor instanceof ColoredFloor){ - mesh.setColor(Tmp.c1.set(tile.extraData | 0xff)); - } - - region = floor.variantRegions()[Mathf.randomSeed(idxWall, 0, floor.variantRegions().length - 1)]; - - mesh.draw(idxWall, region, wx * tilesize, wy * tilesize, 8, 8); - } - - float offsetX = -((wall.size + 1) / 3) * tilesize, offsetY = -((wall.size + 1) / 3) * tilesize; - - //draw non-synthetic wall or ore - if(!(wall.update || wall.destructible) && !useSyntheticWall && wall != Blocks.air){ - region = getIcon(wall, idxWall); - - if(wall == Blocks.cliff){ - mesh.setColor(Tmp.c1.set(floor.mapColor).mul(1.6f)); - region = ((Cliff)Blocks.cliff).editorCliffs[tile.data & 0xff]; - }else if(wall instanceof ColoredWall){ - mesh.setColor(Tmp.c1.set(tile.extraData | 0xff)); - } - - offsetX = tilesize / 2f - region.width * region.scl() / 2f; - offsetY = tilesize / 2f - region.height * region.scl() / 2f; - }else if((wall == Blocks.air || overlay.wallOre) && !overlay.isAir()){ - if(floor.isLiquid){ - mesh.setColor(Tmp.c1.set(1f, 1f, 1f, floor.overlayAlpha)); - } - region = overlay.variantRegions()[Mathf.randomSeed(idxWall, 0, tile.overlay().variantRegions().length - 1)]; - }else{ - region = clearEditor; - } - - float width = region.width * region.scl(), height = region.height * region.scl(); - if(!wall.synthetic() && wall != Blocks.air && !wall.isMultiblock()){ - offsetX = offsetY = 0f; - width = height = tilesize; - } - - mesh.draw(idxDecal, region, wx * tilesize + offsetX, wy * tilesize + offsetY, width, height); - mesh.setColor(Color.white); - } - @Override public void dispose(){ - if(chunks == null){ - return; - } + if(chunks == null) return; + for(int x = 0; x < chunks.length; x++){ for(int y = 0; y < chunks[0].length; y++){ if(chunks[x][y] != null){ diff --git a/core/src/mindustry/editor/MapView.java b/core/src/mindustry/editor/MapView.java index 1932191986..e4f571bfb0 100644 --- a/core/src/mindustry/editor/MapView.java +++ b/core/src/mindustry/editor/MapView.java @@ -248,7 +248,7 @@ public class MapView extends Element implements GestureListener{ Draw.color(Pal.remove); Lines.stroke(2f); Lines.rect(centerx - sclwidth / 2 - 1, centery - sclheight / 2 - 1, sclwidth + 2, sclheight + 2); - editor.renderer.draw(centerx - sclwidth / 2 + Core.scene.marginLeft, centery - sclheight / 2 + Core.scene.marginBottom, sclwidth, sclheight, zoom); + editor.renderer.draw(centerx - sclwidth / 2 + Core.scene.marginLeft, centery - sclheight / 2 + Core.scene.marginBottom, sclwidth, sclheight); Draw.reset(); if(grid){ diff --git a/core/src/mindustry/graphics/CacheLayer.java b/core/src/mindustry/graphics/CacheLayer.java index bdd4e24713..fff6b5f332 100644 --- a/core/src/mindustry/graphics/CacheLayer.java +++ b/core/src/mindustry/graphics/CacheLayer.java @@ -101,7 +101,7 @@ public class CacheLayer{ renderer.effectBuffer.begin(); Core.graphics.clear(Color.clear); - renderer.blocks.floor.beginc(); + renderer.blocks.floor.beginDraw(); } @Override @@ -110,7 +110,7 @@ public class CacheLayer{ renderer.effectBuffer.end(); renderer.effectBuffer.blit(shader); - renderer.blocks.floor.beginc(); + renderer.blocks.floor.beginDraw(); } } } diff --git a/core/src/mindustry/graphics/FloorRenderer.java b/core/src/mindustry/graphics/FloorRenderer.java index 20fb0443f1..31922c8877 100644 --- a/core/src/mindustry/graphics/FloorRenderer.java +++ b/core/src/mindustry/graphics/FloorRenderer.java @@ -115,6 +115,10 @@ public class FloorRenderer{ return indexData; } + public float[] getVertexBuffer(){ + return vertices; + } + /** Queues up a cache change for a tile. Only runs in render loop. */ public void recacheTile(Tile tile){ recacheTile(tile.x, tile.y); @@ -183,14 +187,6 @@ public class FloorRenderer{ underwaterDraw.clear(); } - public void beginc(){ - shader.bind(); - shader.setUniformMatrix4("u_projectionViewMatrix", Core.camera.mat); - - //only ever use the base environment texture - texture.bind(0); - } - public void checkChanges(){ if(recacheSet.size > 0){ //recache one chunk at a time @@ -215,7 +211,11 @@ public class FloorRenderer{ Draw.flush(); - beginc(); + shader.bind(); + shader.setUniformMatrix4("u_projectionViewMatrix", Core.camera.mat); + + //only ever use the base environment texture + texture.bind(0); Gl.enable(Gl.blend); } @@ -343,7 +343,7 @@ public class FloorRenderer{ (cx+1) * tilesize * chunksize + tilesize/2f, (cy+1) * tilesize * chunksize + tilesize/2f); mesh.setVertices(vertices, 0, vidx); - //all vertices are shared + //all indices are shared and identical mesh.indices = indexData; return mesh; diff --git a/core/src/mindustry/graphics/IndexedRenderer.java b/core/src/mindustry/graphics/IndexedRenderer.java deleted file mode 100644 index 5b5a1e3203..0000000000 --- a/core/src/mindustry/graphics/IndexedRenderer.java +++ /dev/null @@ -1,211 +0,0 @@ -package mindustry.graphics; - -import arc.graphics.*; -import arc.graphics.g2d.*; -import arc.graphics.gl.*; -import arc.math.*; -import arc.util.*; -import mindustry.*; - -import java.nio.*; - -public class IndexedRenderer implements Disposable{ - private static final int vsize = 5; - - private final static Shader program = new Shader( - """ - attribute vec4 a_position; - attribute vec4 a_color; - attribute vec2 a_texCoord0; - uniform mat4 u_projTrans; - varying vec4 v_color; - varying vec2 v_texCoords; - void main(){ - v_color = a_color; - v_color.a = v_color.a * (255.0/254.0); - v_texCoords = a_texCoord0; - gl_Position = u_projTrans * a_position; - } - """, - - """ - varying lowp vec4 v_color; - varying vec2 v_texCoords; - uniform sampler2D u_texture; - void main(){ - gl_FragColor = v_color * texture2D(u_texture, v_texCoords); - } - """ - ); - private static final float[] tmpVerts = new float[vsize * 4]; - - private Mesh mesh; - private FloatBuffer buffer; - - private Mat projMatrix = new Mat(); - private Mat transMatrix = new Mat(); - private Mat combined = new Mat(); - private float color = Color.white.toFloatBits(); - - public IndexedRenderer(int sprites){ - resize(sprites); - } - - public void render(Texture texture){ - Gl.enable(Gl.blend); - - updateMatrix(); - - program.bind(); - texture.bind(); - - program.setUniformMatrix4("u_projTrans", combined); - - mesh.render(program, Gl.triangles, 0, mesh.getMaxVertices() * 6 / 4); - } - - public void setColor(Color color){ - this.color = color.toFloatBits(); - } - - public void draw(int index, TextureRegion region, float x, float y, float w, float h){ - float fx2 = x + w; - float fy2 = y + h; - float u = region.u; - float v = region.v2; - float u2 = region.u2; - float v2 = region.v; - - float[] vertices = tmpVerts; - float color = this.color; - - int idx = 0; - vertices[idx++] = x; - vertices[idx++] = y; - vertices[idx++] = color; - vertices[idx++] = u; - vertices[idx++] = v; - - vertices[idx++] = x; - vertices[idx++] = fy2; - vertices[idx++] = color; - vertices[idx++] = u; - vertices[idx++] = v2; - - vertices[idx++] = fx2; - vertices[idx++] = fy2; - vertices[idx++] = color; - vertices[idx++] = u2; - vertices[idx++] = v2; - - vertices[idx++] = fx2; - vertices[idx++] = y; - vertices[idx++] = color; - vertices[idx++] = u2; - vertices[idx++] = v; - - int dest = index * vsize * 4; - - buffer.position(dest); - buffer.put(vertices); - - //mark dirty - mesh.getVerticesBuffer(); - } - - public void draw(int index, TextureRegion region, float x, float y, float w, float h, float rotation){ - float u = region.u; - float v = region.v2; - float u2 = region.u2; - float v2 = region.v; - - float originX = w / 2, originY = h / 2; - - float cos = Mathf.cosDeg(rotation); - float sin = Mathf.sinDeg(rotation); - - float fx = -originX; - float fy = -originY; - float fx2 = w - originX; - float fy2 = h - originY; - - float worldOriginX = x + originX; - float worldOriginY = y + originY; - - float x1 = cos * fx - sin * fy + worldOriginX; - float y1 = sin * fx + cos * fy + worldOriginY; - float x2 = cos * fx - sin * fy2 + worldOriginX; - float y2 = sin * fx + cos * fy2 + worldOriginY; - float x3 = cos * fx2 - sin * fy2 + worldOriginX; - float y3 = sin * fx2 + cos * fy2 + worldOriginY; - float x4 = x1 + (x3 - x2); - float y4 = y3 - (y2 - y1); - - float[] vertices = tmpVerts; - float color = this.color; - - int idx = 0; - vertices[idx++] = x1; - vertices[idx++] = y1; - vertices[idx++] = color; - vertices[idx++] = u; - vertices[idx++] = v; - - vertices[idx++] = x2; - vertices[idx++] = y2; - vertices[idx++] = color; - vertices[idx++] = u; - vertices[idx++] = v2; - - vertices[idx++] = x3; - vertices[idx++] = y3; - vertices[idx++] = color; - vertices[idx++] = u2; - vertices[idx++] = v2; - - vertices[idx++] = x4; - vertices[idx++] = y4; - vertices[idx++] = color; - vertices[idx++] = u2; - vertices[idx++] = v; - - int dest = index * vsize * 4; - - buffer.position(dest); - buffer.put(vertices); - - //mark dirty - mesh.getVerticesBuffer(); - } - - public Mat getTransformMatrix(){ - return transMatrix; - } - - public void setProjectionMatrix(Mat matrix){ - projMatrix = matrix; - } - - public void resize(int sprites){ - if(mesh != null) mesh.dispose(); - - mesh = new Mesh(true, 4 * sprites, 0, - VertexAttribute.position, - VertexAttribute.color, - VertexAttribute.texCoords); - - buffer = mesh.getVerticesBuffer(); - buffer.limit(buffer.capacity()); - - mesh.indices = Vars.renderer.blocks.floor.getIndexData(); - } - - private void updateMatrix(){ - combined.set(projMatrix).mul(transMatrix); - } - - @Override - public void dispose(){ - mesh.dispose(); - } -}