355 lines
12 KiB
Java
355 lines
12 KiB
Java
/*
|
|
* Copyright 2013 Hannes Janetzek
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify it under the
|
|
* terms of the GNU Lesser General Public License as published by the Free Software
|
|
* Foundation, either version 3 of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License along with
|
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
package org.oscim.renderer;
|
|
|
|
import java.nio.ByteBuffer;
|
|
import java.nio.ByteOrder;
|
|
import java.nio.ShortBuffer;
|
|
|
|
import org.oscim.core.MapPosition;
|
|
import org.oscim.renderer.layer.Layer;
|
|
import org.oscim.renderer.layer.Layers;
|
|
import org.oscim.renderer.layer.LineLayer;
|
|
import org.oscim.renderer.layer.LineTexLayer;
|
|
import org.oscim.theme.renderinstruction.Line;
|
|
import org.oscim.utils.FastMath;
|
|
import org.oscim.utils.GlUtils;
|
|
|
|
import android.opengl.GLES20;
|
|
import android.util.Log;
|
|
|
|
public class LineTexRenderer {
|
|
private final static String TAG = LineTexRenderer.class.getName();
|
|
|
|
// factor to normalize extrusion vector and scale to coord scale
|
|
private final static float COORD_SCALE_BY_DIR_SCALE =
|
|
GLRenderer.COORD_SCALE / LineLayer.DIR_SCALE;
|
|
|
|
private static int shader;
|
|
private static int hVertexPosition0;
|
|
private static int hVertexPosition1;
|
|
private static int hVertexLength0;
|
|
private static int hVertexLength1;
|
|
private static int hVertexFlip;
|
|
private static int hMatrix;
|
|
private static int hTexColor;
|
|
private static int hBgColor;
|
|
private static int hScale;
|
|
private static int hWidth;
|
|
private static int hPatternScale;
|
|
private static int hPatternWidth;
|
|
|
|
private static int mIndicesBufferID;
|
|
private static int mVertexFlipID;
|
|
|
|
// batch up up to 64 quads in one draw call
|
|
private static int maxQuads = 64;
|
|
private static int maxIndices = maxQuads * 6;
|
|
private static int[] mTexID;
|
|
|
|
public static void init() {
|
|
shader = GlUtils.createProgram(vertexShader, fragmentShader);
|
|
if (shader == 0) {
|
|
Log.e(TAG, "Could not create program.");
|
|
return;
|
|
}
|
|
|
|
hMatrix = GLES20.glGetUniformLocation(shader, "u_mvp");
|
|
hTexColor = GLES20.glGetUniformLocation(shader, "u_color");
|
|
hBgColor = GLES20.glGetUniformLocation(shader, "u_bgcolor");
|
|
hScale = GLES20.glGetUniformLocation(shader, "u_scale");
|
|
hWidth = GLES20.glGetUniformLocation(shader, "u_width");
|
|
hPatternScale = GLES20.glGetUniformLocation(shader, "u_pscale");
|
|
hPatternWidth = GLES20.glGetUniformLocation(shader, "u_pwidth");
|
|
|
|
hVertexPosition0 = GLES20.glGetAttribLocation(shader, "a_pos0");
|
|
hVertexPosition1 = GLES20.glGetAttribLocation(shader, "a_pos1");
|
|
hVertexLength0 = GLES20.glGetAttribLocation(shader, "a_len0");
|
|
hVertexLength1 = GLES20.glGetAttribLocation(shader, "a_len1");
|
|
hVertexFlip = GLES20.glGetAttribLocation(shader, "a_flip");
|
|
|
|
int[] mVboIds = new int[2];
|
|
GLES20.glGenBuffers(2, mVboIds, 0);
|
|
mIndicesBufferID = mVboIds[0];
|
|
mVertexFlipID = mVboIds[1];
|
|
|
|
short[] indices = new short[maxIndices];
|
|
for (int i = 0, j = 0; i < maxIndices; 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(maxIndices * 2)
|
|
.order(ByteOrder.nativeOrder());
|
|
|
|
ShortBuffer sbuf = buf.asShortBuffer();
|
|
sbuf.put(indices);
|
|
sbuf.flip();
|
|
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER,
|
|
mIndicesBufferID);
|
|
GLES20.glBufferData(GLES20.GL_ELEMENT_ARRAY_BUFFER,
|
|
indices.length * 2, sbuf, GLES20.GL_STATIC_DRAW);
|
|
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
|
|
|
|
// 0, 1, 0, 1, 0, ...
|
|
byte[] flip = new byte[maxQuads * 4];
|
|
for (int i = 0; i < flip.length; i++)
|
|
flip[i] = (byte) (i % 2);
|
|
|
|
buf.clear();
|
|
buf.put(flip);
|
|
buf.flip();
|
|
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mVertexFlipID);
|
|
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, flip.length, buf,
|
|
GLES20.GL_STATIC_DRAW);
|
|
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
|
|
|
|
// mTexID = new int[10];
|
|
// byte[] stipple = new byte[2];
|
|
// stipple[0] = 32;
|
|
// stipple[1] = 32;
|
|
// mTexID[0] = GlUtils.loadStippleTexture(stipple);
|
|
}
|
|
|
|
private final static int STRIDE = 12;
|
|
private final static int LEN_OFFSET = 8;
|
|
|
|
public static Layer draw(Layers layers, Layer curLayer,
|
|
MapPosition pos, float[] matrix, float div) {
|
|
|
|
GLState.blend(true);
|
|
GLState.useProgram(shader);
|
|
|
|
GLState.enableVertexArrays(-1, -1);
|
|
|
|
GLES20.glEnableVertexAttribArray(hVertexPosition0);
|
|
GLES20.glEnableVertexAttribArray(hVertexPosition1);
|
|
GLES20.glEnableVertexAttribArray(hVertexLength0);
|
|
GLES20.glEnableVertexAttribArray(hVertexLength1);
|
|
GLES20.glEnableVertexAttribArray(hVertexFlip);
|
|
|
|
GLES20.glUniformMatrix4fv(hMatrix, 1, false, matrix, 0);
|
|
|
|
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER,
|
|
mIndicesBufferID);
|
|
|
|
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mVertexFlipID);
|
|
GLES20.glVertexAttribPointer(hVertexFlip, 1,
|
|
GLES20.GL_BYTE, false, 0, 0);
|
|
|
|
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, layers.vbo.id);
|
|
|
|
float s = pos.scale / div;
|
|
|
|
//GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTexID[0]);
|
|
|
|
Layer l = curLayer;
|
|
while (l != null && l.type == Layer.TEXLINE) {
|
|
LineTexLayer ll = (LineTexLayer) l;
|
|
Line line = ll.line;
|
|
|
|
if (line.stippleColor == null)
|
|
GLES20.glUniform4f(hTexColor, 1.0f, 1.0f, 1.0f, 1.0f);
|
|
else
|
|
GLES20.glUniform4fv(hTexColor, 1, line.stippleColor, 0);
|
|
|
|
GLES20.glUniform4fv(hBgColor, 1, line.color, 0);
|
|
|
|
float ps = FastMath.clamp((int) (s+0.5f), 1, 3);
|
|
GLES20.glUniform1f(hPatternScale, (GLRenderer.COORD_SCALE * line.stipple) / ps);
|
|
GLES20.glUniform1f(hPatternWidth, line.stippleWidth);
|
|
|
|
GLES20.glUniform1f(hScale, pos.scale);
|
|
// keep line width fixed
|
|
GLES20.glUniform1f(hWidth, ll.width / s * COORD_SCALE_BY_DIR_SCALE);
|
|
|
|
GlUtils.checkGlError("0");
|
|
|
|
// add offset vertex
|
|
int vOffset = -STRIDE;
|
|
|
|
// first pass
|
|
int allIndices = (ll.evenQuads * 6);
|
|
for (int i = 0; i < allIndices; i += maxIndices) {
|
|
int numIndices = allIndices - i;
|
|
if (numIndices > maxIndices)
|
|
numIndices = maxIndices;
|
|
|
|
// i / 6 * (24 shorts per block * 2 short bytes)
|
|
int add = (l.offset + i * 8) + vOffset;
|
|
|
|
GLES20.glVertexAttribPointer(hVertexPosition0,
|
|
4, GLES20.GL_SHORT, false, STRIDE,
|
|
add + STRIDE);
|
|
|
|
GLES20.glVertexAttribPointer(hVertexLength0,
|
|
2, GLES20.GL_SHORT, false, STRIDE,
|
|
add + STRIDE + LEN_OFFSET);
|
|
|
|
GLES20.glVertexAttribPointer(hVertexPosition1,
|
|
4, GLES20.GL_SHORT, false, STRIDE,
|
|
add);
|
|
|
|
GLES20.glVertexAttribPointer(hVertexLength1,
|
|
2, GLES20.GL_SHORT, false, STRIDE,
|
|
add + LEN_OFFSET);
|
|
|
|
GLES20.glDrawElements(GLES20.GL_TRIANGLES, numIndices,
|
|
GLES20.GL_UNSIGNED_SHORT, 0);
|
|
}
|
|
|
|
// second pass
|
|
allIndices = (ll.oddQuads * 6);
|
|
for (int i = 0; i < allIndices; i += maxIndices) {
|
|
int numIndices = allIndices - i;
|
|
if (numIndices > maxIndices)
|
|
numIndices = maxIndices;
|
|
// i / 6 * (24 shorts per block * 2 short bytes)
|
|
int add = (l.offset + i * 8) + vOffset;
|
|
|
|
GLES20.glVertexAttribPointer(hVertexPosition0,
|
|
4, GLES20.GL_SHORT, false, STRIDE,
|
|
add + 2 * STRIDE);
|
|
|
|
GLES20.glVertexAttribPointer(hVertexLength0,
|
|
2, GLES20.GL_SHORT, false, STRIDE,
|
|
add + 2 * STRIDE + LEN_OFFSET);
|
|
|
|
GLES20.glVertexAttribPointer(hVertexPosition1,
|
|
4, GLES20.GL_SHORT, false, STRIDE,
|
|
add + STRIDE);
|
|
|
|
GLES20.glVertexAttribPointer(hVertexLength1,
|
|
2, GLES20.GL_SHORT, false, STRIDE,
|
|
add + STRIDE + LEN_OFFSET);
|
|
|
|
GLES20.glDrawElements(GLES20.GL_TRIANGLES, numIndices,
|
|
GLES20.GL_UNSIGNED_SHORT, 0);
|
|
}
|
|
|
|
l = l.next;
|
|
|
|
GlUtils.checkGlError(TAG);
|
|
}
|
|
|
|
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
|
|
|
|
GLES20.glDisableVertexAttribArray(hVertexPosition0);
|
|
GLES20.glDisableVertexAttribArray(hVertexPosition1);
|
|
GLES20.glDisableVertexAttribArray(hVertexLength0);
|
|
GLES20.glDisableVertexAttribArray(hVertexLength1);
|
|
GLES20.glDisableVertexAttribArray(hVertexFlip);
|
|
|
|
//GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
|
|
|
|
return l;
|
|
}
|
|
|
|
final static String vertexShader = ""
|
|
+ "precision mediump float;"
|
|
+ "uniform mat4 u_mvp;"
|
|
+ "uniform vec4 u_color;"
|
|
+ "uniform float u_pscale;"
|
|
+ "uniform float u_width;"
|
|
+ "attribute vec4 a_pos0;"
|
|
+ "attribute vec4 a_pos1;"
|
|
+ "attribute vec2 a_len0;"
|
|
+ "attribute vec2 a_len1;"
|
|
+ "attribute float a_flip;"
|
|
+ "varying vec2 v_st;"
|
|
+ "void main() {"
|
|
+ " vec4 pos;"
|
|
+ " if (a_flip == 0.0){"
|
|
+ " vec2 dir = u_width * a_pos0.zw;"
|
|
+ " pos = vec4(a_pos0.xy + dir, 0.0, 1.0);"
|
|
+ " v_st = vec2(a_len0.x / u_pscale, 1.0);"
|
|
+ " } else {"
|
|
+ " vec2 dir = u_width * a_pos1.zw ;"
|
|
+ " pos = vec4(a_pos1.xy - dir, 0.0, 1.0);"
|
|
+ " v_st = vec2(a_len1.x / u_pscale, -1.0);"
|
|
+ " }"
|
|
+ " gl_Position = u_mvp * pos;"
|
|
+ "}";
|
|
|
|
//*
|
|
final static String fragmentShader = ""
|
|
+ "#extension GL_OES_standard_derivatives : enable\n"
|
|
+ " precision mediump float;"
|
|
+ " uniform vec4 u_color;"
|
|
+ " uniform vec4 u_bgcolor;"
|
|
+ " uniform float u_pwidth;"
|
|
+ " varying vec2 v_st;"
|
|
+ " void main() {"
|
|
// distance on perpendicular to the line
|
|
+ " float dist = abs(v_st.t);"
|
|
+ " float fuzz = fwidth(v_st.t);"
|
|
+ " float fuzz_p = fwidth(v_st.s);"
|
|
+ " float line_w = smoothstep(0.0, fuzz, 1.0 - dist);"
|
|
+ " float stipple_w = smoothstep(0.0, fuzz, u_pwidth - dist);"
|
|
// triangle waveform in the range 0..1 for regular pattern
|
|
+ " float phase = abs(mod(v_st.s, 2.0) - 1.0);"
|
|
// interpolate between on/off phase, 0.5 = equal phase length
|
|
+ " float stipple_p = smoothstep(0.5 - fuzz_p, 0.5 + fuzz_p, phase);"
|
|
+ " gl_FragColor = line_w * mix(u_bgcolor, u_color, min(stipple_w, stipple_p));"
|
|
+ " } "; //*/
|
|
|
|
/*
|
|
final static String fragmentShader = ""
|
|
+ "#extension GL_OES_standard_derivatives : enable\n"
|
|
+ " precision mediump float;"
|
|
+ " uniform sampler2D tex;"
|
|
+ " uniform float u_scale;"
|
|
+ " uniform vec4 u_color;"
|
|
+ " uniform vec4 u_bgcolor;"
|
|
+ " varying vec2 v_st;"
|
|
+ " void main() {"
|
|
+ " float len = texture2D(tex, v_st).a;"
|
|
+ " float tex_w = abs(v_st.t);"
|
|
+ " vec2 st_width = fwidth(v_st);"
|
|
+ " float fuzz = max(st_width.s, st_width.t);"
|
|
//+ " float fuzz = fwidth(v_st.t);"
|
|
//+ " float line_w = 1.0 - smoothstep(1.0 - fuzz, 1.0, tex_w);"
|
|
//+ " float stipple_w = 1.0 - smoothstep(0.7 - fuzz, 0.7, tex_w);"
|
|
+ " float stipple_p = 1.0 - smoothstep(1.0 - fuzz, 1.0, length(vec2(len*u_scale, v_st.t)));"
|
|
+ " gl_FragColor = u_bgcolor * stipple_p;"
|
|
// + " gl_FragColor = line_w * mix(u_bgcolor, u_color, min(stipple_w, stipple_p));"
|
|
+ "}"; //*/
|
|
/*
|
|
final static String fragmentShader = ""
|
|
+ "#extension GL_OES_standard_derivatives : enable\n"
|
|
+ " precision mediump float;"
|
|
+ " uniform sampler2D tex;"
|
|
+ " uniform vec4 u_color;"
|
|
+ " uniform vec4 u_bgcolor;"
|
|
+ " uniform float u_pwidth;"
|
|
+ " varying vec2 v_st;"
|
|
+ " void main() {"
|
|
+ " float dist = texture2D(tex, v_st).a;"
|
|
+ " float tex_w = abs(v_st.t);"
|
|
+ " vec2 st_width = fwidth(v_st);"
|
|
+ " float fuzz = max(st_width.s, st_width.t);"
|
|
+ " float line_w = (1.0 - smoothstep(1.0 - fuzz, 1.0, tex_w));"
|
|
+ " float stipple_w = (1.0 - smoothstep(u_pwidth - fuzz, u_pwidth, tex_w));"
|
|
+ " float stipple_p = smoothstep(0.495, 0.505, dist);"
|
|
+ " gl_FragColor = line_w * mix(u_bgcolor, u_color, min(stipple_w, stipple_p));"
|
|
+ " } "; //*/
|
|
|
|
}
|