reorganize stencil buffer clipping

This commit is contained in:
Hannes Janetzek 2013-02-04 02:00:30 +01:00
parent 3da48e1ab9
commit 8046081b42
2 changed files with 123 additions and 137 deletions

View File

@ -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);
}
}
}

View File

@ -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 };