Merge branch 'render_refactor'

This commit is contained in:
Hannes Janetzek 2014-01-31 03:54:45 +01:00
commit 8b645a0e8f
23 changed files with 446 additions and 449 deletions

View File

@ -417,7 +417,7 @@ public class VectorTileLoader extends TileLoader implements IRenderTheme.Callbac
if (v != null) if (v != null)
minHeight = Integer.parseInt(v); minHeight = Integer.parseInt(v);
ExtrusionLayer l = (ExtrusionLayer) mTile.layers.extrusionLayers; ExtrusionLayer l = mTile.layers.getExtrusionLayers();
if (l == null) { if (l == null) {
double lat = MercatorProjection.toLatitude(mTile.y); double lat = MercatorProjection.toLatitude(mTile.y);
@ -425,7 +425,8 @@ public class VectorTileLoader extends TileLoader implements IRenderTheme.Callbac
* MercatorProjection.EARTH_CIRCUMFERENCE * MercatorProjection.EARTH_CIRCUMFERENCE
/ ((long) Tile.SIZE << mTile.zoomLevel)); / ((long) Tile.SIZE << mTile.zoomLevel));
mTile.layers.extrusionLayers = l = new ExtrusionLayer(0, groundScale, extrusion.colors); l = new ExtrusionLayer(0, groundScale, extrusion.colors);
mTile.layers.setExtrusionLayers(l);
} }
l.add(mElement, height, minHeight); l.add(mElement, height, minHeight);
} }

View File

@ -216,7 +216,7 @@ public class PathLayer extends Layer {
mMapPosition.copy(t.pos); mMapPosition.copy(t.pos);
// compile new layers // compile new layers
layers.baseLayers = t.layer.baseLayers; layers.setBaseLayers(t.layer.getBaseLayers());
compile(); compile();
} }
} }
@ -289,7 +289,7 @@ public class PathLayer extends Layer {
} }
if (size == 0) { if (size == 0) {
if (task.layer.baseLayers != null) { if (task.layer.getBaseLayers() != null) {
task.layer.clear(); task.layer.clear();
mMap.render(); mMap.render();
} }
@ -299,8 +299,6 @@ public class PathLayer extends Layer {
ElementLayers layers = task.layer; ElementLayers layers = task.layer;
LineLayer ll = layers.getLineLayer(0); LineLayer ll = layers.getLineLayer(0);
ll.clear();
ll.line = mLineStyle; ll.line = mLineStyle;
ll.width = ll.line.width; ll.width = ll.line.width;

View File

@ -115,7 +115,7 @@ public abstract class ItemizedLayer<Item extends MarkerItem> extends MarkerLayer
synchronized (lock) { synchronized (lock) {
if (mItems == null) { if (mItems == null) {
if (layers.textureLayers != null) { if (layers.getTextureLayers() != null) {
layers.clear(); layers.clear();
compile(); compile();
} }
@ -183,10 +183,9 @@ public abstract class ItemizedLayer<Item extends MarkerItem> extends MarkerLayer
mSymbolLayer.addSymbol(s); mSymbolLayer.addSymbol(s);
} }
} }
mSymbolLayer.prepare(); mSymbolLayer.prepare();
layers.textureLayers = mSymbolLayer; layers.setTextureLayers(mSymbolLayer);
compile(); compile();
} }

View File

@ -141,7 +141,7 @@ public class BitmapTileLayer extends TileLayer<TileLoader> {
BitmapLayer l = new BitmapLayer(false); BitmapLayer l = new BitmapLayer(false);
l.setBitmap(bitmap, Tile.SIZE, Tile.SIZE); l.setBitmap(bitmap, Tile.SIZE, Tile.SIZE);
mTile.layers = new ElementLayers(); mTile.layers = new ElementLayers();
mTile.layers.textureLayers = l; mTile.layers.setTextureLayers(l);
} }
@Override @Override

View File

@ -441,7 +441,7 @@ public class VectorTileLoader extends TileLoader implements IRenderTheme.Callbac
/ ((long) Tile.SIZE << mTile.zoomLevel)); / ((long) Tile.SIZE << mTile.zoomLevel));
l = new ExtrusionLayer(0, groundScale, extrusion.colors); l = new ExtrusionLayer(0, groundScale, extrusion.colors);
mTile.layers.add(l); mTile.layers.setExtrusionLayers(l);
} }
l.add(mElement, height, minHeight); l.add(mElement, height, minHeight);
} }

View File

@ -69,7 +69,7 @@ class TextRenderer extends ElementRenderer {
} }
// set new TextLayer to be uploaded and rendered // set new TextLayer to be uploaded and rendered
layers.textureLayers = t.layers; layers.setTextureLayers(t.layers);
mMapPosition = t.pos; mMapPosition = t.pos;
compile(); compile();
} }
@ -81,12 +81,12 @@ class TextRenderer extends ElementRenderer {
layers.vbo.bind(); layers.vbo.bind();
float scale = (float) (mMapPosition.scale / pos.scale); float scale = (float) (pos.scale / mMapPosition.scale);
setMatrix(pos, m, false); setMatrix(pos, m, false);
for (RenderElement l = layers.textureLayers; l != null;) for (RenderElement l = layers.getTextureLayers(); l != null;)
l = TextureLayer.Renderer.draw(l, scale, m); l = TextureLayer.Renderer.draw(l, m, scale);
} }
} }

View File

@ -62,7 +62,7 @@ public class BitmapRenderer extends ElementRenderer {
BitmapLayer l = new BitmapLayer(true); BitmapLayer l = new BitmapLayer(true);
l.setBitmap(mBitmap, mWidth, mHeight); l.setBitmap(mBitmap, mWidth, mHeight);
layers.textureLayers = l; layers.setTextureLayers(l);
mUpdateBitmap = true; mUpdateBitmap = true;
} }
@ -86,6 +86,6 @@ public class BitmapRenderer extends ElementRenderer {
@Override @Override
protected synchronized void render(MapPosition pos, Matrices m) { protected synchronized void render(MapPosition pos, Matrices m) {
m.useScreenCoordinates(false, 8); m.useScreenCoordinates(false, 8);
BitmapLayer.Renderer.draw(layers.textureLayers, m, 1, 1); BitmapLayer.Renderer.draw(layers.getTextureLayers(), m, 1, 1);
} }
} }

View File

