package net.fourbytes.shadow; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.IntMap; import com.badlogic.gdx.utils.LongMap; import net.fourbytes.shadow.systems.IParticleManager; import net.fourbytes.shadow.utils.Cache; /** * Placeholder for the layers in the levels. Processing happens in {@link Level}. * It is using long-coords given by the Coord class but most methods in this * class avoid using the Coords class itself to speed up performance (actually * to reduce overhead when calling external methods). */ public class Layer { protected final Cache<Array<Block>> cache = new Cache(Array.class, 32, new Object[] {false, 4, Block.class}, new Class[] {boolean.class, int.class, Class.class}); public static enum BlockMapSystem { coordinate, //Default, most performance, most garbage row, //performance decreased, less garbage column, //performance decreased, less garbage none //least performance, "no garbage" } public static BlockMapSystem bms = BlockMapSystem.coordinate; public static int round = 1; protected IntMap<Array<Block>> rowmap = new IntMap<Array<Block>>(256); protected LongMap<Array<Block>> blockmap = new LongMap<Array<Block>>(1024); public Level level; public Array<GameObject> inView = new Array<GameObject>(false, 512, GameObject.class); public Array<Block> blocks = new Array<Block>(false, 4096, Block.class); public Array<Entity> entities = new Array<Entity>(false, 512, Entity.class); public Array<Particle> particles = new Array<Particle>(false, 512, Particle.class); public LongMap<Chunk> chunkmap = new LongMap<Chunk>(256); public Array<Chunk> chunks = new Array<Chunk>(false, 256, Chunk.class); public final Color tint = new Color(1f, 1f, 1f, 1f); public Layer(Level level) { this.level = level; } public void add(GameObject go) { if (this != level.mainLayer) { level.mainLayer.add(go); } else { level.goIDMap.put(go.getID(), go); } long cc = (long) ((int)(go.pos.x/Chunk.size)) << 32 | ((int)(go.pos.y/Chunk.size)) & 0xFFFFFFFFL; Chunk chunk = chunkmap.get(cc); if (chunk == null) { chunk = new Chunk((int)(go.pos.x/Chunk.size), (int)(go.pos.y/Chunk.size), this); chunkmap.put(cc, chunk); chunks.add(chunk); } go.chunk = chunk; //long c = Coord.get(go.pos.x/round, go.pos.y/round); long c = (long) ((int)(go.pos.x/round)) << 32 | ((int)(go.pos.y/round)) & 0xFFFFFFFFL; if (go instanceof Block) { blocks.add((Block) go); chunk.blocks.add((Block) go); Array<Block> al = get0(c); if (al == null) { al = put0(c); } al.add((Block) go); chunk.dirtify(); if (!((Block) go).dynamic) { chunk.rerender = true; } } else if (go instanceof Particle) { particles.add((Particle) go); chunk.particles.add((Particle) go); } else if (go instanceof Entity) { entities.add((Entity) go); chunk.entities.add((Entity) go); } } public void remove(GameObject go) { if (this != level.mainLayer) { level.mainLayer.remove(go); } else { level.goIDMap.remove(go.getID()); } long cc = (long) ((int)(go.pos.x/Chunk.size)) << 32 | ((int)(go.pos.y/Chunk.size)) & 0xFFFFFFFFL; Chunk chunk = chunkmap.get(cc); //long c = Coord.get(go.pos.x/round, go.pos.y/round); long c = (long) ((int)(go.pos.x/round)) << 32 | ((int)(go.pos.y/round)) & 0xFFFFFFFFL; inView.removeValue(go, true); if (go instanceof Block) { blocks.removeValue((Block) go, true); if (chunk != null) { chunk.blocks.removeValue((Block) go, true); chunk.dirtify(); if (!((Block) go).dynamic) { chunk.rerender = true; } } Array<Block> al = get0(c); if (al != null) { al.removeValue((Block) go, true); if (al.size == 0) { remove0(c); } } } else if (go instanceof Particle) { if (this == level.mainLayer) { level.systems.get(IParticleManager.class).reset((Particle) go); } particles.removeValue((Particle) go, true); if (chunk != null) { chunk.particles.removeValue((Particle) go, true); } } else if (go instanceof Entity) { entities.removeValue((Entity) go, true); if (chunk != null) { chunk.entities.removeValue((Entity) go, true); } } go.chunk = null; if (chunk != null && chunk.blocks.size == 0 && chunk.particles.size == 0 && chunk.entities.size == 0) { chunkmap.remove(cc); chunks.removeValue(chunk, true); } } public void move(Block b, long oldc, long newc) { if (oldc == newc) { return; } if (this != level.mainLayer) { level.mainLayer.move(b, oldc, newc); } long oldcc = (long) (((int) (oldc >> 32)) / Chunk.size) << 32 | (((int) (oldc)) / Chunk.size) & 0xFFFFFFFFL; Chunk oldchunk = chunkmap.get(oldcc); if (oldchunk != null) { oldchunk.blocks.removeValue(b, true); if (!b.dynamic) { oldchunk.rerender = true; } if (oldchunk.blocks.size == 0 && oldchunk.particles.size == 0 && oldchunk.entities.size == 0) { chunkmap.remove(oldcc); chunks.removeValue(oldchunk, true); } } long newcc = (long) (((int) (newc >> 32)) / Chunk.size) << 32 | (((int) (newc)) / Chunk.size) & 0xFFFFFFFFL; Chunk newchunk = chunkmap.get(newcc); if (newchunk == null) { newchunk = new Chunk((((int) (newc >> 32)) / Chunk.size), (((int) (newc)) / Chunk.size), this); chunkmap.put(newcc, newchunk); chunks.add(newchunk); } if (newchunk != oldchunk) { newchunk.dirtify(); if (!b.dynamic) { oldchunk.rerender = true; } } b.chunk = newchunk; //oldc = Coord.div(oldc, round)); oldc = (long) (((int) (oldc >> 32)) / round) << 32 | (((int) (oldc)) / round) & 0xFFFFFFFFL; //newc = Coord.div(newc, round)); newc = (long) (((int) (newc >> 32)) / round) << 32 | (((int) (newc)) / round) & 0xFFFFFFFFL; Array<Block> oal = get0(oldc); Array<Block> nal = get0(newc); if (oal == nal) { return; } if (nal == null) { nal = put0(newc); } if (oal != null) { oal.removeValue(b, true); if (oal.size == 0) { remove0(oldc); } } nal.add(b); } public Array<Block> get(long c) { //int cx = Coord.getX(c); int cx = (int) (c >> 32); //int cy = Coord.getY(c); int cy = (int) c; //c = Coord.div(c, round)); c = (long) ((int)(cx/round)) << 32 | ((int)(cy/round)) & 0xFFFFFFFFL; Array<Block> vv = get0(c); Array<Block> v; if (round == 1 && bms == BlockMapSystem.coordinate) { v = vv; } else { v = cache.getNext(); v.clear(); if (vv != null) { for (int i = 0; i < vv.size; i++) { Block b = vv.items[i]; if (cx == (int) b.pos.x && cy == (int) b.pos.y) { v.add(b); } } } } if (vv != null && vv.size == 0) { remove0(c); } return v; } protected Array<Block> get0(long c){ if (bms == BlockMapSystem.coordinate) { return blockmap.get(c); } else if (bms == BlockMapSystem.row) { //rowmap.get(Coord.getY(c)); return rowmap.get((int) c); } else if (bms == BlockMapSystem.column) { //rowmap.get(Coord.getX(c)); return rowmap.get((int) (c >> 32)); } else if (bms == BlockMapSystem.none) { return blocks; } return null; } protected Array<Block> put0(long c){ Array<Block> al = null; if (bms == BlockMapSystem.coordinate) { al = new Array<Block>(false, 4, Block.class); blockmap.put(c, al); } else if (bms == BlockMapSystem.row) { al = new Array<Block>(false, 32, Block.class); //rowmap.put(Coord.getY(c), al); rowmap.put((int) c, al); } else if (bms == BlockMapSystem.column) { al = new Array<Block>(false, 32, Block.class); //rowmap.put(Coord.getX(c), al); rowmap.put((int) (c >> 32), al); } return al; } protected void remove0(long c){ if (bms == BlockMapSystem.coordinate) { blockmap.remove(c); } else if (bms == BlockMapSystem.row) { //rowmap.remove(Coord.getY(c)); rowmap.remove((int) c); } else if (bms == BlockMapSystem.column) { //rowmap.remove(Coord.getX(c)); rowmap.remove((int) (c >> 32)); } } }