- use Stencil instead of Depth for clipping test

to avoid drawing everything with polygonOffset
- add GLState.useProgram
This commit is contained in:
Hannes Janetzek 2013-01-30 04:05:44 +01:00
parent 5f03a33492
commit be748138ac
9 changed files with 297 additions and 167 deletions

View File

@ -16,7 +16,6 @@ package org.oscim.renderer;
import static android.opengl.GLES20.GL_ARRAY_BUFFER; import static android.opengl.GLES20.GL_ARRAY_BUFFER;
import static android.opengl.GLES20.GL_BLEND; import static android.opengl.GLES20.GL_BLEND;
import static android.opengl.GLES20.GL_POLYGON_OFFSET_FILL;
import static org.oscim.generator.JobTile.STATE_READY; import static org.oscim.generator.JobTile.STATE_READY;
import org.oscim.core.MapPosition; import org.oscim.core.MapPosition;
@ -31,7 +30,7 @@ import android.opengl.Matrix;
* @author Hannes Janetzek * @author Hannes Janetzek
*/ */
public class BaseMap { public class BaseMap {
private final static String TAG = BaseMap.class.getName(); //private final static String TAG = BaseMap.class.getName();
// used to not draw a tile twice per frame. // used to not draw a tile twice per frame.
private static int mDrawSerial = 0; private static int mDrawSerial = 0;
@ -52,10 +51,10 @@ public class BaseMap {
static void draw(MapTile[] tiles, int tileCnt, MapPosition pos) { static void draw(MapTile[] tiles, int tileCnt, MapPosition pos) {
//long start = SystemClock.uptimeMillis(); //long start = SystemClock.uptimeMillis();
Matrix.multiplyMM(mVPMatrix, 0, mfProjMatrix, 0, pos.viewMatrix, 0); Matrix.multiplyMM(mVPMatrix, 0, mfProjMatrix, 0, pos.viewMatrix, 0);
mDrawCnt = 0; mDrawCnt = 0;
GLES20.glEnable(GL_POLYGON_OFFSET_FILL); GLES20.glDepthFunc(GLES20.GL_LESS);
LineRenderer.beginLines(); LineRenderer.beginLines();
for (int i = 0; i < tileCnt; i++) { for (int i = 0; i < tileCnt; i++) {
MapTile t = tiles[i]; MapTile t = tiles[i];
@ -63,9 +62,8 @@ public class BaseMap {
drawTile(t, pos); drawTile(t, pos);
} }
// proxies are clipped to the region where nothing was drawn to depth // proxies are clipped to the region where nothing was drawn to depth buffer.
// buffer. // draw child or parent proxies.
// TODO draw all parent before grandparent
// TODO draw proxies for placeholder... // TODO draw proxies for placeholder...
for (int i = 0; i < tileCnt; i++) { for (int i = 0; i < tileCnt; i++) {
MapTile t = tiles[i]; MapTile t = tiles[i];
@ -73,6 +71,7 @@ public class BaseMap {
drawProxyTile(t, pos, true); drawProxyTile(t, pos, true);
} }
// draw grandparents
for (int i = 0; i < tileCnt; i++) { for (int i = 0; i < tileCnt; i++) {
MapTile t = tiles[i]; MapTile t = tiles[i];
if (t.isVisible && (t.state != STATE_READY) && (t.holder == null)) if (t.isVisible && (t.state != STATE_READY) && (t.holder == null))
@ -81,8 +80,6 @@ public class BaseMap {
LineRenderer.endLines(); LineRenderer.endLines();
GLES20.glDisable(GL_POLYGON_OFFSET_FILL);
//GLES20.glFinish();
//long end = SystemClock.uptimeMillis(); //long end = SystemClock.uptimeMillis();
//Log.d(TAG, "base took " + (end - start)); //Log.d(TAG, "base took " + (end - start));
mDrawSerial++; mDrawSerial++;
@ -103,9 +100,10 @@ public class BaseMap {
if (t.holder != null) if (t.holder != null)
t = t.holder; t = t.holder;
if (t.layers == null || t.vbo == null) if (t.layers == null || t.vbo == null) {
//Log.d(TAG, "missing data " + (t.layers == null) + " " + (t.vbo == null));
return; return;
}
// set Model matrix for tile // set Model matrix for tile
float div = FastMath.pow(tile.zoomLevel - pos.zoomLevel); float div = FastMath.pow(tile.zoomLevel - pos.zoomLevel);
float x = (float) (tile.pixelX - pos.x * div); float x = (float) (tile.pixelX - pos.x * div);
@ -117,8 +115,7 @@ public class BaseMap {
Matrix.multiplyMM(mvp, 0, mVPMatrix, 0, mvp, 0); Matrix.multiplyMM(mvp, 0, mVPMatrix, 0, mvp, 0);
// set depth offset (used for clipping to tile boundaries) // set depth offset (used for clipping to tile boundaries)
//GLES20.glPolygonOffset(-1, -GLRenderer.depthOffset(t)); GLES20.glPolygonOffset(1, mDrawCnt++);
GLES20.glPolygonOffset(-1, (mDrawCnt++));
GLES20.glBindBuffer(GL_ARRAY_BUFFER, t.vbo.id); GLES20.glBindBuffer(GL_ARRAY_BUFFER, t.vbo.id);
@ -140,8 +137,6 @@ public class BaseMap {
PolygonRenderer.draw(pos, null, mvp, true, true); PolygonRenderer.draw(pos, null, mvp, true, true);
clipped = true; clipped = true;
} }
// clip lines to quad in depth buffer
GLState.test(true, false);
GLES20.glEnable(GL_BLEND); GLES20.glEnable(GL_BLEND);
l = LineRenderer.draw(pos, l, mvp, div, simpleShader, l = LineRenderer.draw(pos, l, mvp, div, simpleShader,
@ -149,6 +144,7 @@ public class BaseMap {
break; break;
} }
} }
PolygonRenderer.drawOver(mvp);
} }
private static int drawProxyChild(MapTile tile, MapPosition pos) { private static int drawProxyChild(MapTile tile, MapPosition pos) {
@ -179,8 +175,9 @@ public class BaseMap {
// draw parent proxy // draw parent proxy
if ((tile.proxies & MapTile.PROXY_PARENT) != 0) { if ((tile.proxies & MapTile.PROXY_PARENT) != 0) {
MapTile t = tile.rel.parent.tile; MapTile t = tile.rel.parent.tile;
if (t.state == STATE_READY) if (t.state == STATE_READY) {
drawTile(t, pos); drawTile(t, pos);
}
} }
} else if ((tile.proxies & MapTile.PROXY_GRAMPA) != 0) { } else if ((tile.proxies & MapTile.PROXY_GRAMPA) != 0) {
// check if parent was already drawn // check if parent was already drawn
@ -197,14 +194,14 @@ public class BaseMap {
} else { } else {
// prefer drawing parent // prefer drawing parent
if (parent) { if (parent) {
MapTile t = tile.rel.parent.tile; if ((tile.proxies & MapTile.PROXY_PARENT) != 0) {
MapTile t = tile.rel.parent.tile;
if (t != null && t.state == STATE_READY) { if (t != null && t.state == STATE_READY) {
drawTile(t, pos); drawTile(t, pos);
return; return;
}
} }
drawProxyChild(tile, pos); drawProxyChild(tile, pos);
} else if ((tile.proxies & MapTile.PROXY_GRAMPA) != 0) { } else if ((tile.proxies & MapTile.PROXY_GRAMPA) != 0) {

View File

@ -27,6 +27,7 @@ public class GLState {
private static boolean blend = false; private static boolean blend = false;
private static boolean depth = false; private static boolean depth = false;
private static boolean stencil = false; private static boolean stencil = false;
private static int shader;
public static void init() { public static void init() {
vertexArray[0] = false; vertexArray[0] = false;
@ -34,11 +35,19 @@ public class GLState {
blend = false; blend = false;
depth = false; depth = false;
stencil = false; stencil = false;
shader = -1;
GLES20.glDisable(GLES20.GL_STENCIL_TEST); GLES20.glDisable(GLES20.GL_STENCIL_TEST);
GLES20.glDisable(GLES20.GL_DEPTH_TEST); GLES20.glDisable(GLES20.GL_DEPTH_TEST);
} }
public static void useProgram(int shaderProgram) {
if (shaderProgram != shader) {
GLES20.glUseProgram(shaderProgram);
shader = shaderProgram;
}
}
// TODO
public static void blend(boolean enable) { public static void blend(boolean enable) {
if (blend == enable) if (blend == enable)
return; return;

View File

@ -20,9 +20,7 @@ import static android.opengl.GLES20.glDrawArrays;
import static android.opengl.GLES20.glGetAttribLocation; import static android.opengl.GLES20.glGetAttribLocation;
import static android.opengl.GLES20.glGetUniformLocation; import static android.opengl.GLES20.glGetUniformLocation;
import static android.opengl.GLES20.glUniform1f; import static android.opengl.GLES20.glUniform1f;
import static android.opengl.GLES20.glUniform1i;
import static android.opengl.GLES20.glUniformMatrix4fv; import static android.opengl.GLES20.glUniformMatrix4fv;
import static android.opengl.GLES20.glUseProgram;
import static android.opengl.GLES20.glVertexAttribPointer; import static android.opengl.GLES20.glVertexAttribPointer;
import org.oscim.core.MapPosition; import org.oscim.core.MapPosition;
@ -119,7 +117,7 @@ public final class LineRenderer {
if (layer == null) if (layer == null)
return null; return null;
glUseProgram(lineProgram[mode]); GLState.useProgram(lineProgram[mode]);
int uLineScale = hLineScale[mode]; int uLineScale = hLineScale[mode];
int uLineMode = hLineMode[mode]; int uLineMode = hLineMode[mode];
@ -153,7 +151,7 @@ public final class LineRenderer {
glUniform1f(uLineScale, pixel); glUniform1f(uLineScale, pixel);
int lineMode = 0; int lineMode = 0;
glUniform1i(uLineMode, lineMode); glUniform1f(uLineMode, lineMode);
float blurScale = pixel; float blurScale = pixel;
boolean blur = false; boolean blur = false;
@ -209,11 +207,11 @@ public final class LineRenderer {
if (o.roundCap) { if (o.roundCap) {
if (lineMode != 1) { if (lineMode != 1) {
lineMode = 1; lineMode = 1;
glUniform1i(uLineMode, lineMode); glUniform1f(uLineMode, lineMode);
} }
} else if (lineMode != 0) { } else if (lineMode != 0) {
lineMode = 0; lineMode = 0;
glUniform1i(uLineMode, lineMode); glUniform1f(uLineMode, lineMode);
} }
glDrawArrays(GL_TRIANGLE_STRIP, o.offset, o.verticesCnt); glDrawArrays(GL_TRIANGLE_STRIP, o.offset, o.verticesCnt);
} }
@ -244,11 +242,11 @@ public final class LineRenderer {
if (ll.roundCap) { if (ll.roundCap) {
if (lineMode != 1) { if (lineMode != 1) {
lineMode = 1; lineMode = 1;
glUniform1i(uLineMode, lineMode); glUniform1f(uLineMode, lineMode);
} }
} else if (lineMode != 0) { } else if (lineMode != 0) {
lineMode = 0; lineMode = 0;
glUniform1i(uLineMode, lineMode); glUniform1f(uLineMode, lineMode);
} }
glDrawArrays(GL_TRIANGLE_STRIP, l.offset, l.verticesCnt); glDrawArrays(GL_TRIANGLE_STRIP, l.offset, l.verticesCnt);
@ -263,8 +261,9 @@ public final class LineRenderer {
+ "uniform mat4 u_mvp;" + "uniform mat4 u_mvp;"
+ "uniform float u_width;" + "uniform float u_width;"
+ "attribute vec4 a_pos;" + "attribute vec4 a_pos;"
+ "uniform int u_mode;" + "uniform float u_mode;"
+ "varying vec2 v_st;" + "varying vec2 v_st;"
+ "varying vec2 v_mode;"
+ "const float dscale = 8.0/2048.0;" + "const float dscale = 8.0/2048.0;"
+ "void main() {" + "void main() {"
// scale extrusion to u_width pixel // scale extrusion to u_width pixel
@ -274,22 +273,27 @@ public final class LineRenderer {
// last two bits of a_st hold the texture coordinates // last two bits of a_st hold the texture coordinates
// ..maybe one could wrap texture so that `abs` is not required // ..maybe one could wrap texture so that `abs` is not required
+ " v_st = abs(mod(dir, 4.0)) - 1.0;" + " v_st = abs(mod(dir, 4.0)) - 1.0;"
+ " v_mode = vec2(1.0 - u_mode, u_mode);"
+ "}"; + "}";
private final static String lineSimpleFragmentShader = "" private final static String lineSimpleFragmentShader = ""
+ "precision mediump float;" + "precision mediump float;"
+ "uniform sampler2D tex;" + "uniform sampler2D tex;"
+ "uniform int u_mode;"
+ "uniform float u_width;" + "uniform float u_width;"
+ "uniform float u_wscale;" + "uniform float u_wscale;"
+ "uniform vec4 u_color;" + "uniform vec4 u_color;"
+ "varying vec2 v_st;" + "varying vec2 v_st;"
+ "varying vec2 v_mode;"
+ "void main() {" + "void main() {"
+ " float len;" //+ " float len;"
+ " if (u_mode == 0)" // some say one should not use conditionals
+ " len = abs(v_st.s);" // (FIXME currently required as overlay line renderers dont load the texture)
+ " else" //+ " if (u_mode == 0)"
+ " len = texture2D(tex, v_st).a;" //+ " len = abs(v_st.s);"
//+ " else"
//+ " len = texture2D(tex, v_st).a;"
// one trick to avoid branching, need to check performance
+ " float len = max(v_mode[0] * abs(v_st.s), v_mode[1] * texture2D(tex, v_st).a);"
// interpolate alpha between: 0.0 < 1.0 - len < u_wscale // interpolate alpha between: 0.0 < 1.0 - len < u_wscale
// where wscale is 'filter width' / 'line width' and 0 <= len <= sqrt(2) // where wscale is 'filter width' / 'line width' and 0 <= len <= sqrt(2)
+ " gl_FragColor = u_color * smoothstep(0.0, u_wscale, 1.0 - len);" + " gl_FragColor = u_color * smoothstep(0.0, u_wscale, 1.0 - len);"
@ -300,7 +304,7 @@ public final class LineRenderer {
+ "#extension GL_OES_standard_derivatives : enable\n" + "#extension GL_OES_standard_derivatives : enable\n"
+ "precision mediump float;" + "precision mediump float;"
+ "uniform sampler2D tex;" + "uniform sampler2D tex;"
+ "uniform int u_mode;" + "uniform float u_mode;"
+ "uniform vec4 u_color;" + "uniform vec4 u_color;"
+ "uniform float u_width;" + "uniform float u_width;"
+ "uniform float u_wscale;" + "uniform float u_wscale;"
@ -308,7 +312,7 @@ public final class LineRenderer {
+ "void main() {" + "void main() {"
+ " float len;" + " float len;"
+ " float fuzz;" + " float fuzz;"
+ " if (u_mode == 0){" + " if (u_mode == 0.0){"
+ " len = abs(v_st.s);" + " len = abs(v_st.s);"
+ " fuzz = fwidth(v_st.s);" + " fuzz = fwidth(v_st.s);"
+ " } else {" + " } else {"
@ -317,10 +321,12 @@ public final class LineRenderer {
+ " vec2 st_width = fwidth(v_st);" + " vec2 st_width = fwidth(v_st);"
+ " fuzz = max(st_width.s, st_width.t);" + " fuzz = max(st_width.s, st_width.t);"
+ " }" + " }"
// smoothstep is too sharp, guess one could increase extrusion with z..
// but this looks ok too:
+ " gl_FragColor = u_color * min(1.0, (1.0 - len) / (u_wscale + fuzz));"
//+ " gl_FragColor = u_color * smoothstep(0.0, fuzz + u_wscale, 1.0 - len);" //+ " gl_FragColor = u_color * smoothstep(0.0, fuzz + u_wscale, 1.0 - len);"
// smoothstep is too sharp, guess one could increase extrusion with z..
// this looks ok:
//+ " gl_FragColor = u_color * min(1.0, (1.0 - len) / (u_wscale + fuzz));"
// can be faster according to nvidia docs 'Optimize OpenGL ES 2.0 Performace'
+ " gl_FragColor = u_color * clamp((1.0 - len) / (u_wscale + fuzz), 0.0, 1.0);"
+ "}"; + "}";
// private final static String lineVertexShader = "" // private final static String lineVertexShader = ""

View File

@ -18,13 +18,11 @@ import static android.opengl.GLES20.GL_ALWAYS;
import static android.opengl.GLES20.GL_BLEND; import static android.opengl.GLES20.GL_BLEND;
import static android.opengl.GLES20.GL_EQUAL; import static android.opengl.GLES20.GL_EQUAL;
import static android.opengl.GLES20.GL_INVERT; import static android.opengl.GLES20.GL_INVERT;
import static android.opengl.GLES20.GL_LESS;
import static android.opengl.GLES20.GL_SHORT; import static android.opengl.GLES20.GL_SHORT;
import static android.opengl.GLES20.GL_TRIANGLE_FAN; import static android.opengl.GLES20.GL_TRIANGLE_FAN;
import static android.opengl.GLES20.GL_TRIANGLE_STRIP; import static android.opengl.GLES20.GL_TRIANGLE_STRIP;
import static android.opengl.GLES20.GL_ZERO; import static android.opengl.GLES20.GL_ZERO;
import static android.opengl.GLES20.glColorMask; import static android.opengl.GLES20.glColorMask;
import static android.opengl.GLES20.glDepthFunc;
import static android.opengl.GLES20.glDepthMask; import static android.opengl.GLES20.glDepthMask;
import static android.opengl.GLES20.glDisable; import static android.opengl.GLES20.glDisable;
import static android.opengl.GLES20.glDrawArrays; import static android.opengl.GLES20.glDrawArrays;
@ -36,7 +34,6 @@ import static android.opengl.GLES20.glStencilMask;
import static android.opengl.GLES20.glStencilOp; import static android.opengl.GLES20.glStencilOp;
import static android.opengl.GLES20.glUniform4fv; import static android.opengl.GLES20.glUniform4fv;
import static android.opengl.GLES20.glUniformMatrix4fv; import static android.opengl.GLES20.glUniformMatrix4fv;
import static android.opengl.GLES20.glUseProgram;
import static android.opengl.GLES20.glVertexAttribPointer; import static android.opengl.GLES20.glVertexAttribPointer;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@ -51,7 +48,7 @@ import org.oscim.utils.GlUtils;
import android.opengl.GLES20; import android.opengl.GLES20;
public final class PolygonRenderer { public final class PolygonRenderer {
// private static final String TAG = "PolygonRenderer"; //private static final String TAG = PolygonRenderer.class.getName();
// private static final int NUM_VERTEX_SHORTS = 2; // private static final int NUM_VERTEX_SHORTS = 2;
private static final int POLYGON_VERTICES_DATA_POS_OFFSET = 0; private static final int POLYGON_VERTICES_DATA_POS_OFFSET = 0;
@ -93,7 +90,7 @@ public final class PolygonRenderer {
boolean blend = false; boolean blend = false;
/* draw to framebuffer */ /* draw to framebuffer */
glColorMask(true, true, true, true); glColorMask(true, true, true, false);
/* do not modify stencil buffer */ /* do not modify stencil buffer */
glStencilMask(0); glStencilMask(0);
@ -144,18 +141,10 @@ public final class PolygonRenderer {
glUniform4fv(hPolygonColor, 1, l.area.color, 0); glUniform4fv(hPolygonColor, 1, l.area.color, 0);
} }
// if (alpha < 1) { // set stencil buffer mask used to draw this layer
// if (!blend) { // also check that clip bit is 0 to avoid overdraw
// glEnable(GL_BLEND); // of other tiles
// blend = true; glStencilFunc(GL_EQUAL, 0x7f, 0x80 | 1 << c);
// }
// } else if (blend) {
// glDisable(GL_BLEND);
// blend = false;
// }
/* set stencil buffer mask used to draw this layer */
glStencilFunc(GL_EQUAL, 0xff, 1 << c);
/* draw tile fill coordinates */ /* draw tile fill coordinates */
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
@ -195,7 +184,7 @@ public final class PolygonRenderer {
int zoom = pos.zoomLevel; int zoom = pos.zoomLevel;
float scale = pos.scale; float scale = pos.scale;
glUseProgram(polygonProgram); GLState.useProgram(polygonProgram);
GLState.enableVertexArrays(hPolygonVertexPosition, -1); GLState.enableVertexArrays(hPolygonVertexPosition, -1);
@ -204,82 +193,33 @@ public final class PolygonRenderer {
glUniformMatrix4fv(hPolygonMatrix, 1, false, matrix, 0); glUniformMatrix4fv(hPolygonMatrix, 1, false, matrix, 0);
// reset start when only two layer left in stencil buffer // reset start when only one layer left in stencil buffer
// if (mCount > 5) { if (first || mCount > 5) {
// mCount = 0;
// mStart = 0;
// }
if (first) {
mCount = 0; mCount = 0;
mStart = 0; mStart = 0;
} else { } else {
mStart = mCount; mStart = mCount;
} }
//GLState.test(drawClipped, true); GLState.test(false, true);
GLState.test(true, true);
Layer l = layer; Layer l = layer;
for (; l != null && l.type == Layer.POLYGON; l = l.next) { for (; l != null && l.type == Layer.POLYGON; l = l.next) {
PolygonLayer pl = (PolygonLayer) l; PolygonLayer pl = (PolygonLayer) l;
// fade out polygon layers (set in RederTheme)
// fade out polygon layers (set in RenderTheme)
if (pl.area.fade > 0 && pl.area.fade > zoom) if (pl.area.fade > 0 && pl.area.fade > zoom)
continue; continue;
if (mCount == mStart) { if (mCount == mStart) {
/* clear stencilbuffer (tile region) by drawing drawStencilRegion(drawClipped, first);
* a quad with func 'always' and op 'zero' */ first = false;
// disable drawing to framebuffer
glColorMask(false, false, false, false);
// if (!first) {
// // first run draw map bg, otherwise
// // disable drawing to framebuffer
// glColorMask(false, false, false, false);
// } else {
// glUniform4fv(hPolygonColor, 1, GLRenderer.mClearColor, 0);
// }
// never pass the test: always apply fail op
glStencilFunc(GL_ALWAYS, 0, 0xFF);
glStencilMask(0xFF);
glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO);
/* draw clip-region into depth buffer:
* this is used for lines and polygons */
if (first && drawClipped) {
// write to depth buffer
glDepthMask(true);
// to prevent overdraw gl_less restricts the
// clip to the area where no other tile has drawn
glDepthFunc(GL_LESS);
}
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
// if (first) {
// glColorMask(false, false, false, false);
// }
if (first && drawClipped) {
first = false;
// do not modify depth buffer anymore
glDepthMask(false);
// only draw to this tile
glDepthFunc(GL_EQUAL);
}
// op for stencil method polygon drawing // op for stencil method polygon drawing
glStencilOp(GLES20.GL_KEEP, GLES20.GL_KEEP, GL_INVERT); glStencilOp(GLES20.GL_KEEP, GLES20.GL_KEEP, GL_INVERT);
} }
// no need for depth test while drawing stencil
//GLState.test(false, true);
mFillPolys[mCount] = pl; mFillPolys[mCount] = pl;
// set stencil mask to draw to // set stencil mask to draw to
@ -287,43 +227,113 @@ public final class PolygonRenderer {
glDrawArrays(GL_TRIANGLE_FAN, l.offset, l.verticesCnt); glDrawArrays(GL_TRIANGLE_FAN, l.offset, l.verticesCnt);
// draw up to 8 layers into stencil buffer // draw up to 7 layers into stencil buffer
if (mCount == STENCIL_BITS) { if (mCount == STENCIL_BITS - 1) {
/* only draw where nothing was drawn yet */
if (drawClipped)
GLState.test(true, true);
fillPolygons(zoom, scale); fillPolygons(zoom, scale);
mCount = 0; mCount = 0;
mStart = 0; mStart = 0;
} }
} }
if (mCount > 0) { if (mCount > 0)
/* only draw where nothing was drawn yet */
if (drawClipped)
GLState.test(true, true);
fillPolygons(zoom, scale); fillPolygons(zoom, scale);
if (drawClipped) {
if (first) {
drawStencilRegion(drawClipped, first);
glStencilMask(0x00);
glColorMask(true, true, true, false);
}
// clip bit must be zero
glStencilFunc(GL_EQUAL, 0x00, 0x80);
} }
if (drawClipped && first) {
GLState.test(true, false);
GLES20.glColorMask(false, false, false, false);
//glUniform4fv(hPolygonColor, 1, GLRenderer.mClearColor, 0);
GLES20.glDepthMask(true);
GLES20.glDepthFunc(GLES20.GL_LESS);
GLES20.glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
GLES20.glDepthMask(false);
GLES20.glColorMask(true, true, true, true);
GLES20.glDepthFunc(GLES20.GL_EQUAL);
}
return l; return l;
} }
static void drawStencilRegion(boolean clip, boolean first) {
/* 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);
GLES20.glUniform4f(hPolygonColor, 0.7f, 0.7f, 0.7f, 1);
// write to all bits
glStencilMask(0xFF);
// zero out area to draw to
glStencilOp(GLES20.GL_KEEP, GLES20.GL_KEEP, GL_ZERO);
if (clip) {
if (first) {
// draw clip-region into depth and stencil buffer:
// this is used for tile line and polygon layers
// always pass stencil test:
glStencilFunc(GL_ALWAYS, 0x00, 0x00);
GLES20.glEnable(GLES20.GL_POLYGON_OFFSET_FILL);
// test depth. stencil passes always, just keep it enabled
GLState.test(true, true);
// write to depth buffer
glDepthMask(true);
}
else {
// use clip region from stencil buffer
glStencilFunc(GL_EQUAL, 0x00, 0x80);
}
} else {
// always pass stencil test:
glStencilFunc(GL_ALWAYS, 0x00, 0x00);
}
// 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);
} else {
glStencilFunc(GL_ALWAYS, 0x00, 0x00);
}
}
}
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, 0xFF, 0xFF);
// write to all bits
glStencilMask(0xFF);
// zero out area to draw to
glStencilOp(GLES20.GL_KEEP, GLES20.GL_KEEP, GLES20.GL_REPLACE);
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[] debugFillColor = { 0.3f, 0.0f, 0.0f, 0.3f };
private static float[] debugFillColor2 = { .8f, .8f, .8f, .8f }; private static float[] debugFillColor2 = { .8f, .8f, .8f, .8f };
private static FloatBuffer mDebugFill; private static FloatBuffer mDebugFill;
@ -339,7 +349,7 @@ public final class PolygonRenderer {
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0); GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
mDebugFill.position(0); mDebugFill.position(0);
glUseProgram(polygonProgram); GLState.useProgram(polygonProgram);
GLES20.glEnableVertexAttribArray(hPolygonVertexPosition); GLES20.glEnableVertexAttribArray(hPolygonVertexPosition);
glVertexAttribPointer(hPolygonVertexPosition, 2, GLES20.GL_FLOAT, glVertexAttribPointer(hPolygonVertexPosition, 2, GLES20.GL_FLOAT,

View File

@ -93,7 +93,7 @@ public final class TextureRenderer {
GLState.test(false, false); GLState.test(false, false);
GLES20.glEnable(GLES20.GL_BLEND); GLES20.glEnable(GLES20.GL_BLEND);
// GlUtils.checkGlError("draw texture >"); // GlUtils.checkGlError("draw texture >");
GLES20.glUseProgram(mTextureProgram); GLState.useProgram(mTextureProgram);
GLState.enableVertexArrays(hTextureTexCoord, hTextureVertex); GLState.enableVertexArrays(hTextureTexCoord, hTextureVertex);

View File

@ -350,7 +350,7 @@ public class BuildingOverlay extends RenderOverlay {
setMatrix(pos, mv); setMatrix(pos, mv);
Matrix.multiplyMM(mv, 0, proj, 0, mv, 0); Matrix.multiplyMM(mv, 0, proj, 0, mv, 0);
GLES20.glUseProgram(buildingProgram); GLState.useProgram(buildingProgram);
GLES20.glUniformMatrix4fv(hBuildingMatrix, 1, false, mv, 0); GLES20.glUniformMatrix4fv(hBuildingMatrix, 1, false, mv, 0);
GLES20.glUniform4f(hBuildingColor, 0.5f, 0.5f, 0.5f, 0.7f); GLES20.glUniform4f(hBuildingColor, 0.5f, 0.5f, 0.5f, 0.7f);

View File

@ -180,7 +180,7 @@ public class ExtrusionOverlay extends RenderOverlay {
int uExtMode = hExtrusionMode[shaderMode]; int uExtMode = hExtrusionMode[shaderMode];
if (debug) { if (debug) {
GLES20.glUseProgram(extrusionProgram[shaderMode]); GLState.useProgram(extrusionProgram[shaderMode]);
GLState.enableVertexArrays(uExtVertexPosition, uExtLightPosition); GLState.enableVertexArrays(uExtVertexPosition, uExtLightPosition);
GLES20.glUniform1i(uExtMode, 0); GLES20.glUniform1i(uExtMode, 0);
@ -224,9 +224,11 @@ public class ExtrusionOverlay extends RenderOverlay {
GLState.test(true, false); GLState.test(true, false);
GLES20.glUseProgram(extrusionProgram[shaderMode]); GLState.useProgram(extrusionProgram[shaderMode]);
GLState.enableVertexArrays(uExtVertexPosition, -1); GLState.enableVertexArrays(uExtVertexPosition, -1);
if (pos.scale < 2) { if (pos.scale < 2) {
// chances are high that one moves through a building
// with scale > 2 also draw back sides in this case.
GLES20.glEnable(GLES20.GL_CULL_FACE); GLES20.glEnable(GLES20.GL_CULL_FACE);
GLES20.glCullFace(GLES20.GL_FRONT); GLES20.glCullFace(GLES20.GL_FRONT);
} }

View File

@ -172,7 +172,7 @@ public class ModelOverlay extends RenderOverlay {
setMatrix(pos, mv); setMatrix(pos, mv);
Matrix.multiplyMM(mv, 0, proj, 0, mv, 0); Matrix.multiplyMM(mv, 0, proj, 0, mv, 0);
GLES20.glUseProgram(polygonProgram); GLState.useProgram(polygonProgram);
GLState.enableVertexArrays(hPolygonVertexPosition, hPolygonLightPosition); GLState.enableVertexArrays(hPolygonVertexPosition, hPolygonLightPosition);

View File

@ -66,7 +66,7 @@ public class TestLineOverlay extends RenderOverlay {
// //
// Vertex layout: // Vertex layout:
// x/y pos[16][16], dir_x[8]|dir_y[8], start[4]|length[12] // x/y pos[16][16], dir_x[8]|dir_y[8], start[4]|length[12]
// - 'direction' precision 1/16 maximum line width is 2*32 // - 'direction' precision 1/16, maximum line width is 2*16
// - texture 'start' prescision 1 // - texture 'start' prescision 1
// -> max tex width is 32 // -> max tex width is 32
// - segment 'length' prescision 1/4 // - segment 'length' prescision 1/4
@ -99,16 +99,18 @@ public class TestLineOverlay extends RenderOverlay {
0, 0, 0, 0, 0, 0, 0, 0,
}; };
private final short[] indices = { private short[] indices = {
0, 1, 2, 0, 1, 2,
2, 1, 3, 2, 1, 3,
4, 5, 6, 4, 5, 6,
6, 5, 7, 6, 5, 7,
8, 9, 10, 8, 9, 10,
10, 9, 11, 10, 9, 11,
}; };
private byte[] flip = { 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 }; private byte[] flip;
private static int testProgram; private static int testProgram;
private static int htestVertexPosition0; private static int htestVertexPosition0;
@ -131,13 +133,14 @@ public class TestLineOverlay extends RenderOverlay {
+ "const float ffff = 65536.0;" + "const float ffff = 65536.0;"
+ "void main() {" + "void main() {"
+ " if (a_flip == 0.0){" + " if (a_flip == 0.0){"
+ " vec2 dir = vec2((a_pos0.z / ffff), fract(a_pos0.z/ff))*64.0;" // extract 8 bit direction vector
+ " vec2 dir = a_pos0.zw/16.0;"
+ " gl_Position = u_mvp * vec4(a_pos0.xy + dir, 0.0, 1.0);" + " gl_Position = u_mvp * vec4(a_pos0.xy + dir, 0.0, 1.0);"
+ " color = vec4(0.0,1.0,a_pos0.w,1.0);" + " color = vec4(dir/255.0 + 0.5, 1.0,1.0);"
+ " }else {" + " }else {"
+ " vec2 dir = vec2((a_pos1.z / ffff), fract(a_pos1.z/ff))*64.0;" + " vec2 dir = a_pos1.zw/16.0;"
+ " gl_Position = u_mvp * vec4(a_pos1.xy - dir, 0.0, 1.0);" + " gl_Position = u_mvp * vec4(a_pos1.xy - dir, 0.0, 1.0);"
+ " color = vec4(1.0,0.5,a_pos1.w,1.0);" + " color = vec4(dir/255.0 + 0.5, 1.0,1.0);"
+ "}}"; + "}}";
final static String testFragmentShader = "" final static String testFragmentShader = ""
@ -151,6 +154,9 @@ public class TestLineOverlay extends RenderOverlay {
private int mVertexBufferID; private int mVertexBufferID;
private int mVertexFlipID; private int mVertexFlipID;
private int mNumVertices;
private int mNumIndices;
@Override @Override
public synchronized void update(MapPosition curPos, boolean positionChanged, public synchronized void update(MapPosition curPos, boolean positionChanged,
boolean tilesChanged) { boolean tilesChanged) {
@ -178,6 +184,93 @@ public class TestLineOverlay extends RenderOverlay {
mVertexBufferID = mVboIds[1]; mVertexBufferID = mVboIds[1];
mVertexFlipID = mVboIds[2]; mVertexFlipID = mVboIds[2];
float points[] = {
800, 0,
0, 0,
//-400, 100,
//-600, 200,
//-800, 100,
};
// float[] points = new float[12 * 2];
// for (int i = 0; i < 24; i += 2) {
// points[i + 0] = (float) Math.sin(-i / 11f * Math.PI) * 400;
// points[i + 1] = (float) Math.cos(-i / 11f * Math.PI) * 400;
// }
mNumVertices = (points.length - 2) * 2;
short[] vertices = new short[(mNumVertices + 2) * 4];
int opos = 4;
float x = points[0];
float y = points[1];
float scale = 127;
boolean even = true;
for (int i = 2; i < points.length;) {
float nx = points[i++];
float ny = points[i++];
// Calculate triangle corners for the given width
float vx = nx - x;
float vy = ny - y;
float a = (float) Math.sqrt(vx * vx + vy * vy);
// normal vector
vx = (vx / a);
vy = (vy / a);
float ux = -vy;
float uy = vx;
short dx = (short) (ux * scale);
short dy = (short) (uy * scale);
vertices[opos + 0] = (short) x;
vertices[opos + 1] = (short) y;
vertices[opos + 2] = dx;
vertices[opos + 3] = dy;
vertices[opos + 8] = (short) nx;
vertices[opos + 9] = (short) ny;
vertices[opos + 10] = dx;
vertices[opos + 11] = dy;
x = nx;
y = ny;
if (even) {
opos += 4;
even = false;
} else {
even = true;
opos += 12;
}
}
flip = new byte[(points.length - 2)];
for (int i = 0; i < flip.length; i++)
flip[i] = (byte) (i % 2);
short j = 0;
mNumIndices = ((points.length) >> 2) * 6;
indices = new short[mNumIndices];
for (int i = 0; i < mNumIndices; i += 6, j += 4) {
indices[i + 0] = (short) (j + 0);
indices[i + 1] = (short) (j + 1);
indices[i + 2] = (short) (j + 2);
indices[i + 3] = (short) (j + 2);
indices[i + 4] = (short) (j + 1);
indices[i + 5] = (short) (j + 3);
}
ByteBuffer buf = ByteBuffer.allocateDirect(128 * 4) ByteBuffer buf = ByteBuffer.allocateDirect(128 * 4)
.order(ByteOrder.nativeOrder()); .order(ByteOrder.nativeOrder());
@ -185,20 +278,24 @@ public class TestLineOverlay extends RenderOverlay {
sbuf.put(indices); sbuf.put(indices);
sbuf.flip(); sbuf.flip();
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, mIndicesBufferID); GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, mIndicesBufferID);
GLES20.glBufferData(GLES20.GL_ELEMENT_ARRAY_BUFFER, 18 * 2, sbuf, GLES20.GL_STATIC_DRAW); GLES20.glBufferData(GLES20.GL_ELEMENT_ARRAY_BUFFER, indices.length * 2, sbuf,
GLES20.GL_STATIC_DRAW);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0); GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
sbuf.clear(); sbuf.clear();
sbuf.put(box); //sbuf.put(box);
sbuf.put(vertices);
sbuf.flip(); sbuf.flip();
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mVertexBufferID); GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mVertexBufferID);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, 56 * 2, sbuf, GLES20.GL_STATIC_DRAW); GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, vertices.length * 2, sbuf,
GLES20.GL_STATIC_DRAW);
buf.clear(); buf.clear();
buf.put(flip); buf.put(flip);
buf.flip(); buf.flip();
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mVertexFlipID); GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mVertexFlipID);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, 12, buf, GLES20.GL_STATIC_DRAW); GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, flip.length, buf,
GLES20.GL_STATIC_DRAW);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0); GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
mMapView.getMapViewPosition().getMapPosition(mMapPosition, null); mMapView.getMapViewPosition().getMapPosition(mMapPosition, null);
@ -213,12 +310,13 @@ public class TestLineOverlay extends RenderOverlay {
setMatrix(pos, mv); setMatrix(pos, mv);
Matrix.multiplyMM(mv, 0, proj, 0, mv, 0); Matrix.multiplyMM(mv, 0, proj, 0, mv, 0);
GLES20.glUseProgram(testProgram); GLState.useProgram(testProgram);
GLES20.glDisable(GLES20.GL_CULL_FACE); GLES20.glDisable(GLES20.GL_CULL_FACE);
GLState.test(false, false); GLState.test(false, false);
GLState.enableVertexArrays(-1, -1); GLState.enableVertexArrays(-1, -1);
GLES20.glEnableVertexAttribArray(htestVertexPosition0); GLES20.glEnableVertexAttribArray(htestVertexPosition0);
GLES20.glEnableVertexAttribArray(htestVertexPosition1); GLES20.glEnableVertexAttribArray(htestVertexPosition1);
GLES20.glEnableVertexAttribArray(htestVertexFlip); GLES20.glEnableVertexAttribArray(htestVertexFlip);
GLES20.glUniformMatrix4fv(htestMatrix, 1, false, mv, 0); GLES20.glUniformMatrix4fv(htestMatrix, 1, false, mv, 0);
@ -230,15 +328,23 @@ public class TestLineOverlay extends RenderOverlay {
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mVertexBufferID); GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mVertexBufferID);
GLES20.glVertexAttribPointer(htestVertexPosition0, 4, GLES20.GL_SHORT, false, 0, 8); GLES20.glVertexAttribPointer(htestVertexPosition0,
GLES20.glVertexAttribPointer(htestVertexPosition1, 4, GLES20.GL_SHORT, false, 0, 0); 4, GLES20.GL_SHORT, false, 0, 8);
GLES20.glUniform4f(htestColor, 0.5f, 0.5f, 1.0f, 1.0f);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, 18, GLES20.GL_UNSIGNED_SHORT, 0); GLES20.glVertexAttribPointer(htestVertexPosition1,
4, GLES20.GL_SHORT, false, 0, 0);
GLES20.glUniform4f(htestColor, 0.5f, 0.5f, 1.0f, 1.0f);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, mNumIndices, GLES20.GL_UNSIGNED_SHORT, 0);
GLES20.glVertexAttribPointer(htestVertexPosition0,
4, GLES20.GL_SHORT, false, 0, 16);
GLES20.glVertexAttribPointer(htestVertexPosition1,
4, GLES20.GL_SHORT, false, 0, 8);
GLES20.glVertexAttribPointer(htestVertexPosition0, 4, GLES20.GL_SHORT, false, 0, 16);
GLES20.glVertexAttribPointer(htestVertexPosition1, 4, GLES20.GL_SHORT, false, 0, 8);
GLES20.glUniform4f(htestColor, 0.5f, 1.0f, 0.5f, 1.0f); GLES20.glUniform4f(htestColor, 0.5f, 1.0f, 0.5f, 1.0f);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, 18, GLES20.GL_UNSIGNED_SHORT, 0); GLES20.glDrawElements(GLES20.GL_TRIANGLES, mNumIndices, GLES20.GL_UNSIGNED_SHORT, 0);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0); GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);