reorganize stencil buffer clipping
This commit is contained in:
parent
3da48e1ab9
commit
8046081b42
@ -54,7 +54,6 @@ public class BaseMap {
|
||||
mDrawCnt = 0;
|
||||
|
||||
GLES20.glDepthFunc(GLES20.GL_LESS);
|
||||
glStencilMask(0xFF);
|
||||
LineRenderer.beginLines();
|
||||
|
||||
for (int i = 0; i < tileCnt; i++) {
|
||||
@ -118,6 +117,8 @@ public class BaseMap {
|
||||
|
||||
// set depth offset (used for clipping to tile boundaries)
|
||||
GLES20.glPolygonOffset(1, mDrawCnt++);
|
||||
if (mDrawCnt > 20)
|
||||
mDrawCnt = 0;
|
||||
|
||||
GLES20.glBindBuffer(GL_ARRAY_BUFFER, t.vbo.id);
|
||||
|
||||
@ -144,12 +145,7 @@ public class BaseMap {
|
||||
}
|
||||
}
|
||||
|
||||
glStencilMask(0xFF);
|
||||
GLES20.glClear(GLES20.GL_STENCIL_BUFFER_BIT);
|
||||
//glStencilMask(0x0);
|
||||
|
||||
//PolygonRenderer.drawOver(mvp);
|
||||
//GLES20.glFlush();
|
||||
}
|
||||
|
||||
private static int drawProxyChild(MapTile tile, MapPosition pos) {
|
||||
@ -170,6 +166,8 @@ public class BaseMap {
|
||||
|
||||
private static void drawProxyTile(MapTile tile, MapPosition pos, boolean parent) {
|
||||
int diff = pos.zoomLevel - tile.zoomLevel;
|
||||
QuadTree r = tile.rel;
|
||||
MapTile proxy;
|
||||
|
||||
if (pos.scale > 1.5f || diff < 0) {
|
||||
// prefer drawing children
|
||||
@ -179,30 +177,32 @@ public class BaseMap {
|
||||
if (parent) {
|
||||
// draw parent proxy
|
||||
if ((tile.proxies & MapTile.PROXY_PARENT) != 0) {
|
||||
MapTile t = tile.rel.parent.tile;
|
||||
if (t.state == STATE_READY) {
|
||||
drawTile(t, pos);
|
||||
proxy = r.parent.tile;
|
||||
if (proxy.state == STATE_READY) {
|
||||
//Log.d(TAG, "1. draw parent " + proxy);
|
||||
drawTile(proxy, pos);
|
||||
}
|
||||
}
|
||||
} else if ((tile.proxies & MapTile.PROXY_GRAMPA) != 0) {
|
||||
// check if parent was already drawn
|
||||
if ((tile.proxies & MapTile.PROXY_PARENT) != 0) {
|
||||
MapTile t = tile.rel.parent.tile;
|
||||
if (t.state == STATE_READY)
|
||||
proxy = r.parent.tile;
|
||||
if (proxy.state == STATE_READY)
|
||||
return;
|
||||
}
|
||||
|
||||
MapTile t = tile.rel.parent.parent.tile;
|
||||
if (t.state == STATE_READY)
|
||||
drawTile(t, pos);
|
||||
proxy = r.parent.parent.tile;
|
||||
if (proxy.state == STATE_READY)
|
||||
drawTile(proxy, pos);
|
||||
}
|
||||
} else {
|
||||
// prefer drawing parent
|
||||
if (parent) {
|
||||
if ((tile.proxies & MapTile.PROXY_PARENT) != 0) {
|
||||
MapTile t = tile.rel.parent.tile;
|
||||
if (t != null && t.state == STATE_READY) {
|
||||
drawTile(t, pos);
|
||||
proxy = r.parent.tile;
|
||||
if (proxy != null && proxy.state == STATE_READY) {
|
||||
//Log.d(TAG, "2. draw parent " + proxy);
|
||||
drawTile(proxy, pos);
|
||||
return;
|
||||
|
||||
}
|
||||
@ -212,17 +212,17 @@ public class BaseMap {
|
||||
} else if ((tile.proxies & MapTile.PROXY_GRAMPA) != 0) {
|
||||
// check if parent was already drawn
|
||||
if ((tile.proxies & MapTile.PROXY_PARENT) != 0) {
|
||||
MapTile t = tile.rel.parent.tile;
|
||||
if (t.state == STATE_READY)
|
||||
proxy = r.parent.tile;
|
||||
if (proxy.state == STATE_READY)
|
||||
return;
|
||||
}
|
||||
// this will do nothing, just to check
|
||||
if (drawProxyChild(tile, pos) > 0)
|
||||
return;
|
||||
|
||||
MapTile t = tile.rel.parent.parent.tile;
|
||||
if (t.state == STATE_READY)
|
||||
drawTile(t, pos);
|
||||
proxy = r.parent.parent.tile;
|
||||
if (proxy.state == STATE_READY)
|
||||
drawTile(proxy, pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -45,9 +45,8 @@ import org.oscim.utils.GlUtils;
|
||||
import android.opengl.GLES20;
|
||||
|
||||
public final class PolygonRenderer {
|
||||
//private static final String TAG = PolygonRenderer.class.getName();
|
||||
private static final String TAG = PolygonRenderer.class.getName();
|
||||
|
||||
// private static final int NUM_VERTEX_SHORTS = 2;
|
||||
private static final int POLYGON_VERTICES_DATA_POS_OFFSET = 0;
|
||||
private static final int STENCIL_BITS = 8;
|
||||
private final static int CLIP_BIT = 0x80;
|
||||
@ -84,15 +83,15 @@ public final class PolygonRenderer {
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void fillPolygons(int zoom, float scale) {
|
||||
private static void fillPolygons(int start, int end, int zoom, float scale) {
|
||||
|
||||
/* draw to framebuffer */
|
||||
glColorMask(true, true, true, true);
|
||||
|
||||
/* do not modify stencil buffer */
|
||||
glStencilMask(0);
|
||||
glStencilMask(0x00);
|
||||
|
||||
for (int c = mStart; c < mCount; c++) {
|
||||
for (int c = start; c < end; c++) {
|
||||
Area a = mFillPolys[c].area;
|
||||
|
||||
if (a.fade >= zoom) {
|
||||
@ -132,7 +131,7 @@ public final class PolygonRenderer {
|
||||
}
|
||||
|
||||
// set stencil buffer mask used to draw this layer
|
||||
// also check that clip bit is 0 to avoid overdraw
|
||||
// also check that clip bit is set to avoid overdraw
|
||||
// of other tiles
|
||||
glStencilFunc(GL_EQUAL, 0xff, CLIP_BIT | 1 << c);
|
||||
|
||||
@ -141,10 +140,8 @@ public final class PolygonRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
// layers to fill
|
||||
// current layer to fill (0 - STENCIL_BITS-1)
|
||||
private static int mCount;
|
||||
// stencil buffer index to start fill
|
||||
private static int mStart;
|
||||
|
||||
/**
|
||||
* draw polygon layers (unil layer.next is not polygon layer)
|
||||
@ -166,29 +163,24 @@ public final class PolygonRenderer {
|
||||
public static Layer draw(MapPosition pos, Layer layer,
|
||||
float[] matrix, boolean first, boolean clip) {
|
||||
|
||||
int zoom = pos.zoomLevel;
|
||||
float scale = pos.scale;
|
||||
|
||||
GLState.useProgram(polygonProgram);
|
||||
|
||||
GLState.enableVertexArrays(hPolygonVertexPosition, -1);
|
||||
|
||||
glVertexAttribPointer(hPolygonVertexPosition, 2, GL_SHORT,
|
||||
false, 0, POLYGON_VERTICES_DATA_POS_OFFSET);
|
||||
|
||||
glUniformMatrix4fv(hPolygonMatrix, 1, false, matrix, 0);
|
||||
|
||||
// reset start when only one layer left in stencil buffer
|
||||
if (first || mCount > 5) {
|
||||
mStart = mCount = 0;
|
||||
} else {
|
||||
mStart = mCount;
|
||||
}
|
||||
|
||||
GLState.test(false, true);
|
||||
|
||||
Layer l = layer;
|
||||
GLState.useProgram(polygonProgram);
|
||||
GLState.enableVertexArrays(hPolygonVertexPosition, -1);
|
||||
glVertexAttribPointer(hPolygonVertexPosition, 2, GL_SHORT,
|
||||
false, 0, POLYGON_VERTICES_DATA_POS_OFFSET);
|
||||
glUniformMatrix4fv(hPolygonMatrix, 1, false, matrix, 0);
|
||||
|
||||
int zoom = pos.zoomLevel;
|
||||
int cur = mCount;
|
||||
|
||||
// reset start when only one layer left in stencil buffer
|
||||
if (first || cur > 5)
|
||||
cur = 0;
|
||||
|
||||
int start = cur;
|
||||
|
||||
Layer l = layer;
|
||||
for (; l != null && l.type == Layer.POLYGON; l = l.next) {
|
||||
PolygonLayer pl = (PolygonLayer) l;
|
||||
|
||||
@ -196,137 +188,131 @@ public final class PolygonRenderer {
|
||||
if (pl.area.fade > 0 && pl.area.fade > zoom)
|
||||
continue;
|
||||
|
||||
if (mCount == mStart) {
|
||||
drawStencilRegion(clip, first);
|
||||
if (cur == start) {
|
||||
drawStencilRegion(first);
|
||||
first = false;
|
||||
|
||||
// op for stencil method polygon drawing
|
||||
glStencilOp(GLES20.GL_KEEP, GLES20.GL_KEEP, GL_INVERT);
|
||||
//GLState.blend(false);
|
||||
}
|
||||
|
||||
mFillPolys[mCount] = pl;
|
||||
mFillPolys[cur] = pl;
|
||||
|
||||
// set stencil mask to draw to
|
||||
glStencilMask(1 << mCount++);
|
||||
glStencilMask(1 << cur++);
|
||||
|
||||
glDrawArrays(GL_TRIANGLE_FAN, l.offset, l.verticesCnt);
|
||||
|
||||
// draw up to 7 layers into stencil buffer
|
||||
if (mCount == STENCIL_BITS - 1) {
|
||||
fillPolygons(zoom, scale);
|
||||
mStart = mCount = 0;
|
||||
if (cur == STENCIL_BITS - 1) {
|
||||
fillPolygons(start, cur, zoom, pos.scale);
|
||||
start = cur = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (mCount > 0)
|
||||
fillPolygons(zoom, scale);
|
||||
if (cur > 0)
|
||||
fillPolygons(start, cur, zoom, pos.scale);
|
||||
|
||||
if (clip) {
|
||||
if (first) {
|
||||
drawStencilRegion(clip, first);
|
||||
drawStencilRegion(first);
|
||||
// disable writes to stencil buffer
|
||||
glStencilMask(0x00);
|
||||
// enable writes to color buffer
|
||||
glColorMask(true, true, true, true);
|
||||
} else {
|
||||
// set test for clip to tile region
|
||||
glStencilFunc(GL_EQUAL, CLIP_BIT, CLIP_BIT);
|
||||
}
|
||||
// clip to tile region
|
||||
glStencilFunc(GL_EQUAL, CLIP_BIT, CLIP_BIT);
|
||||
}
|
||||
|
||||
mCount = cur;
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param clip ...
|
||||
* @param first ...
|
||||
* Draw a tile filling rectangle to set stencil- and depth buffer
|
||||
* appropriately
|
||||
* @param first in the first run the clip region is set based on
|
||||
* depth buffer and depth buffer is updated
|
||||
*/
|
||||
static void drawStencilRegion(boolean clip, boolean first) {
|
||||
//if (!first && clip) {
|
||||
// // only clear 'layer-bits'
|
||||
// glStencilMask(0x7F);
|
||||
// GLES20.glClear(GLES20.GL_STENCIL_BUFFER_BIT);
|
||||
// glColorMask(false, false, false, false);
|
||||
// glStencilFunc(GL_EQUAL, CLIP_BIT, CLIP_BIT);
|
||||
// return;
|
||||
//}
|
||||
// disable drawing to framebuffer (will be re-enabled in fill)
|
||||
static void drawStencilRegion(boolean first) {
|
||||
|
||||
// disable drawing to color buffer
|
||||
glColorMask(false, false, false, false);
|
||||
|
||||
if (!first) {
|
||||
// write to all bits
|
||||
glStencilMask(0xFF);
|
||||
// write to all stencil bits
|
||||
glStencilMask(0xFF);
|
||||
|
||||
if (first) {
|
||||
// clear previous clip-region from stencil buffer
|
||||
GLES20.glClear(GLES20.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.
|
||||
GLES20.glEnable(GLES20.GL_POLYGON_OFFSET_FILL);
|
||||
|
||||
// test depth and write to depth buffer
|
||||
GLState.test(true, true);
|
||||
glDepthMask(true);
|
||||
|
||||
// always pass stencil test and set clip bit
|
||||
glStencilFunc(GL_ALWAYS, CLIP_BIT, 0x00);
|
||||
} else {
|
||||
// use clip bit from stencil buffer
|
||||
// to clear stencil 'layer-bits' (0x7f)
|
||||
glStencilFunc(GL_EQUAL, CLIP_BIT, CLIP_BIT);
|
||||
}
|
||||
|
||||
// set clip bit (0x80) for draw region
|
||||
glStencilOp(GLES20.GL_KEEP, GLES20.GL_KEEP, GLES20.GL_REPLACE);
|
||||
|
||||
if (clip) {
|
||||
if (first) {
|
||||
// draw clip-region into depth and stencil buffer:
|
||||
// this is used for tile line and polygon layers
|
||||
GLES20.glEnable(GLES20.GL_POLYGON_OFFSET_FILL);
|
||||
|
||||
// test depth and write to depth buffer
|
||||
GLState.test(true, true);
|
||||
glDepthMask(true);
|
||||
}
|
||||
}
|
||||
if (!clip || first) {
|
||||
// always pass stencil test:
|
||||
glStencilFunc(GL_ALWAYS, CLIP_BIT, CLIP_BIT);
|
||||
} else {
|
||||
// use clip region from stencil buffer
|
||||
// to clear stencil 'layer-bits' (0x7f)
|
||||
glStencilFunc(GL_EQUAL, CLIP_BIT, CLIP_BIT);
|
||||
}
|
||||
|
||||
// draw a quad for the tile region
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
if (clip) {
|
||||
if (first) {
|
||||
// dont modify depth buffer
|
||||
glDepthMask(false);
|
||||
|
||||
GLState.test(false, true);
|
||||
|
||||
GLES20.glDisable(GLES20.GL_POLYGON_OFFSET_FILL);
|
||||
}
|
||||
}
|
||||
|
||||
if (first) {
|
||||
// dont modify depth buffer
|
||||
glDepthMask(false);
|
||||
// test only stencil
|
||||
GLState.test(false, true);
|
||||
|
||||
GLES20.glDisable(GLES20.GL_POLYGON_OFFSET_FILL);
|
||||
|
||||
glStencilFunc(GL_EQUAL, CLIP_BIT, CLIP_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
static void drawOver(float[] matrix) {
|
||||
|
||||
GLState.useProgram(polygonProgram);
|
||||
|
||||
GLState.enableVertexArrays(hPolygonVertexPosition, -1);
|
||||
|
||||
glVertexAttribPointer(hPolygonVertexPosition, 2, GL_SHORT,
|
||||
false, 0, POLYGON_VERTICES_DATA_POS_OFFSET);
|
||||
|
||||
glUniformMatrix4fv(hPolygonMatrix, 1, false, matrix, 0);
|
||||
|
||||
/* clear stencilbuffer (tile region) by drawing
|
||||
* a quad with func 'always' and op 'zero' */
|
||||
|
||||
// disable drawing to framebuffer (will be re-enabled in fill)
|
||||
glColorMask(false, false, false, false);
|
||||
|
||||
// always pass stencil test:
|
||||
glStencilFunc(GL_ALWAYS, 0x00, 0x00);
|
||||
// write to all bits
|
||||
glStencilMask(0xFF);
|
||||
// zero out area to draw to
|
||||
glStencilOp(GLES20.GL_KEEP, GLES20.GL_KEEP, GLES20.GL_ZERO);
|
||||
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
glColorMask(true, true, true, true);
|
||||
}
|
||||
// static void drawOver(float[] matrix) {
|
||||
//
|
||||
// GLState.useProgram(polygonProgram);
|
||||
//
|
||||
// GLState.enableVertexArrays(hPolygonVertexPosition, -1);
|
||||
//
|
||||
// glVertexAttribPointer(hPolygonVertexPosition, 2, GL_SHORT,
|
||||
// false, 0, POLYGON_VERTICES_DATA_POS_OFFSET);
|
||||
//
|
||||
// glUniformMatrix4fv(hPolygonMatrix, 1, false, matrix, 0);
|
||||
//
|
||||
// /* clear stencilbuffer (tile region) by drawing
|
||||
// * a quad with func 'always' and op 'zero' */
|
||||
//
|
||||
// // disable drawing to framebuffer (will be re-enabled in fill)
|
||||
// glColorMask(false, false, false, false);
|
||||
//
|
||||
// // always pass stencil test:
|
||||
// glStencilFunc(GL_ALWAYS, 0x00, 0x00);
|
||||
// // write to all bits
|
||||
// glStencilMask(0xFF);
|
||||
// // zero out area to draw to
|
||||
// glStencilOp(GLES20.GL_KEEP, GLES20.GL_KEEP, GLES20.GL_ZERO);
|
||||
//
|
||||
// glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
// glColorMask(true, true, true, true);
|
||||
// }
|
||||
|
||||
private static float[] debugFillColor = { 0.3f, 0.0f, 0.0f, 0.3f };
|
||||
private static float[] debugFillColor2 = { .8f, .8f, .8f, .8f };
|
||||
|
Loading…
x
Reference in New Issue
Block a user