@ -16,6 +16,13 @@
*/ */
package org.oscim.renderer; package org.oscim.renderer;
import static org.oscim.renderer.elements.RenderElement.BITMAP;
import static org.oscim.renderer.elements.RenderElement.LINE;
import static org.oscim.renderer.elements.RenderElement.MESH;
import static org.oscim.renderer.elements.RenderElement.POLYGON;
import static org.oscim.renderer.elements.RenderElement.SYMBOL;
import static org.oscim.renderer.elements.RenderElement.TEXLINE;
import java.nio.ShortBuffer; import java.nio.ShortBuffer;
import org.oscim.backend.GL20; import org.oscim.backend.GL20;
@ -51,11 +58,15 @@ public abstract class ElementRenderer extends LayerRenderer {
/** /**
* Use mMapPosition.copy(position) to keep the position for which * Use mMapPosition.copy(position) to keep the position for which
* the Overlay is _compiled_. NOTE: required by setMatrix utility * the Overlay is *compiled*. NOTE: required by setMatrix utility
* functions to draw this layer fixed to the map * functions to draw this layer fixed to the map
*/ */
protected MapPosition mMapPosition; protected MapPosition mMapPosition;
/** Wrap around dateline */
protected boolean mFlipOnDateLine = true;
/** Layer data for rendering */
public final ElementLayers layers; public final ElementLayers layers;
public ElementRenderer() { public ElementRenderer() {
@ -67,59 +78,55 @@ public abstract class ElementRenderer extends LayerRenderer {
* Render all 'layers' * Render all 'layers'
*/ */
@Override @Override
protected synchronized void render(MapPosition curPos, Matrices m) { protected synchronized void render(MapPosition pos, Matrices m) {
MapPosition pos = mMapPosition; MapPosition layerPos = mMapPosition;
float div = (float) (curPos.scale / pos.scale);
//float div = FastMath.pow(pos.zoomLevel - curPos.zoomLevel);
layers.vbo.bind(); layers.vbo.bind();
GLState.test(false, false); GLState.test(false, false);
GLState.blend(true); GLState.blend(true);
if (layers.baseLayers != null) { float div = (float) (pos.scale / layerPos.scale);
setMatrix(curPos, m, true);
for (RenderElement l = layers.baseLayers; l != null;) { RenderElement l = layers.getBaseLayers();
switch (l.type) {
case RenderElement.POLYGON:
l = PolygonLayer.Renderer.draw(curPos, l, m, true, 1, false);
break;
case RenderElement.LINE: if (l != null)
l = LineLayer.Renderer.draw(layers, l, curPos, m, div); setMatrix(pos, m, true);
break;
case RenderElement.TEXLINE: while (l != null) {
l = LineTexLayer.Renderer.draw(layers, l, curPos, m, div); if (l.type == POLYGON) {
break; l = PolygonLayer.Renderer.draw(l, m, pos, 1, true, 0);
continue;
case RenderElement.MESH: }
l = MeshLayer.Renderer.draw(pos, l, m); if (l.type == LINE) {
break; l = LineLayer.Renderer.draw(l, m, pos, div, layers);
continue;
default: }
log.debug("invalid layer"); if (l.type == TEXLINE) {
l = l.next; l = LineTexLayer.Renderer.draw(l, m, pos, div, layers);
continue;
}
if (l.type == MESH) {
l = MeshLayer.Renderer.draw(l, m, pos);
continue;
}
log.debug("invalid layer {}", l.type);
break; break;
} }
}
}
if (layers.textureLayers != null) { l = layers.getTextureLayers();
setMatrix(curPos, m, false); if (l != null)
setMatrix(pos, m, false);
for (RenderElement l = layers.textureLayers; l != null;) { while (l != null) {
switch (l.type) { if (l.type == BITMAP) {
case RenderElement.BITMAP:
l = BitmapLayer.Renderer.draw(l, m, 1, 1); l = BitmapLayer.Renderer.draw(l, m, 1, 1);
continue;
}
if (l.type == SYMBOL) {
l = TextureLayer.Renderer.draw(l, m, div);
continue;
}
log.debug("invalid layer {}", l.type);
break; break;
default:
l = TextureLayer.Renderer.draw(l, 1 / div, m);
}
}
} }
} }
@ -147,7 +154,7 @@ public abstract class ElementRenderer extends LayerRenderer {
public static boolean uploadLayers(ElementLayers layers, int newSize, public static boolean uploadLayers(ElementLayers layers, int newSize,
boolean addFill) { boolean addFill) {
// add fill coordinates
if (addFill) if (addFill)
newSize += 8; newSize += 8;
@ -192,11 +199,13 @@ public abstract class ElementRenderer extends LayerRenderer {
double x = oPos.x - position.x; double x = oPos.x - position.x;
double y = oPos.y - position.y; double y = oPos.y - position.y;
// wrap around date-line if (mFlipOnDateLine) {
// while (x < -1) //wrap around date-line
// x += 1.0; while (x < 0.5)
// while (x > 2) x += 1.0;
// x -= 1.0; while (x > 0.5)
x -= 1.0;
}
matrices.mvp.setTransScale((float) (x * tileScale), matrices.mvp.setTransScale((float) (x * tileScale),
(float) (y * tileScale), (float) (y * tileScale),

View File

@ -168,9 +168,9 @@ public class ExtrusionRenderer extends LayerRenderer {
} }
private static ExtrusionLayer getLayer(MapTile t) { private static ExtrusionLayer getLayer(MapTile t) {
if (t.layers != null && t.layers.extrusionLayers != null if (t.layers != null && t.layers.getExtrusionLayers() != null
&& t.state(MapTile.STATE_READY)) && t.state(MapTile.STATE_READY))
return (ExtrusionLayer) t.layers.extrusionLayers; return (ExtrusionLayer) t.layers.getExtrusionLayers();
return null; return null;
} }
@ -200,7 +200,7 @@ public class ExtrusionRenderer extends LayerRenderer {
GLState.test(false, false); GLState.test(false, false);
for (int i = 0; i < mTileCnt; i++) { for (int i = 0; i < mTileCnt; i++) {
ExtrusionLayer el = (ExtrusionLayer) tiles[i].layers.extrusionLayers; ExtrusionLayer el = tiles[i].layers.getExtrusionLayers();
setMatrix(pos, m, tiles[i], 0); setMatrix(pos, m, tiles[i], 0);
m.mvp.setAsUniform(uExtMatrix); m.mvp.setAsUniform(uExtMatrix);
@ -251,7 +251,7 @@ public class ExtrusionRenderer extends LayerRenderer {
// draw to depth buffer // draw to depth buffer
for (int i = 0; i < mTileCnt; i++) { for (int i = 0; i < mTileCnt; i++) {
MapTile t = tiles[i]; MapTile t = tiles[i];
ExtrusionLayer el = (ExtrusionLayer) t.layers.extrusionLayers; ExtrusionLayer el = t.layers.getExtrusionLayers();
int d = MapRenderer.depthOffset(t) * 10; int d = MapRenderer.depthOffset(t) * 10;
setMatrix(pos, m, t, d); setMatrix(pos, m, t, d);
m.mvp.setAsUniform(uExtMatrix); m.mvp.setAsUniform(uExtMatrix);
@ -277,7 +277,7 @@ public class ExtrusionRenderer extends LayerRenderer {
for (int i = 0; i < mTileCnt; i++) { for (int i = 0; i < mTileCnt; i++) {
MapTile t = tiles[i]; MapTile t = tiles[i];
ExtrusionLayer el = (ExtrusionLayer) t.layers.extrusionLayers; ExtrusionLayer el = t.layers.getExtrusionLayers();
if (el.colors == null) { if (el.colors == null) {
currentColor = mColor; currentColor = mColor;

View File

@ -137,7 +137,8 @@ public class GridRenderer extends ElementRenderer {
if (mText != null) { if (mText != null) {
addLabels(x, y, pos.zoomLevel); addLabels(x, y, pos.zoomLevel);
mLineLayer.clear();
layers.setBaseLayers(mLineLayer);
mLineLayer.addLine(mLines); mLineLayer.addLine(mLines);
} }

View File

@ -106,7 +106,7 @@ public class BitmapLayer extends TextureLayer {
buf[pos++] = texMax; buf[pos++] = texMax;
buf[pos++] = texMax; buf[pos++] = texMax;
setOffset(sbuf.position() * 2); this.offset = sbuf.position() * 2;
sbuf.put(buf); sbuf.put(buf);
} }
@ -215,7 +215,7 @@ public class BitmapLayer extends TextureLayer {
// draw up to maxVertices in each iteration // draw up to maxVertices in each iteration
for (int i = 0; i < t.vertices; i += maxVertices) { for (int i = 0; i < t.vertices; i += maxVertices) {
// to.offset * (24(shorts) * 2(short-bytes) / 6(indices) == 8) // to.offset * (24(shorts) * 2(short-bytes) / 6(indices) == 8)
int off = (t.offset + i) * 8 + tl.getOffset(); int off = (t.offset + i) * 8 + tl.offset;
GL.glVertexAttribPointer(hTextureVertex, 4, GL.glVertexAttribPointer(hTextureVertex, 4,
GL20.GL_SHORT, false, 12, off); GL20.GL_SHORT, false, 12, off);

View File

@ -16,15 +16,24 @@
*/ */
package org.oscim.renderer.elements; package org.oscim.renderer.elements;
import static org.oscim.renderer.elements.RenderElement.LINE;
import static org.oscim.renderer.elements.RenderElement.MESH;
import static org.oscim.renderer.elements.RenderElement.POLYGON;
import static org.oscim.renderer.elements.RenderElement.TEXLINE;
import java.nio.ShortBuffer; import java.nio.ShortBuffer;
import org.oscim.backend.GL20; import org.oscim.backend.GL20;
import org.oscim.renderer.BufferObject; import org.oscim.renderer.BufferObject;
import org.oscim.theme.styles.Line; import org.oscim.theme.styles.Line;
import org.oscim.utils.pool.Inlist;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
/**
* This class is primarily intended for rendering the vector elements of a
* MapTile. It can be used for other purposes as well but some optimizations
* applied probably wont make sense in different contexts.
*/
public class ElementLayers { public class ElementLayers {
static final Logger log = LoggerFactory.getLogger(ElementLayers.class); static final Logger log = LoggerFactory.getLogger(ElementLayers.class);
@ -42,12 +51,13 @@ public class ElementLayers {
} }
/** mixed Polygon- and LineLayer */ /** mixed Polygon- and LineLayer */
public RenderElement baseLayers; private RenderElement baseLayers;
/** Text- and SymbolLayer */ /** Text- and SymbolLayer */
public RenderElement textureLayers; private RenderElement textureLayers;
private RenderElement extrusionLayers;
public RenderElement extrusionLayers;
/** /**
* VBO holds all vertex data to draw lines and polygons after compilation. * VBO holds all vertex data to draw lines and polygons after compilation.
* Layout: * Layout:
@ -62,10 +72,9 @@ public class ElementLayers {
* To not need to switch VertexAttribPointer positions all the time: * To not need to switch VertexAttribPointer positions all the time:
* 1. polygons are packed in VBO at offset 0 * 1. polygons are packed in VBO at offset 0
* 2. lines afterwards at lineOffset * 2. lines afterwards at lineOffset
* 3. other layers keep their byte offset in RenderElement.offset * 3. other layers keep their byte offset in offset
*/ */
public int lineOffset; public int[] offset = { 0, 0 };
public int texLineOffset;
private RenderElement mCurLayer; private RenderElement mCurLayer;
@ -74,7 +83,7 @@ public class ElementLayers {
* ordered from bottom (0) to top * ordered from bottom (0) to top
*/ */
public LineLayer addLineLayer(int level, Line style) { public LineLayer addLineLayer(int level, Line style) {
LineLayer ll = (LineLayer) getLayer(level, RenderElement.LINE); LineLayer ll = (LineLayer) getLayer(level, LINE);
if (ll == null) if (ll == null)
return null; return null;
@ -89,7 +98,7 @@ public class ElementLayers {
* bottom (0) to top * bottom (0) to top
*/ */
public LineLayer getLineLayer(int level) { public LineLayer getLineLayer(int level) {
return (LineLayer) getLayer(level, RenderElement.LINE); return (LineLayer) getLayer(level, LINE);
} }
/** /**
@ -97,7 +106,7 @@ public class ElementLayers {
* bottom (0) to top * bottom (0) to top
*/ */
public MeshLayer getMeshLayer(int level) { public MeshLayer getMeshLayer(int level) {
return (MeshLayer) getLayer(level, RenderElement.MESH); return (MeshLayer) getLayer(level, MESH);
} }
/** /**
@ -105,7 +114,7 @@ public class ElementLayers {
* bottom (0) to top * bottom (0) to top
*/ */
public PolygonLayer getPolygonLayer(int level) { public PolygonLayer getPolygonLayer(int level) {
return (PolygonLayer) getLayer(level, RenderElement.POLYGON); return (PolygonLayer) getLayer(level, POLYGON);
} }
/** /**
@ -113,7 +122,7 @@ public class ElementLayers {
* bottom (0) to top * bottom (0) to top
*/ */
public LineTexLayer getLineTexLayer(int level) { public LineTexLayer getLineTexLayer(int level) {
return (LineTexLayer) getLayer(level, RenderElement.TEXLINE); return (LineTexLayer) getLayer(level, TEXLINE);
} }
public TextLayer addTextLayer(TextLayer textLayer) { public TextLayer addTextLayer(TextLayer textLayer) {
@ -122,32 +131,76 @@ public class ElementLayers {
return textLayer; return textLayer;
} }
private RenderElement getLayer(int level, byte type) { public void setBaseLayers(RenderElement layers) {
RenderElement l = baseLayers; for (RenderElement l = baseLayers; l != null; l = l.next)
RenderElement renderElement = null; l.clear();
if (!(type == RenderElement.LINE baseLayers = layers;
|| type == RenderElement.POLYGON }
|| type == RenderElement.TEXLINE
|| type == RenderElement.MESH)) public RenderElement getBaseLayers() {
throw new IllegalArgumentException("invalid layer type"); return baseLayers;
}
public void setTextureLayers(TextureLayer tl) {
for (RenderElement l = textureLayers; l != null; l = l.next)
l.clear();
textureLayers = tl;
}
public RenderElement getTextureLayers() {
return textureLayers;
}
public void setExtrusionLayers(ExtrusionLayer el) {
for (RenderElement l = extrusionLayers; l != null; l = l.next)
l.clear();
extrusionLayers = el;
}
public ExtrusionLayer getExtrusionLayers() {
return (ExtrusionLayer) extrusionLayers;
}
/** cleanup only when layers are not used by tile or overlay anymore! */
public void clear() {
setBaseLayers(null);
setTextureLayers(null);
setExtrusionLayers(null);
mCurLayer = null;
if (vbo != null)
vbo = BufferObject.release(vbo);
}
private RenderElement getLayer(int level, int type) {
RenderElement layer = null;
if (mCurLayer != null && mCurLayer.level == level) { if (mCurLayer != null && mCurLayer.level == level) {
renderElement = mCurLayer; layer = mCurLayer;
} else { if (layer.type != type) {
log.error("BUG wrong layer {} {} on layer {}",
layer.type, type, level);
throw new IllegalArgumentException();
}
return layer;
}
RenderElement l = baseLayers;
if (l == null || l.level > level) { if (l == null || l.level > level) {
// insert new layer at start /** insert new layer at start */
l = null; l = null;
} else { } else {
while (true) { while (true) {
// found layer /** found layer */
if (l.level == level) { if (l.level == level) {
renderElement = l; layer = l;
break; break;
} }
/** insert layer between current and next layer */
// insert new layer between current and next layer
if (l.next == null || l.next.level > level) if (l.next == null || l.next.level > level)
break; break;
@ -155,53 +208,50 @@ public class ElementLayers {
} }
} }
if (renderElement == null) { if (layer == null) {
// add a new RenderElement /** add a new RenderElement */
if (type == RenderElement.LINE) if (type == LINE)
renderElement = new LineLayer(level); layer = new LineLayer(level);
else if (type == RenderElement.POLYGON) else if (type == POLYGON)
renderElement = new PolygonLayer(level); layer = new PolygonLayer(level);
else if (type == RenderElement.TEXLINE) else if (type == TEXLINE)
renderElement = new LineTexLayer(level); layer = new LineTexLayer(level);
else if (type == RenderElement.MESH) else if (type == MESH)
renderElement = new MeshLayer(level); layer = new MeshLayer(level);
if (renderElement == null) if (layer == null)
throw new IllegalArgumentException(); throw new IllegalArgumentException();
if (l == null) { if (l == null) {
// insert at start /** insert at start */
renderElement.next = baseLayers; layer.next = baseLayers;
baseLayers = renderElement; baseLayers = layer;
} else { } else {
renderElement.next = l.next; layer.next = l.next;
l.next = renderElement; l.next = layer;
}
} }
} }
if (renderElement.type != type) { /** check if found layer matches requested type */
// check if found layer matches requested type if (layer.type != type) {
log.debug("BUG wrong layer " + renderElement.type + " " + type + log.error("BUG wrong layer {} {} on layer {}",
" on layer " + renderElement.level); layer.type, type, level);
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
mCurLayer = renderElement; mCurLayer = layer;
return renderElement; return layer;
} }
private final static int[] VERTEX_SHORT_CNT = { private final static int[] VERTEX_SHORT_CNT = {
4, // LINE_VERTEX_SHORTS 4, // LINE_VERTEX_SHORTS
6, // TEXLINE_VERTEX_SHORTS
2, // POLY_VERTEX_SHORTS 2, // POLY_VERTEX_SHORTS
2, // MESH_VERTEX_SHORTS 2, // MESH_VERTEX_SHORTS
6, // TEXLINE_VERTEX_SHORTS
}; };
private final static int TEXTURE_VERTEX_SHORTS = 6; private final static int TEXTURE_VERTEX_SHORTS = 6;
private final static int SHORT_BYTES = 2; private final static int SHORT_BYTES = 2;
public int getSize() { public int getSize() {
@ -217,51 +267,32 @@ public class ElementLayers {
} }
public void compile(ShortBuffer sbuf, boolean addFill) { public void compile(ShortBuffer sbuf, boolean addFill) {
// offset from fill coordinates
int pos = 0;
int size = 0;
if (addFill) { addLayerItems(sbuf, baseLayers, POLYGON, addFill ? 4 : 0);
pos = 4;
size = 8;
}
size += addLayerItems(sbuf, baseLayers, RenderElement.POLYGON, pos); offset[LINE] = sbuf.position() * SHORT_BYTES;
addLayerItems(sbuf, baseLayers, LINE, 0);
lineOffset = size * SHORT_BYTES; //offset[TEXLINE] = size * SHORT_BYTES;
size += addLayerItems(sbuf, baseLayers, RenderElement.LINE, 0);
texLineOffset = size * SHORT_BYTES;
for (RenderElement l = baseLayers; l != null; l = l.next) { for (RenderElement l = baseLayers; l != null; l = l.next) {
if (l.type == RenderElement.TEXLINE) { if (l.type == TEXLINE || l.type == MESH) {
addPoolItems(l, sbuf);
// add additional vertex for interleaving,
// see TexLineLayer.
sbuf.position(sbuf.position() + 6);
}
}
for (RenderElement l = baseLayers; l != null; l = l.next) {
if (l.type == RenderElement.MESH)
l.compile(sbuf); l.compile(sbuf);
} }
}
for (RenderElement l = textureLayers; l != null; l = l.next) { for (RenderElement l = textureLayers; l != null; l = l.next) {
//TextureLayer tl = (TextureLayer) l;
l.compile(sbuf); l.compile(sbuf);
} }
// extrusion layers are compiled by extrusion overlay
// for (RenderElement l = extrusionLayers; l != null; l = l.next) {
// ExtrusionLayer tl = (ExtrusionLayer) l;
// tl.compile(sbuf);
// }
} }
// optimization for Line- and PolygonLayer: /**
// collect all pool items and add back in one go * optimization for Line- and PolygonLayer:
private static int addLayerItems(ShortBuffer sbuf, RenderElement l, byte type, int pos) { * collect all pool items and add back in one go.
*/
private static int addLayerItems(ShortBuffer sbuf, RenderElement l,
int type, int pos) {
VertexItem last = null, items = null; VertexItem last = null, items = null;
int size = 0; int size = 0;
@ -283,7 +314,7 @@ public class ElementLayers {
if (last == null) if (last == null)
continue; continue;
l.setOffset(pos); l.offset = pos;
pos += l.numVertices; pos += l.numVertices;
last.next = items; last.next = items;
@ -298,8 +329,8 @@ public class ElementLayers {
} }
static void addPoolItems(RenderElement l, ShortBuffer sbuf) { static void addPoolItems(RenderElement l, ShortBuffer sbuf) {
// offset of layer data in vbo /** keep offset of layer data in vbo */
l.setOffset(sbuf.position() * SHORT_BYTES); l.offset = sbuf.position() * SHORT_BYTES;
for (VertexItem it = l.vertexItems; it != null; it = it.next) { for (VertexItem it = l.vertexItems; it != null; it = it.next) {
if (it.next == null) if (it.next == null)
@ -310,39 +341,4 @@ public class ElementLayers {
l.vertexItems = VertexItem.pool.releaseAll(l.vertexItems); l.vertexItems = VertexItem.pool.releaseAll(l.vertexItems);
} }
// cleanup only when layers are not used by tile or overlay anymore!
public void clear() {
// clear line and polygon layers directly
for (RenderElement l = baseLayers; l != null; l = l.next) {
if (l.vertexItems != null)
l.vertexItems = VertexItem.pool.releaseAll(l.vertexItems);
l.numVertices = 0;
}
for (RenderElement l = textureLayers; l != null; l = l.next)
l.clear();
for (RenderElement l = extrusionLayers; l != null; l = l.next)
l.clear();
baseLayers = null;
textureLayers = null;
extrusionLayers = null;
mCurLayer = null;
// if (vbo != null){
// BufferObject.release(vbo);
// vbo = null;
// }
}
public void add(ExtrusionLayer l) {
extrusionLayers = Inlist.appendItem(extrusionLayers, l);
}
public ExtrusionLayer getExtrusionLayers() {
return (ExtrusionLayer) extrusionLayers;
}
} }

View File

@ -16,8 +16,6 @@
*/ */
package org.oscim.renderer.elements; package org.oscim.renderer.elements;
import java.nio.ShortBuffer;
import org.oscim.backend.GL20; import org.oscim.backend.GL20;
import org.oscim.backend.GLAdapter; import org.oscim.backend.GLAdapter;
import org.oscim.backend.canvas.Paint.Cap; import org.oscim.backend.canvas.Paint.Cap;
@ -556,16 +554,6 @@ public final class LineLayer extends RenderElement {
si.used = opos; si.used = opos;
} }
@Override
public void clear() {
vertexItems = VertexItem.pool.releaseAll(vertexItems);
numVertices = 0;
}
@Override
protected void compile(ShortBuffer sbuf) {
}
public static final class Renderer { public static final class Renderer {
// TODO: http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter22.html // TODO: http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter22.html
@ -640,8 +628,8 @@ public final class LineLayer extends RenderElement {
return true; return true;
} }
public static RenderElement draw(ElementLayers layers, RenderElement curLayer, public static RenderElement draw(RenderElement curLayer, Matrices m,
MapPosition pos, Matrices m, float scale) { MapPosition pos, float scale, ElementLayers layers) {
if (curLayer == null) if (curLayer == null)
return null; return null;
@ -668,7 +656,7 @@ public final class LineLayer extends RenderElement {
GLState.enableVertexArrays(hLineVertexPosition[mode], -1); GLState.enableVertexArrays(hLineVertexPosition[mode], -1);
GL.glVertexAttribPointer(hLineVertexPosition[mode], 4, GL20.GL_SHORT, GL.glVertexAttribPointer(hLineVertexPosition[mode], 4, GL20.GL_SHORT,
false, 0, layers.lineOffset); false, 0, layers.offset[LINE]);
m.mvp.setAsUniform(hLineMatrix[mode]); m.mvp.setAsUniform(hLineMatrix[mode]);
@ -745,7 +733,7 @@ public final class LineLayer extends RenderElement {
} }
GL.glDrawArrays(GL20.GL_TRIANGLE_STRIP, GL.glDrawArrays(GL20.GL_TRIANGLE_STRIP,
l.getOffset(), l.numVertices); l.offset, l.numVertices);
continue; continue;
} }
@ -781,7 +769,7 @@ public final class LineLayer extends RenderElement {
} }
GL.glDrawArrays(GL20.GL_TRIANGLE_STRIP, GL.glDrawArrays(GL20.GL_TRIANGLE_STRIP,
o.getOffset(), o.numVertices); o.offset, o.numVertices);
} }
} }

View File

@ -246,12 +246,12 @@ public final class LineTexLayer extends RenderElement {
si.used = opos; si.used = opos;
} }
@Override
protected void clear() {
}
@Override @Override
protected void compile(ShortBuffer sbuf) { protected void compile(ShortBuffer sbuf) {
ElementLayers.addPoolItems(this, sbuf);
// add additional vertex for interleaving,
// see TexLineLayer.
sbuf.position(sbuf.position() + 6);
} }
public final static class Renderer { public final static class Renderer {
@ -329,8 +329,8 @@ public final class LineTexLayer extends RenderElement {
private final static int STRIDE = 12; private final static int STRIDE = 12;
private final static int LEN_OFFSET = 8; private final static int LEN_OFFSET = 8;
public static RenderElement draw(ElementLayers layers, RenderElement curLayer, public static RenderElement draw(RenderElement curLayer, Matrices m,
MapPosition pos, Matrices m, float div) { MapPosition pos, float div, ElementLayers layers) {
// shader failed to compile // shader failed to compile
if (shader == 0) if (shader == 0)
@ -369,7 +369,6 @@ public final class LineTexLayer extends RenderElement {
for (; l != null && l.type == RenderElement.TEXLINE; l = l.next) { for (; l != null && l.type == RenderElement.TEXLINE; l = l.next) {
LineTexLayer ll = (LineTexLayer) l; LineTexLayer ll = (LineTexLayer) l;
Line line = ll.line; Line line = ll.line;
int lOffset = l.getOffset();
GLUtils.setColor(hTexColor, line.stippleColor, 1); GLUtils.setColor(hTexColor, line.stippleColor, 1);
GLUtils.setColor(hBgColor, line.color, 1); GLUtils.setColor(hBgColor, line.color, 1);
@ -396,7 +395,7 @@ public final class LineTexLayer extends RenderElement {
numIndices = maxIndices; numIndices = maxIndices;
// i / 6 * (24 shorts per block * 2 short bytes) // i / 6 * (24 shorts per block * 2 short bytes)
int add = (lOffset + i * 8) + vOffset; int add = (l.offset + i * 8) + vOffset;
GL.glVertexAttribPointer(hVertexPosition0, GL.glVertexAttribPointer(hVertexPosition0,
4, GL20.GL_SHORT, false, STRIDE, 4, GL20.GL_SHORT, false, STRIDE,
@ -425,7 +424,7 @@ public final class LineTexLayer extends RenderElement {
if (numIndices > maxIndices) if (numIndices > maxIndices)
numIndices = maxIndices; numIndices = maxIndices;
// i / 6 * (24 shorts per block * 2 short bytes) // i / 6 * (24 shorts per block * 2 short bytes)
int add = (lOffset + i * 8) + vOffset; int add = (l.offset + i * 8) + vOffset;
GL.glVertexAttribPointer(hVertexPosition0, GL.glVertexAttribPointer(hVertexPosition0,
4, GL20.GL_SHORT, false, STRIDE, 4, GL20.GL_SHORT, false, STRIDE,

View File

@ -119,8 +119,8 @@ public class MeshLayer extends RenderElement {
return true; return true;
} }
public static RenderElement draw(MapPosition pos, RenderElement l, public static RenderElement draw(RenderElement l, Matrices m,
Matrices m) { MapPosition pos) {
GLState.blend(true); GLState.blend(true);
@ -144,7 +144,7 @@ public class MeshLayer extends RenderElement {
GLUtils.setColor(hColor, ml.area.color, 1); GLUtils.setColor(hColor, ml.area.color, 1);
GL.glVertexAttribPointer(hVertexPosition, 2, GL20.GL_SHORT, GL.glVertexAttribPointer(hVertexPosition, 2, GL20.GL_SHORT,
false, 0, ml.getOffset()); false, 0, ml.offset);
GL.glDrawElements(GL20.GL_TRIANGLES, ml.numIndices, GL.glDrawElements(GL20.GL_TRIANGLES, ml.numIndices,
GL20.GL_UNSIGNED_SHORT, 0); GL20.GL_UNSIGNED_SHORT, 0);

View File

@ -19,7 +19,6 @@ package org.oscim.renderer.elements;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.nio.FloatBuffer; import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import org.oscim.backend.GL20; import org.oscim.backend.GL20;
import org.oscim.backend.GLAdapter; import org.oscim.backend.GLAdapter;
@ -117,14 +116,6 @@ public final class PolygonLayer extends RenderElement {
si.used = outPos; si.used = outPos;
} }
@Override
protected void compile(ShortBuffer sbuf) {
}
@Override
protected void clear() {
}
public static final class Renderer { public static final class Renderer {
private static final int POLYGON_VERTICES_DATA_POS_OFFSET = 0; private static final int POLYGON_VERTICES_DATA_POS_OFFSET = 0;
@ -270,25 +261,25 @@ public final class PolygonLayer extends RenderElement {
/** /**
* draw polygon layers (unil layer.next is not polygon layer) * draw polygon layers (unil layer.next is not polygon layer)
* using stencil buffer method * using stencil buffer method
*
* @param pos
* used to fade layers accorind to 'fade'
* in layer.area.
* @param renderElement * @param renderElement
* layer to draw (referencing vertices in current vbo) * layer to draw (referencing vertices in current vbo)
* @param m * @param m
* current Matrices * current Matrices
* @param first * @param pos
* pass true to clear stencil buffer region * used to fade layers according to 'fade' in
* layer.area style
* @param div * @param div
* scale relative to 'base scale' of the tile * scale relative to 'base scale' of the tile
* @param clip * @param first
* pass true to clear stencil buffer region
* @param clipMode
* clip to first quad in current vbo * clip to first quad in current vbo
*
* @return * @return
* next layer * next layer
*/ */
public static RenderElement draw(MapPosition pos, RenderElement renderElement, public static RenderElement draw(RenderElement renderElement, Matrices m,
Matrices m, boolean first, float div, boolean clip) { MapPosition pos, float div, boolean first, int clipMode) {
GLState.test(false, true); GLState.test(false, true);
@ -314,7 +305,7 @@ public final class PolygonLayer extends RenderElement {
continue; continue;
if (cur == start) { if (cur == start) {
drawStencilRegion(first); drawStencilRegion(first, clipMode);
first = false; first = false;
// op for stencil method polygon drawing // op for stencil method polygon drawing
@ -326,7 +317,7 @@ public final class PolygonLayer extends RenderElement {
// set stencil mask to draw to // set stencil mask to draw to
GL.glStencilMask(1 << cur++); GL.glStencilMask(1 << cur++);
GL.glDrawArrays(GL20.GL_TRIANGLE_FAN, l.getOffset(), l.numVertices); GL.glDrawArrays(GL20.GL_TRIANGLE_FAN, l.offset, l.numVertices);
// draw up to 7 layers into stencil buffer // draw up to 7 layers into stencil buffer
if (cur == STENCIL_BITS - 1) { if (cur == STENCIL_BITS - 1) {
@ -338,9 +329,9 @@ public final class PolygonLayer extends RenderElement {
if (cur > 0) if (cur > 0)
fillPolygons(m, start, cur, zoom, scale, div); fillPolygons(m, start, cur, zoom, scale, div);
if (clip) { if (clipMode > 0) {
if (first) { if (first) {
drawStencilRegion(first); drawStencilRegion(first, clipMode);
// disable writes to stencil buffer // disable writes to stencil buffer
GL.glStencilMask(0x00); GL.glStencilMask(0x00);
// enable writes to color buffer // enable writes to color buffer
@ -359,7 +350,7 @@ public final class PolygonLayer extends RenderElement {
public static void clip(Matrices m) { public static void clip(Matrices m) {
setShader(polyShader, m); setShader(polyShader, m);
drawStencilRegion(true); drawStencilRegion(true, 1);
// disable writes to stencil buffer // disable writes to stencil buffer
GL.glStencilMask(0x00); GL.glStencilMask(0x00);
// enable writes to color buffer // enable writes to color buffer
@ -373,7 +364,7 @@ public final class PolygonLayer extends RenderElement {
* @param first in the first run the clip region is set based on * @param first in the first run the clip region is set based on
* depth buffer and depth buffer is updated * depth buffer and depth buffer is updated
*/ */
static void drawStencilRegion(boolean first) { static void drawStencilRegion(boolean first, int clipMode) {
// disable drawing to color buffer // disable drawing to color buffer
GL.glColorMask(false, false, false, false); GL.glColorMask(false, false, false, false);
@ -382,6 +373,21 @@ public final class PolygonLayer extends RenderElement {
GL.glStencilMask(0xFF); GL.glStencilMask(0xFF);
if (first) { if (first) {
// clear previous clip-region from stencil buffer
//GL.glClear(GL20.GL_STENCIL_BUFFER_BIT);
// Draw clip-region into depth and stencil buffer
// this is used for tile line and polygon layers.
// Depth offset is increased for each tile. Together
// with depth test (GL_LESS) this ensures to only
// draw where no other tile has drawn yet.
//GL.glEnable(GL20.GL_POLYGON_OFFSET_FILL);
if (clipMode > 1) {
// test GL_LESS and write to depth buffer
GLState.test(true, true);
GL.glDepthMask(true);
}
// always pass stencil test and set clip bit // always pass stencil test and set clip bit
GL.glStencilFunc(GL20.GL_ALWAYS, CLIP_BIT, 0x00); GL.glStencilFunc(GL20.GL_ALWAYS, CLIP_BIT, 0x00);
} else { } else {
@ -397,6 +403,12 @@ public final class PolygonLayer extends RenderElement {
GL.glDrawArrays(GL20.GL_TRIANGLE_STRIP, 0, 4); GL.glDrawArrays(GL20.GL_TRIANGLE_STRIP, 0, 4);
if (first) { if (first) {
if (clipMode > 1) {
// dont modify depth buffer
GL.glDepthMask(false);
// test only stencil
GLState.test(false, true);
}
GL.glStencilFunc(GL20.GL_EQUAL, CLIP_BIT, CLIP_BIT); GL.glStencilFunc(GL20.GL_EQUAL, CLIP_BIT, CLIP_BIT);
} }
} }

View File

@ -24,45 +24,45 @@ import org.oscim.utils.pool.Inlist;
public abstract class RenderElement extends Inlist<RenderElement> { public abstract class RenderElement extends Inlist<RenderElement> {
protected static GL20 GL; protected static GL20 GL;
public final static byte LINE = 0; public final static int LINE = 0;
public final static byte POLYGON = 1; public final static int TEXLINE = 1;
public final static byte MESH = 2; public final static int POLYGON = 2;
public final static byte TEXLINE = 3; public final static int MESH = 3;
public final static byte SYMBOL = 4; public final static int SYMBOL = 4;
public final static byte BITMAP = 5; public final static int BITMAP = 5;
public final static byte EXTRUSION = 6; public final static int EXTRUSION = 6;
protected RenderElement(byte type) { public final int type;
/** drawing order from bottom to top. */
int level;
/** number of vertices for this layer. */
protected int numVertices;
/** temporary list of vertex data. */
protected VertexItem vertexItems;
protected RenderElement(int type) {
this.type = type; this.type = type;
} }
public final byte type; /** clear all resources. */
protected void clear() {
if (vertexItems != null)
vertexItems = VertexItem.pool.releaseAll(vertexItems);
numVertices = 0;
}
/** drawing order from bottom to top */ /** compile vertex data to vbo. */
int level; protected void compile(ShortBuffer sbuf) {
/** number of vertices for this layer */ }
protected int numVertices;
protected VertexItem vertexItems;
abstract protected void compile(ShortBuffer sbuf);
abstract protected void clear();
/** /**
* for line and polygon layers: * For line- and polygon-layers this is the offset
* - number of VERTICES mOffset for this layertype in VBO * of VERTICES in its layers.vbo.
* otherwise: * For all other types it is the byte offset in vbo.
* - offset in byte in VBO
*/ */
private int mOffset; protected int offset;
public int getOffset() {
return mOffset;
}
public void setOffset(int offset) {
mOffset = offset;
}
} }

View File

@ -62,7 +62,7 @@ public final class SymbolLayer extends TextureLayer {
@Override @Override
protected void compile(ShortBuffer sbuf) { protected void compile(ShortBuffer sbuf) {
// offset of layer data in vbo // offset of layer data in vbo
setOffset(sbuf.position() * 2); //SHORT_BYTES; this.offset = sbuf.position() * 2; //SHORT_BYTES;
short numIndices = 0; short numIndices = 0;

View File

@ -42,7 +42,7 @@ public abstract class TextureLayer extends RenderElement {
TEXTURE_WIDTH, TEXTURE_WIDTH,
TEXTURE_HEIGHT); TEXTURE_HEIGHT);
protected TextureLayer(byte type) { protected TextureLayer(int type) {
super(type); super(type);
} }
@ -140,7 +140,7 @@ public abstract class TextureLayer extends RenderElement {
pool.init(0); pool.init(0);
} }
public static RenderElement draw(RenderElement l, float scale, Matrices m) { public static RenderElement draw(RenderElement l, Matrices m, float scale) {
GLState.test(false, false); GLState.test(false, false);
GLState.blend(true); GLState.blend(true);
@ -152,7 +152,7 @@ public abstract class TextureLayer extends RenderElement {
TextureLayer tl = (TextureLayer) l; TextureLayer tl = (TextureLayer) l;
if (tl.fixed) if (tl.fixed)
GL.glUniform1f(hTextureScale, scale); GL.glUniform1f(hTextureScale, 1 / scale);
else else
GL.glUniform1f(hTextureScale, 1); GL.glUniform1f(hTextureScale, 1);
@ -174,7 +174,7 @@ public abstract class TextureLayer extends RenderElement {
// draw up to maxVertices in each iteration // draw up to maxVertices in each iteration
for (int i = 0; i < t.vertices; i += maxVertices) { for (int i = 0; i < t.vertices; i += maxVertices) {
// to.offset * (24(shorts) * 2(short-bytes) / 6(indices) == 8) // to.offset * (24(shorts) * 2(short-bytes) / 6(indices) == 8)
int off = (t.offset + i) * 8 + tl.getOffset(); int off = (t.offset + i) * 8 + tl.offset;
GL.glVertexAttribPointer(hTextureVertex, 4, GL.glVertexAttribPointer(hTextureVertex, 4,
GL20.GL_SHORT, false, 12, off); GL20.GL_SHORT, false, 12, off);

View File

@ -56,7 +56,7 @@ public class AtlasRenderLayer extends ElementRenderer {
TextLayer tl = new TextLayer(); TextLayer tl = new TextLayer();
Text t = Text.createText(20, 0, Color.BLACK, 0, false); Text t = Text.createText(20, 0, Color.BLACK, 0, false);
layers.textureLayers = tl; layers.setTextureLayers(tl);
float[] points = new float[10]; float[] points = new float[10];

View File

@ -28,7 +28,7 @@ public class SymbolRenderLayer extends ElementRenderer {
public SymbolRenderLayer() { public SymbolRenderLayer() {
SymbolLayer l = new SymbolLayer(); SymbolLayer l = new SymbolLayer();
layers.textureLayers = l; layers.setTextureLayers(l);
SymbolItem it = SymbolItem.pool.get(); SymbolItem it = SymbolItem.pool.get();
it.billboard = false; it.billboard = false;

View File

@ -17,7 +17,6 @@
package org.oscim.tiling; package org.oscim.tiling;
import org.oscim.core.Tile; import org.oscim.core.Tile;
import org.oscim.renderer.BufferObject;
import org.oscim.renderer.elements.ElementLayers; import org.oscim.renderer.elements.ElementLayers;
import org.oscim.renderer.elements.SymbolItem; import org.oscim.renderer.elements.SymbolItem;
import org.oscim.renderer.elements.TextItem; import org.oscim.renderer.elements.TextItem;
@ -226,8 +225,6 @@ public class MapTile extends Tile {
*/ */
protected void clear() { protected void clear() {
if (layers != null) { if (layers != null) {
// TODO move this to layers clear
layers.vbo = BufferObject.release(layers.vbo);
layers.clear(); layers.clear();
layers = null; layers = null;
} }

View File

@ -16,6 +16,11 @@
*/ */
package org.oscim.tiling; package org.oscim.tiling;
import static org.oscim.renderer.elements.RenderElement.BITMAP;
import static org.oscim.renderer.elements.RenderElement.LINE;
import static org.oscim.renderer.elements.RenderElement.MESH;
import static org.oscim.renderer.elements.RenderElement.POLYGON;
import static org.oscim.renderer.elements.RenderElement.TEXLINE;
import static org.oscim.tiling.MapTile.STATE_NEW_DATA; import static org.oscim.tiling.MapTile.STATE_NEW_DATA;
import static org.oscim.tiling.MapTile.STATE_READY; import static org.oscim.tiling.MapTile.STATE_READY;
@ -25,6 +30,7 @@ import org.oscim.core.MapPosition;
import org.oscim.core.Tile; import org.oscim.core.Tile;
import org.oscim.renderer.BufferObject; import org.oscim.renderer.BufferObject;
import org.oscim.renderer.ElementRenderer; import org.oscim.renderer.ElementRenderer;
import org.oscim.renderer.GLMatrix;
import org.oscim.renderer.LayerRenderer; import org.oscim.renderer.LayerRenderer;
import org.oscim.renderer.MapRenderer; import org.oscim.renderer.MapRenderer;
import org.oscim.renderer.MapRenderer.Matrices; import org.oscim.renderer.MapRenderer.Matrices;
@ -59,6 +65,14 @@ public class TileRenderer extends LayerRenderer {
private int mRenderOverdraw; private int mRenderOverdraw;
private float mRenderAlpha; private float mRenderAlpha;
// Current number of frames drawn, used to not draw a
// tile twice per frame.
private int mDrawSerial;
private int mClipMode;
private GLMatrix mViewProj = new GLMatrix();
private Matrices mMatrices;
/** /**
* Threadsafe * Threadsafe
*/ */
@ -97,6 +111,15 @@ public class TileRenderer extends LayerRenderer {
mRenderAlpha = mAlpha; mRenderAlpha = mAlpha;
mRenderOverdraw = mOverdraw; mRenderOverdraw = mOverdraw;
/**
* discard depth projection from tilt, depth buffer
* is used for clipping
*/
mViewProj.copy(m.proj);
mViewProj.setValue(10, 0);
mViewProj.setValue(14, 0);
mViewProj.multiplyRhs(m.view);
int tileCnt = mDrawTiles.cnt; int tileCnt = mDrawTiles.cnt;
MapTile[] tiles = mDrawTiles.tiles; MapTile[] tiles = mDrawTiles.tiles;
@ -112,7 +135,69 @@ public class TileRenderer extends LayerRenderer {
BufferObject.checkBufferUsage(false); BufferObject.checkBufferUsage(false);
} }
draw(tiles, tileCnt, pos, m); mMatrices = m;
mClipMode = 1;
for (int i = 0; i < tileCnt; i++) {
MapTile t = tiles[i];
if (t.isVisible && t.state != STATE_READY) {
mClipMode = 2;
break;
}
}
/** draw visible tiles */
for (int i = 0; i < tileCnt; i++) {
MapTile t = tiles[i];
if (t.isVisible && t.state == STATE_READY)
drawTile(t, pos);
}
/**
* draw parent or children as proxy for visibile tiles that dont
* have data yet. Proxies are clipped to the region where nothing
* was drawn to depth buffer.
* TODO draw proxies for placeholder
*/
if (mClipMode > 1) {
mClipMode = 3;
//GL.glClear(GL20.GL_DEPTH_BUFFER_BIT);
GL.glDepthFunc(GL20.GL_LESS);
double scale = pos.getZoomScale();
for (int i = 0; i < tileCnt; i++) {
MapTile t = tiles[i];
if (t.isVisible
&& (t.state != STATE_READY)
&& (t.holder == null)) {
boolean preferParent = (scale > 1.5)
|| (pos.zoomLevel - t.zoomLevel < 0);
drawProxyTile(t, pos, true, preferParent);
}
}
/** draw grandparents */
for (int i = 0; i < tileCnt; i++) {
MapTile t = tiles[i];
if (t.isVisible
&& (t.state != STATE_READY)
&& (t.holder == null))
drawProxyTile(t, pos, false, false);
}
GL.glDepthMask(false);
}
/** make sure stencil buffer write is disabled */
GL.glStencilMask(0x00);
mDrawSerial++;
mMatrices = null;
}
@Override
protected void render(MapPosition position, Matrices matrices) {
// render in update() so that tiles cannot vanish in between.
} }
public void clearTiles() { public void clearTiles() {
@ -178,7 +263,8 @@ public class TileRenderer extends LayerRenderer {
return 1; return 1;
int newSize = tile.layers.getSize(); int newSize = tile.layers.getSize();
if (newSize > 0) { if (newSize <= 0)
return 1;
if (tile.layers.vbo == null) if (tile.layers.vbo == null)
tile.layers.vbo = BufferObject.get(GL20.GL_ARRAY_BUFFER, newSize); tile.layers.vbo = BufferObject.get(GL20.GL_ARRAY_BUFFER, newSize);
@ -191,7 +277,6 @@ public class TileRenderer extends LayerRenderer {
tile.layers = null; tile.layers = null;
return 0; return 0;
} }
}
return 1; return 1;
} }
@ -267,23 +352,15 @@ public class TileRenderer extends LayerRenderer {
tileSet.releaseTiles(); tileSet.releaseTiles();
} }
// Add additional tiles that serve as placeholer when flipping
// over date-line.
// I dont really like this but cannot think of a better solution:
// The other option would be to run scanbox each time for upload,
// drawing, proxies and text layer. Adding placeholder only
// happens rarely, unless you live on Fidschi
/* package */int mNumTileHolder; /* package */int mNumTileHolder;
/* package */TileSet mDrawTiles = new TileSet(); /* package */TileSet mDrawTiles = new TileSet();
// scanline fill class used to check tile visibility /** scanline fill class used to check tile visibility */
private final ScanBox mScanBox = new ScanBox() { private final ScanBox mScanBox = new ScanBox() {
@Override @Override
protected void setVisible(int y, int x1, int x2) { protected void setVisible(int y, int x1, int x2) {
int cnt = mDrawTiles.cnt;
MapTile[] tiles = mDrawTiles.tiles; MapTile[] tiles = mDrawTiles.tiles;
int cnt = mDrawTiles.cnt;
for (int i = 0; i < cnt; i++) { for (int i = 0; i < cnt; i++) {
MapTile t = tiles[i]; MapTile t = tiles[i];
@ -360,154 +437,78 @@ public class TileRenderer extends LayerRenderer {
return maxFade; return maxFade;
} }
// Current number of frames drawn, used to not draw a
// tile twice per frame.
private int mDrawSerial = 0;
private Matrices mMatrices;
/**
* Draw tiles:
*
* @param fade
* alpha value for bitmap tiles
* @param overdrawColor
* draw color on top, e.g. to darken the layer temporarily
*/
private void draw(MapTile[] tiles, int tileCnt, MapPosition pos, Matrices m) {
mMatrices = m;
/** draw visible tiles */
for (int i = 0; i < tileCnt; i++) {
MapTile t = tiles[i];
if (t.isVisible && t.state == STATE_READY)
drawTile(t, pos);
}
/**
* draw parent or children as proxy for visibile tiles that dont
* have data yet. Proxies are clipped to the region where nothing
* was drawn to depth buffer.
* TODO draw proxies for placeholder
*/
double scale = pos.getZoomScale();
for (int i = 0; i < tileCnt; i++) {
MapTile t = tiles[i];
if (t.isVisible && (t.state != STATE_READY) && (t.holder == null)) {
boolean preferParent = (scale > 1.5) || (pos.zoomLevel - t.zoomLevel < 0);
drawProxyTile(t, pos, true, preferParent);
}
}
/** draw grandparents */
for (int i = 0; i < tileCnt; i++) {
MapTile t = tiles[i];
if (t.isVisible && (t.state != STATE_READY) && (t.holder == null))
drawProxyTile(t, pos, false, false);
}
/** make sure stencil buffer write is disabled */
GL.glStencilMask(0x00);
GL.glDepthMask(false);
mDrawSerial++;
mMatrices = null;
}
private void drawTile(MapTile tile, MapPosition pos) { private void drawTile(MapTile tile, MapPosition pos) {
// draw parents only once /** ensure to draw parents only once */
if (tile.lastDraw == mDrawSerial) if (tile.lastDraw == mDrawSerial)
return; return;
tile.lastDraw = mDrawSerial; tile.lastDraw = mDrawSerial;
MapTile t = tile; /** use holder proxy when it is set */
if (t.holder != null) MapTile t = tile.holder == null ? tile : tile.holder;
t = t.holder;
if (t.layers == null || t.layers.vbo == null) { if (t.layers == null || t.layers.vbo == null)
//log.debug("missing data " + (t.layers == null) + " " + (t.vbo == null)); //throw new IllegalStateException(t + "no data " + (t.layers == null));
return; return;
}
t.layers.vbo.bind(); t.layers.vbo.bind();
// place tile relative to map position /** place tile relative to map position */
int z = tile.zoomLevel; int z = tile.zoomLevel;
float div = FastMath.pow(z - pos.zoomLevel); float div = FastMath.pow(z - pos.zoomLevel);
double tileScale = Tile.SIZE * pos.scale; double tileScale = Tile.SIZE * pos.scale;
float x = (float) ((tile.x - pos.x) * tileScale); float x = (float) ((tile.x - pos.x) * tileScale);
float y = (float) ((tile.y - pos.y) * tileScale); float y = (float) ((tile.y - pos.y) * tileScale);
// scale relative to zoom-level of this tile /** scale relative to zoom-level of this tile */
float scale = (float) (pos.scale / (1 << z)); float scale = (float) (pos.scale / (1 << z));
Matrices m = mMatrices; Matrices m = mMatrices;
m.mvp.setTransScale(x, y, scale / MapRenderer.COORD_SCALE); m.mvp.setTransScale(x, y, scale / MapRenderer.COORD_SCALE);
m.mvp.multiplyLhs(m.viewproj); m.mvp.multiplyLhs(mViewProj);
boolean clipped = false; boolean clipped = false;
int mode = mClipMode;
RenderElement l = t.layers.getBaseLayers();
for (RenderElement l = t.layers.baseLayers; l != null;) { while (l != null) {
switch (l.type) { if (l.type == POLYGON) {
case RenderElement.POLYGON: l = PolygonLayer.Renderer.draw(l, m, pos, div, !clipped, mode);
l = PolygonLayer.Renderer.draw(pos, l, m, !clipped, div, true);
clipped = true; clipped = true;
break; continue;
case RenderElement.LINE:
if (!clipped) {
clipped = true;
PolygonLayer.Renderer.draw(pos, null, m, true, div, true);
} }
l = LineLayer.Renderer.draw(t.layers, l, pos, m, scale);
break;
case RenderElement.TEXLINE:
if (!clipped) { if (!clipped) {
// draw stencil buffer clip region
PolygonLayer.Renderer.draw(null, m, pos, div, true, mode);
clipped = true; clipped = true;
PolygonLayer.Renderer.draw(pos, null, m, true, div, true);
} }
l = LineTexLayer.Renderer.draw(t.layers, l, pos, m, div); if (l.type == LINE) {
break; l = LineLayer.Renderer.draw(l, m, pos, scale, t.layers);
continue;
case RenderElement.MESH: }
if (!clipped) { if (l.type == TEXLINE) {
clipped = true; l = LineTexLayer.Renderer.draw(l, m, pos, div, t.layers);
PolygonLayer.Renderer.draw(pos, null, m, true, div, true); continue;
}
if (l.type == MESH) {
l = MeshLayer.Renderer.draw(l, m, pos);
continue;
} }
l = MeshLayer.Renderer.draw(pos, l, m);
break;
default:
// just in case // just in case
l = l.next; l = l.next;
} }
}
for (RenderElement l = t.layers.textureLayers; l != null;) { l = t.layers.getTextureLayers();
while (l != null) {
if (!clipped) { if (!clipped) {
// draw stencil buffer clip region PolygonLayer.Renderer.draw(null, m, pos, div, true, mode);
PolygonLayer.Renderer.draw(pos, null, m, true, div, true);
clipped = true; clipped = true;
} }
// if (!clipped) { if (l.type == BITMAP) {
// // draw stencil buffer clip region
// PolygonRenderer.clip(m);
// clipped = true;
// }
//GLState.test(false, false);
switch (l.type) {
case RenderElement.BITMAP:
l = BitmapLayer.Renderer.draw(l, m, 1, mRenderAlpha); l = BitmapLayer.Renderer.draw(l, m, 1, mRenderAlpha);
break; continue;
default:
l = l.next;
} }
l = l.next;
} }
if (t.fadeTime == 0) if (t.fadeTime == 0)
@ -612,8 +613,4 @@ public class TileRenderer extends LayerRenderer {
} }
} }
} }
@Override
protected void render(MapPosition position, Matrices matrices) {
}
} }