Added support for changing cached floor/terrain

This commit is contained in:
Anuken
2020-03-03 17:01:09 -05:00
parent f1aadd97a8
commit bac1648d4b
12 changed files with 117 additions and 29 deletions

View File

@@ -1,12 +1,16 @@
#ifdef GL_ES #ifdef GL_ES
precision mediump float; precision mediump float;
precision lowp int;
#define INTEGER lowp int
#else
#define INTEGER int
#endif #endif
#define gradients false #define gradients false
const int MAX_COLORS = 10; const int MAX_COLORS = 10;
uniform int u_colornum; uniform INTEGER u_colornum;
uniform vec4 u_colors[MAX_COLORS]; uniform vec4 u_colors[MAX_COLORS];
varying float v_height; varying float v_height;

View File

@@ -1,3 +1,11 @@
#ifdef GL_ES
precision mediump float;
precision lowp int;
#define INTEGER lowp int
#else
#define INTEGER int
#endif
attribute vec4 a_position; attribute vec4 a_position;
attribute vec3 a_normal; attribute vec3 a_normal;
@@ -14,7 +22,7 @@ uniform float u_spread;
uniform float u_magnitude; uniform float u_magnitude;
uniform float u_seed; uniform float u_seed;
uniform int u_colornum; uniform INTEGER u_colornum;
varying float v_height; varying float v_height;

View File

@@ -169,6 +169,7 @@ public class Renderer implements ApplicationListener{
drawBackground(); drawBackground();
blocks.floor.checkChanges();
blocks.floor.drawFloor(); blocks.floor.drawFloor();
Groups.drawFloor(); Groups.drawFloor();

View File

@@ -99,6 +99,7 @@ public class World{
return tile.block().linked(tile); return tile.block().linked(tile);
} }
@NonNull
public Tile rawTile(int x, int y){ public Tile rawTile(int x, int y){
return tiles.getn(x, y); return tiles.getn(x, y);
} }

View File

