From 71fbfffaecefb875628e9d664102cdf579192a9e Mon Sep 17 00:00:00 2001 From: Anuken Date: Fri, 19 Sep 2025 18:26:06 -0400 Subject: [PATCH] Buttons for toggling buildings/terrain in editor --- core/assets/bundles/bundle.properties | 4 +- core/src/mindustry/editor/EditorRenderer.java | 44 ++++++++++++++----- core/src/mindustry/editor/EditorTile.java | 4 ++ core/src/mindustry/editor/MapEditor.java | 1 + .../src/mindustry/editor/MapEditorDialog.java | 19 +++++--- .../src/mindustry/graphics/BlockRenderer.java | 26 ++++++++++- .../src/mindustry/graphics/FloorRenderer.java | 28 +++++++----- 7 files changed, 95 insertions(+), 31 deletions(-) diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index ab7bafc07e..e0684e5ebe 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -451,10 +451,12 @@ publish.confirm = Are you sure you want to publish this?\n\n[lightgray]Make sure publish.error = Error publishing item: {0} steam.error = Failed to initialize Steam services.\nError: {0} +editor.showblocks = Show Blocks +editor.showterrain = Show Terrain +editor.showfloor = Show Floor editor.planet = Planet: editor.sector = Sector: editor.seed = Seed: -editor.cliffs = Walls To Cliffs editor.brush = Brush editor.openin = Open In Editor editor.oregen = Ore Generation diff --git a/core/src/mindustry/editor/EditorRenderer.java b/core/src/mindustry/editor/EditorRenderer.java index 75b7c549be..7a23ccdb2e 100644 --- a/core/src/mindustry/editor/EditorRenderer.java +++ b/core/src/mindustry/editor/EditorRenderer.java @@ -85,7 +85,7 @@ public class EditorRenderer implements Disposable{ //don't process terrain updates every frame (helps with lag on low end devices) boolean doUpdate = Core.graphics.getFrameId() % 2 == 0; - if(doUpdate) renderer.blocks.floor.checkChanges(); + if(doUpdate) renderer.blocks.floor.checkChanges(!editor.showTerrain); boolean prev = renderer.animateWater; renderer.animateWater = false; @@ -95,14 +95,16 @@ public class EditorRenderer implements Disposable{ 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(); + if(editor.showFloor){ + renderer.blocks.floor.drawFloor(); + } Tmp.m2.set(Draw.proj()); //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); - if(doUpdate) renderer.blocks.processShadows(); + if(doUpdate) renderer.blocks.processShadows(!editor.showBuildings, !editor.showTerrain); Gl.enable(Gl.scissorTest); @@ -115,7 +117,9 @@ public class EditorRenderer implements Disposable{ Draw.proj(Tmp.m2); renderer.blocks.floor.beginDraw(); - renderer.blocks.floor.drawLayer(CacheLayer.walls); + if(editor.showTerrain){ + renderer.blocks.floor.drawLayer(CacheLayer.walls); + } renderer.animateWater = prev; if(chunks == null) return; @@ -125,16 +129,18 @@ public class EditorRenderer implements Disposable{ recacheChunks.clear(); } - shader.bind(); - shader.setUniformMatrix4("u_projTrans", Tmp.m1.set(Core.camera.mat).translate(-packPad, -packPad).scale(packWidth, packHeight)); + if(editor.showBuildings){ + shader.bind(); + 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++){ - EditorSpriteCache mesh = chunks[x][y]; + for(int x = 0; x < chunks.length; x++){ + for(int y = 0; y < chunks[0].length; y++){ + EditorSpriteCache mesh = chunks[x][y]; - if(mesh == null) continue; + if(mesh == null) continue; - mesh.render(shader); + mesh.render(shader); + } } } @@ -159,7 +165,7 @@ public class EditorRenderer implements Disposable{ } void recache(){ - renderer.blocks.floor.clearTiles(); + renderer.blocks.floor.reload(!editor.showTerrain); renderer.blocks.reload(); for(int x = 0; x < chunks.length; x++){ @@ -167,6 +173,20 @@ public class EditorRenderer implements Disposable{ recacheChunk(x, y); } } + //this causes 2 recaches, but it's necessary to fix the wrong shadows after a reload + if(!editor.showBuildings || !editor.showTerrain){ + recacheShadows(); + } + } + + void recacheTerrain(){ + renderer.blocks.floor.reload(!editor.showTerrain); + renderer.blocks.reload(); + recacheShadows(); + } + + void recacheShadows(){ + renderer.blocks.updateShadows(!editor.showBuildings, !editor.showTerrain); } void recacheChunk(int cx, int cy){ diff --git a/core/src/mindustry/editor/EditorTile.java b/core/src/mindustry/editor/EditorTile.java index 33c48a79d3..c68ecf9001 100644 --- a/core/src/mindustry/editor/EditorTile.java +++ b/core/src/mindustry/editor/EditorTile.java @@ -81,6 +81,10 @@ public class EditorTile extends Tile{ }else{ renderer.blocks.updateShadowTile(this); } + + if(build != null){ + build.wasVisible = true; + } } @Override diff --git a/core/src/mindustry/editor/MapEditor.java b/core/src/mindustry/editor/MapEditor.java index f04bd1339d..ff55266e17 100644 --- a/core/src/mindustry/editor/MapEditor.java +++ b/core/src/mindustry/editor/MapEditor.java @@ -32,6 +32,7 @@ public class MapEditor{ public int rotation; public Block drawBlock = Blocks.stone; public Team drawTeam = Team.sharded; + public boolean showTerrain = true, showFloor = true, showBuildings = true; public boolean isLoading(){ return loading; diff --git a/core/src/mindustry/editor/MapEditorDialog.java b/core/src/mindustry/editor/MapEditorDialog.java index 5f648b9c71..2972d3de60 100644 --- a/core/src/mindustry/editor/MapEditorDialog.java +++ b/core/src/mindustry/editor/MapEditorDialog.java @@ -650,10 +650,7 @@ public class MapEditorDialog extends Dialog implements Disposable{ tools.row(); - tools.table(Tex.underline, t -> t.add("@editor.teams")) - .colspan(3).height(40).width(size * 3f + 3f).padBottom(3); - - tools.row(); + tools.image(Tex.whiteui, Pal.gray).colspan(3).height(4f).width(size * 3f + 3f).row(); ButtonGroup teamgroup = new ButtonGroup<>(); @@ -695,10 +692,18 @@ public class MapEditorDialog extends Dialog implements Disposable{ mid.row(); + mid.check("@editor.showblocks", editor.showBuildings, b -> { + editor.showBuildings = b; + editor.renderer.recacheShadows(); + }).pad(2f).growX().with(Table::left).row(); + mid.check("@editor.showterrain", editor.showTerrain, b -> { + editor.showTerrain = b; + editor.renderer.recacheTerrain(); + }).pad(2f).growX().with(Table::left).row(); + mid.check("@editor.showfloor", editor.showFloor, b -> editor.showFloor = b).pad(2f).growX().with(Table::left).row(); + if(!mobile){ - mid.table(t -> { - t.button("@editor.center", Icon.move, Styles.flatt, view::center).growX().margin(9f); - }).growX().top(); + mid.button("@editor.center", Icon.move, Styles.flatt, view::center).growX().margin(9f); } }).margin(0).left().growY(); diff --git a/core/src/mindustry/graphics/BlockRenderer.java b/core/src/mindustry/graphics/BlockRenderer.java index 83e8990426..ebf8fc9b8d 100644 --- a/core/src/mindustry/graphics/BlockRenderer.java +++ b/core/src/mindustry/graphics/BlockRenderer.java @@ -154,6 +154,26 @@ public class BlockRenderer{ updateDarkness(); } + public void updateShadows(boolean ignoreBuildings, boolean ignoreTerrain){ + shadows.getTexture().setFilter(TextureFilter.linear, TextureFilter.linear); + shadows.resize(world.width(), world.height()); + shadows.begin(); + Core.graphics.clear(Color.white); + Draw.proj().setOrtho(0, 0, shadows.getWidth(), shadows.getHeight()); + + Draw.color(blendShadowColor); + + for(Tile tile : world.tiles){ + if(tile.block().displayShadow(tile) && (tile.build == null || tile.build.wasVisible) && !(ignoreBuildings && !tile.block().isStatic()) && !(ignoreTerrain && tile.block().isStatic())){ + Fill.rect(tile.x + 0.5f, tile.y + 0.5f, 1, 1); + } + } + + Draw.flush(); + Draw.color(); + shadows.end(); + } + public void updateDarkness(){ darkEvents.clear(); dark.getTexture().setFilter(TextureFilter.linear); @@ -303,6 +323,10 @@ public class BlockRenderer{ } public void processShadows(){ + processShadows(false, false); + } + + public void processShadows(boolean ignoreBuildings, boolean ignoreTerrain){ if(!shadowEvents.isEmpty()){ Draw.flush(); @@ -312,7 +336,7 @@ public class BlockRenderer{ for(Tile tile : shadowEvents){ if(tile == null) continue; //draw white/shadow color depending on blend - Draw.color((!tile.block().displayShadow(tile) || (state.rules.fog && tile.build != null && !tile.build.wasVisible)) ? Color.white : blendShadowColor); + Draw.color((!tile.block().displayShadow(tile) || (state.rules.fog && tile.build != null && !tile.build.wasVisible) || (ignoreBuildings && !tile.block().isStatic()) || (ignoreTerrain && tile.block().isStatic())) ? Color.white : blendShadowColor); Fill.rect(tile.x + 0.5f, tile.y + 0.5f, 1, 1); } diff --git a/core/src/mindustry/graphics/FloorRenderer.java b/core/src/mindustry/graphics/FloorRenderer.java index 1eb5e6d85a..ebc7c5c623 100644 --- a/core/src/mindustry/graphics/FloorRenderer.java +++ b/core/src/mindustry/graphics/FloorRenderer.java @@ -113,7 +113,7 @@ public class FloorRenderer{ } """); - Events.on(WorldLoadEvent.class, event -> clearTiles()); + Events.on(WorldLoadEvent.class, event -> reload()); } public IndexData getIndexData(){ @@ -162,7 +162,7 @@ public class FloorRenderer{ if(!Structs.inBounds(x, y, cache)) continue; if(cache[x][y].length == 0){ - cacheChunk(x, y); + cacheChunk(x, y, false); } ChunkMesh[] chunk = cache[x][y]; @@ -193,12 +193,16 @@ public class FloorRenderer{ } public void checkChanges(){ + checkChanges(false); + } + + public void checkChanges(boolean ignoreWalls){ if(recacheSet.size > 0){ //recache one chunk at a time IntSetIterator iterator = recacheSet.iterator(); while(iterator.hasNext){ int chunk = iterator.next(); - cacheChunk(Point2.x(chunk), Point2.y(chunk)); + cacheChunk(Point2.x(chunk), Point2.y(chunk), ignoreWalls); } recacheSet.clear(); @@ -278,13 +282,13 @@ public class FloorRenderer{ layer.end(); } - private void cacheChunk(int cx, int cy){ + private void cacheChunk(int cx, int cy, boolean ignoreWalls){ used.clear(); for(int tilex = Math.max(cx * chunksize - 1, 0); tilex < (cx + 1) * chunksize + 1 && tilex < world.width(); tilex++){ for(int tiley = Math.max(cy * chunksize - 1, 0); tiley < (cy + 1) * chunksize + 1 && tiley < world.height(); tiley++){ Tile tile = world.rawTile(tilex, tiley); - boolean wall = tile.block().cacheLayer != CacheLayer.normal; + boolean wall = !ignoreWalls && tile.block().cacheLayer != CacheLayer.normal; if(wall){ used.add(tile.block().cacheLayer); @@ -310,11 +314,11 @@ public class FloorRenderer{ } for(CacheLayer layer : used){ - meshes[layer.id] = cacheChunkLayer(cx, cy, layer); + meshes[layer.id] = cacheChunkLayer(cx, cy, layer, ignoreWalls); } } - private ChunkMesh cacheChunkLayer(int cx, int cy, CacheLayer layer){ + private ChunkMesh cacheChunkLayer(int cx, int cy, CacheLayer layer, boolean ignoreWalls){ vidx = 0; Batch current = Core.batch; @@ -333,7 +337,7 @@ public class FloorRenderer{ if(tile.block().cacheLayer == layer && layer == CacheLayer.walls && !(tile.isDarkened() && tile.data >= 5)){ tile.block().drawBase(tile); - }else if(floor.cacheLayer == layer && (world.isAccessible(tile.x, tile.y) || tile.block().cacheLayer != CacheLayer.walls || !tile.block().fillsTile)){ + }else if(floor.cacheLayer == layer && (ignoreWalls || world.isAccessible(tile.x, tile.y) || tile.block().cacheLayer != CacheLayer.walls || !tile.block().fillsTile)){ floor.drawBase(tile); }else if(floor.cacheLayer != layer && layer != CacheLayer.walls){ floor.drawNonLayer(tile, layer); @@ -355,7 +359,11 @@ public class FloorRenderer{ return mesh; } - public void clearTiles(){ + public void reload(){ + reload(false); + } + + public void reload(boolean ignoreWalls){ //dispose all old meshes if(cache != null){ for(var x : cache){ @@ -385,7 +393,7 @@ public class FloorRenderer{ for(int x = 0; x < chunksx; x++){ for(int y = 0; y < chunksy; y++){ - cacheChunk(x, y); + cacheChunk(x, y, ignoreWalls); } }