diff --git a/SPD-classes/src/main/java/com/watabou/noosa/Tilemap.java b/SPD-classes/src/main/java/com/watabou/noosa/Tilemap.java index f344cc35b..ad4fd1b76 100644 --- a/SPD-classes/src/main/java/com/watabou/noosa/Tilemap.java +++ b/SPD-classes/src/main/java/com/watabou/noosa/Tilemap.java @@ -22,6 +22,7 @@ package com.watabou.noosa; import java.nio.FloatBuffer; +import java.util.Arrays; import com.watabou.gltextures.SmartTexture; import com.watabou.gltextures.TextureCache; @@ -35,54 +36,48 @@ public class Tilemap extends Visual { protected SmartTexture texture; protected TextureFilm tileset; - + protected int[] data; protected int mapWidth; protected int mapHeight; protected int size; - + private float cellW; private float cellH; - + protected float[] vertices; - protected short[] bufferPositions; - protected short bufferLength; protected FloatBuffer quads; protected Vertexbuffer buffer; - + private volatile Rect updated; private boolean fullUpdate; private Rect updating; private int topLeftUpdating; private int bottomRightUpdating; - + public Tilemap( Object tx, TextureFilm tileset ) { - + super( 0, 0, 0, 0 ); - + this.texture = TextureCache.get( tx ); this.tileset = tileset; - + RectF r = tileset.get( 0 ); cellW = tileset.width( r ); cellH = tileset.height( r ); - + vertices = new float[16]; - + updated = new Rect(); } - + public void map( int[] data, int cols ) { - + this.data = data; - + mapWidth = cols; mapHeight = data.length / cols; size = mapWidth * mapHeight; - bufferPositions = new short[size]; - for (int i = 0; i < bufferPositions.length; i++) - bufferPositions[i] = -1; - bufferLength = 0; width = cellW * mapWidth; height = cellH * mapHeight; @@ -92,11 +87,10 @@ public class Tilemap extends Visual { updateMap(); } - //forces a full update, including new buffer and culling recalculation + //forces a full update, including new buffer public synchronized void updateMap(){ updated.set( 0, 0, mapWidth, mapHeight ); fullUpdate = true; - camX = null; } public synchronized void updateMapCell(int cell){ @@ -124,72 +118,66 @@ public class Tilemap extends Visual { for (int j=updating.left; j < updating.right; j++) { - //Currently if a none-rendered tile becomes rendered it will mess with culling in draw() - //However shifting the whole array is expensive, even with selective updating - //So right now I'm accepting this as an engine limitation, but support could be added. + if (topLeftUpdating == -1) + topLeftUpdating = pos; - //It's also worth noting that nothing is stopping the game from rendering tiles - //which will need to be visible in future as transparent, and accepting the small - //performance cost of rendering them before they become visible - if (needsRender(pos) || bufferPositions[pos] != -1) { - int bufferPos = bufferPositions[pos]; - if (bufferPos == -1){ - bufferPos = bufferPositions[pos] = bufferLength; - bufferLength ++; - } + bottomRightUpdating = pos + 1; - if (topLeftUpdating == 0) - topLeftUpdating = bufferPos; + quads.position(pos*16); - bottomRightUpdating = bufferPos + 1; + if (needsRender(pos)) { + RectF uv = tileset.get(data[pos]); - quads.position(bufferPos*16); - RectF uv = tileset.get( data[pos] ); + vertices[0] = x1; + vertices[1] = y1; - vertices[0] = x1; - vertices[1] = y1; + vertices[2] = uv.left; + vertices[3] = uv.top; - vertices[2] = uv.left; - vertices[3] = uv.top; + vertices[4] = x2; + vertices[5] = y1; - vertices[4] = x2; - vertices[5] = y1; + vertices[6] = uv.right; + vertices[7] = uv.top; - vertices[6] = uv.right; - vertices[7] = uv.top; + vertices[8] = x2; + vertices[9] = y2; - vertices[8] = x2; - vertices[9] = y2; + vertices[10] = uv.right; + vertices[11] = uv.bottom; - vertices[10] = uv.right; - vertices[11] = uv.bottom; + vertices[12] = x1; + vertices[13] = y2; - vertices[12] = x1; - vertices[13] = y2; + vertices[14] = uv.left; + vertices[15] = uv.bottom; - vertices[14] = uv.left; - vertices[15] = uv.bottom; + } else { - quads.put( vertices ); + //If we don't need to draw this tile simply set the quad to size 0 at 0, 0. + // This does result in the quad being drawn, but we are skipping all + // pixel-filling. This is better than fully skipping rendering as we + // don't need to manage a buffer of drawable tiles with insertions/deletions. + Arrays.fill(vertices, 0); } + quads.put(vertices); + pos++; x1 = x2; x2 += cellW; - + } - + y1 = y2; y2 += cellH; } } - int topLeft, bottomRight, length; + private int camX, camY, camW, camH; + private int topLeft, bottomRight, length; - //check these before updating, allows for cached values when the camera isn't moving. - Integer camX, camY, camW, camH; - @Override public void draw() { @@ -197,7 +185,6 @@ public class Tilemap extends Visual { if (!updated.isEmpty()) { updateVertices(); - quads.limit(bufferLength*16); if (buffer == null) buffer = new Vertexbuffer(quads); else { @@ -210,52 +197,36 @@ public class Tilemap extends Visual { bottomRightUpdating * 16); } } - topLeftUpdating = 0; + topLeftUpdating = -1; updating.setEmpty(); } Camera c = Camera.main; - - //If one is null they all are - if (camX == null - || camX != (int)c.scroll.x/16 - || camY != (int)c.scroll.y/16 - || camW != (int)Math.ceil(c.width/cellW) - || camH != (int)Math.ceil(c.height/cellH)){ - camX = (int)c.scroll.x/16; - camY = (int)c.scroll.y/16; - camW = (int)Math.ceil(c.width/cellW); - camH = (int)Math.ceil(c.height/cellH); - - if (camX >= mapWidth - || camY >= mapHeight - || camW + camW <= 0 - || camH + camH <= 0) - return; - - //determines the top-left visible tile, the bottom-right one, and the buffer length - //between them, this culls a good number of none-visible tiles while keeping to 1 draw - topLeft = Math.max(camX, 0) - + Math.max(camY*mapWidth, 0); - while(topLeft < bufferPositions.length && bufferPositions[topLeft] == -1) - topLeft++; - - bottomRight = Math.min(camX+camW, mapWidth-1) - + Math.min((camY+camH)*mapWidth, (mapHeight-1)*mapWidth); - while(bottomRight >= topLeft && bufferPositions[bottomRight] == -1) - bottomRight--; - - if (topLeft >= bufferPositions.length || bottomRight <= 0) - length = 0; - else - length = bufferPositions[bottomRight] - bufferPositions[topLeft] + 1; - } + camX = (int)c.scroll.x/16; + camY = (int)c.scroll.y/16; + camW = (int)Math.ceil(c.width/cellW); + camH = (int)Math.ceil(c.height/cellH); if (camX >= mapWidth || camY >= mapHeight || camW + camW <= 0 - || camH + camH <= 0 - || length <= 0) + || camH + camH <= 0) + return; + + //determines the top-left visible tile, the bottom-right one, and the buffer length + //between them, this culls a good number of none-visible tiles while keeping to 1 draw + topLeft = Math.max(camX, 0) + + Math.max(camY*mapWidth, 0); + + bottomRight = Math.min(camX+camW, mapWidth-1) + + Math.min((camY+camH)*mapWidth, (mapHeight-1)*mapWidth); + + if (topLeft >= size || bottomRight <= 0) + length = 0; + else + length = bottomRight - topLeft + 1; + + if (length <= 0) return; NoosaScript script = NoosaScriptNoLighting.get(); @@ -266,7 +237,7 @@ public class Tilemap extends Visual { script.camera( camera ); - script.drawQuadSet( buffer, length, bufferPositions[topLeft] ); + script.drawQuadSet( buffer, length, topLeft ); }