@@ -1,5 +1,6 @@
package mindustry.editor; package mindustry.editor;
import arc.util.ArcAnnotate.*;
import mindustry.content.Blocks; import mindustry.content.Blocks;
import mindustry.core.GameState.State; import mindustry.core.GameState.State;
import mindustry.editor.DrawOperation.OpType; import mindustry.editor.DrawOperation.OpType;
@@ -20,7 +21,7 @@ public class EditorTile extends Tile{
} }
@Override @Override
public void setFloor(Floor type){ public void setFloor(@NonNull Floor type){
if(state.is(State.playing)){ if(state.is(State.playing)){
super.setFloor(type); super.setFloor(type);
return; return;

View File

@@ -42,9 +42,21 @@ public enum CacheLayer{
endShader(Shaders.slag); endShader(Shaders.slag);
} }
}, },
normal, normal(5),
walls; walls;
public static final CacheLayer[] all = values();
/** Capacity multiplier. */
public final int capacity;
CacheLayer(){
this(2);
}
CacheLayer(int capacity){
this.capacity = capacity;
}
public void begin(){ public void begin(){
} }

View File

@@ -16,11 +16,13 @@ import java.util.*;
import static mindustry.Vars.*; import static mindustry.Vars.*;
public class FloorRenderer implements Disposable{ public class FloorRenderer implements Disposable{
private final static int chunksize = 64; //TODO find out number with best performance
private final static int chunksize = mobile ? 16 : 32;
private Chunk[][] cache; private Chunk[][] cache;
private MultiCacheBatch cbatch; private MultiCacheBatch cbatch;
private IntSet drawnLayerSet = new IntSet(); private IntSet drawnLayerSet = new IntSet();
private IntSet recacheSet = new IntSet();
private IntArray drawnLayers = new IntArray(); private IntArray drawnLayers = new IntArray();
private ObjectSet<CacheLayer> used = new ObjectSet<>(); private ObjectSet<CacheLayer> used = new ObjectSet<>();
@@ -28,6 +30,11 @@ public class FloorRenderer implements Disposable{
Events.on(WorldLoadEvent.class, event -> clearTiles()); Events.on(WorldLoadEvent.class, event -> clearTiles());
} }
/**Queues up a cache change for a tile. Only runs in render loop. */
public void recacheTile(Tile tile){
recacheSet.add(Pos.get(tile.x / chunksize, tile.y / chunksize));
}
public void drawFloor(){ public void drawFloor(){
if(cache == null){ if(cache == null){
return; return;
@@ -41,7 +48,7 @@ public class FloorRenderer implements Disposable{
int camx = (int)(camera.position.x / (chunksize * tilesize)); int camx = (int)(camera.position.x / (chunksize * tilesize));
int camy = (int)(camera.position.y / (chunksize * tilesize)); int camy = (int)(camera.position.y / (chunksize * tilesize));
int layers = CacheLayer.values().length; int layers = CacheLayer.all.length;
drawnLayers.clear(); drawnLayers.clear();
drawnLayerSet.clear(); drawnLayerSet.clear();
@@ -77,7 +84,7 @@ public class FloorRenderer implements Disposable{
beginDraw(); beginDraw();
for(int i = 0; i < drawnLayers.size; i++){ for(int i = 0; i < drawnLayers.size; i++){
CacheLayer layer = CacheLayer.values()[drawnLayers.get(i)]; CacheLayer layer = CacheLayer.all[drawnLayers.get(i)];
drawLayer(layer); drawLayer(layer);
} }
@@ -93,6 +100,19 @@ public class FloorRenderer implements Disposable{
cbatch.endDraw(); cbatch.endDraw();
} }
public void checkChanges(){
if(recacheSet.size > 0){
//recache one chunk at a time
IntSetIterator iterator = recacheSet.iterator();
while(iterator.hasNext){
int chunk = iterator.next();
cacheChunk(Pos.x(chunk), Pos.y(chunk));
}
recacheSet.clear();
}
}
public void beginDraw(){ public void beginDraw(){
if(cache == null){ if(cache == null){
return; return;
@@ -146,16 +166,14 @@ public class FloorRenderer implements Disposable{
used.clear(); used.clear();
Chunk chunk = cache[cx][cy]; Chunk chunk = cache[cx][cy];
for(int tilex = cx * chunksize; tilex < (cx + 1) * chunksize; tilex++){ for(int tilex = cx * chunksize; tilex < (cx + 1) * chunksize && tilex < world.width(); tilex++){
for(int tiley = cy * chunksize; tiley < (cy + 1) * chunksize; tiley++){ for(int tiley = cy * chunksize; tiley < (cy + 1) * chunksize && tiley < world.height(); tiley++){
Tile tile = world.tile(tilex, tiley); Tile tile = world.rawTile(tilex, tiley);
if(tile != null){ if(tile.block().cacheLayer != CacheLayer.normal){
if(tile.block().cacheLayer != CacheLayer.normal){ used.add(tile.block().cacheLayer);
used.add(tile.block().cacheLayer); }else{
}else{ used.add(tile.floor().cacheLayer);
used.add(tile.floor().cacheLayer);
}
} }
} }
} }
@@ -169,7 +187,12 @@ public class FloorRenderer implements Disposable{
SpriteBatch current = Core.batch; SpriteBatch current = Core.batch;
Core.batch = cbatch; Core.batch = cbatch;
cbatch.beginCache(); //begin a new cache
if(chunk.caches[layer.ordinal()] == -1){
cbatch.beginCache();
}else{
cbatch.beginCache(chunk.caches[layer.ordinal()]);
}
for(int tilex = cx * chunksize; tilex < (cx + 1) * chunksize; tilex++){ for(int tilex = cx * chunksize; tilex < (cx + 1) * chunksize; tilex++){
for(int tiley = cy * chunksize; tiley < (cy + 1) * chunksize; tiley++){ for(int tiley = cy * chunksize; tiley < (cy + 1) * chunksize; tiley++){
@@ -191,13 +214,16 @@ public class FloorRenderer implements Disposable{
} }
} }
} }
Core.batch = current; Core.batch = current;
cbatch.reserve(layer.capacity * chunksize * chunksize);
chunk.caches[layer.ordinal()] = cbatch.endCache(); chunk.caches[layer.ordinal()] = cbatch.endCache();
} }
public void clearTiles(){ public void clearTiles(){
if(cbatch != null) cbatch.dispose(); if(cbatch != null) cbatch.dispose();
recacheSet.clear();
int chunksx = Mathf.ceil((float)(world.width()) / chunksize), int chunksx = Mathf.ceil((float)(world.width()) / chunksize),
chunksy = Mathf.ceil((float)(world.height()) / chunksize); chunksy = Mathf.ceil((float)(world.height()) / chunksize);
cache = new Chunk[chunksx][chunksy]; cache = new Chunk[chunksx][chunksy];
@@ -226,6 +252,8 @@ public class FloorRenderer implements Disposable{
} }
private class Chunk{ private class Chunk{
int[] caches = new int[CacheLayer.values().length]; /** Maps cache layer ID to cache ID in the batch.
* -1 means that this cache is unoccupied. */
int[] caches = new int[CacheLayer.all.length];
} }
} }

View File

@@ -40,6 +40,7 @@ public class MenuRenderer implements Disposable{
} }
private void generate(){ private void generate(){
world.beginMapLoad();
Tiles tiles = world.resize(width, height); Tiles tiles = world.resize(width, height);
Array<Block> ores = content.blocks().select(b -> b instanceof OreBlock); Array<Block> ores = content.blocks().select(b -> b instanceof OreBlock);
shadows = new FrameBuffer(width, height); shadows = new FrameBuffer(width, height);
@@ -159,6 +160,8 @@ public class MenuRenderer implements Disposable{
tile.setOverlay(ore); tile.setOverlay(ore);
} }
} }
world.endMapLoad();
} }
private void cache(){ private void cache(){

View File

@@ -21,9 +21,9 @@ public class Tile implements Position{
/** Tile entity, usually null. */ /** Tile entity, usually null. */
public Tilec entity; public Tilec entity;
public short x, y; public short x, y;
protected Block block; protected @NonNull Block block;
protected Floor floor; protected @NonNull Floor floor;
protected Floor overlay; protected @NonNull Floor overlay;
/** Rotation, 0-3. Also used to store offload location, in which case it can be any number.*/ /** Rotation, 0-3. Also used to store offload location, in which case it can be any number.*/
protected byte rotation; protected byte rotation;
/** Team ordinal. */ /** Team ordinal. */
@@ -175,10 +175,13 @@ public class Tile implements Position{
changed(); changed();
} }
/**This resets the overlay!*/ /** This resets the overlay! */
public void setFloor(@NonNull Floor type){ public void setFloor(@NonNull Floor type){
this.floor = type; this.floor = type;
this.overlay = (Floor)Blocks.air; this.overlay = (Floor)Blocks.air;
recache();
block.onProximityUpdate(this);
} }
/** Sets the floor, preserving overlay.*/ /** Sets the floor, preserving overlay.*/
@@ -188,6 +191,19 @@ public class Tile implements Position{
setOverlay(overlay); setOverlay(overlay);
} }
public void recache(){
if(!headless && !world.isGenerating()){
renderer.blocks.floor.recacheTile(this);
renderer.minimap.update(this);
for(int i = 0; i < 8; i++){
Tile other = world.tile(x + Geometry.d8[i].x, y + Geometry.d8[i].y);
if(other != null){
renderer.blocks.floor.recacheTile(other);
}
}
}
}
public void remove(){ public void remove(){
link().getLinkedTiles(other -> other.setBlock(Blocks.air)); link().getLinkedTiles(other -> other.setBlock(Blocks.air));
} }
@@ -441,10 +457,14 @@ public class Tile implements Position{
} }
protected void preChanged(){ protected void preChanged(){
block().removed(this); block.removed(this);
if(entity != null){ if(entity != null){
entity.removeFromProximity(); entity.removeFromProximity();
} }
//recache when static blocks get changed
if(block.isStatic()){
recache();
}
team = 0; team = 0;
} }
@@ -482,6 +502,11 @@ public class Tile implements Position{
updateOcclusion(); updateOcclusion();
world.notifyChanged(this); world.notifyChanged(this);
//recache when static block is added
if(block.isStatic()){
recache();
}
} }
@Override @Override

View File

@@ -234,15 +234,21 @@ public class Drill extends Block{
returnCount = oreCount.get(itemArray.peek(), 0); returnCount = oreCount.get(itemArray.peek(), 0);
} }
@Override
public void onProximityUpdate(Tile tile){
DrillEntity entity = tile.ent();
countOre(tile);
entity.dominantItem = returnItem;
entity.dominantItems = returnCount;
}
@Override @Override
public void update(Tile tile){ public void update(Tile tile){
DrillEntity entity = tile.ent(); DrillEntity entity = tile.ent();
if(entity.dominantItem == null){ if(entity.dominantItem == null){
countOre(tile); return;
if(returnItem == null) return;
entity.dominantItem = returnItem;
entity.dominantItems = returnCount;
} }
if(entity.timer(timerDump, dumpTime)){ if(entity.timer(timerDump, dumpTime)){

View File

@@ -1,3 +1,3 @@
org.gradle.daemon=true org.gradle.daemon=true
org.gradle.jvmargs=-Xms256m -Xmx1024m org.gradle.jvmargs=-Xms256m -Xmx1024m
archash=23a7b4c41d1723835af9b79aab1093384cfcc621 archash=80007985ae0f1cb24531272e910844d0b4b5bb18

View File

@@ -36,7 +36,6 @@ public class ZoneTests{
for(Zone zone : content.zones()){ for(Zone zone : content.zones()){
out.add(dynamicTest(zone.name, () -> { out.add(dynamicTest(zone.name, () -> {
zone.generator.init(zone.loadout);
logic.reset(); logic.reset();
try{ try{
//world.loadGenerator(zone.generator); //world.loadGenerator(zone.generator);