From 235e001a82de3dc5552cffe396dd5380be0cb8e4 Mon Sep 17 00:00:00 2001
From: Hannes Janetzek <hannes.janetzek@gmail.com>
Date: Mon, 21 Jan 2013 03:13:47 +0100
Subject: [PATCH] add 'min-size' option to line renderinstruction, when size is
 less no outline will be drawn

---
 src/org/oscim/renderer/LineRenderer.java      | 51 ++++++++-----------
 .../oscim/theme/renderinstruction/Line.java   | 20 ++++++--
 src/org/oscim/utils/GlUtils.java              | 47 +++++++++++++++--
 3 files changed, 77 insertions(+), 41 deletions(-)

diff --git a/src/org/oscim/renderer/LineRenderer.java b/src/org/oscim/renderer/LineRenderer.java
index 47e02678..4645e8ac 100644
--- a/src/org/oscim/renderer/LineRenderer.java
+++ b/src/org/oscim/renderer/LineRenderer.java
@@ -25,9 +25,6 @@ import static android.opengl.GLES20.glUniformMatrix4fv;
 import static android.opengl.GLES20.glUseProgram;
 import static android.opengl.GLES20.glVertexAttribPointer;
 
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
 import org.oscim.core.MapPosition;
 import org.oscim.generator.TileGenerator;
 import org.oscim.renderer.layer.Layer;
@@ -84,6 +81,8 @@ public final class LineRenderer {
 			//hLineTexturePosition[i] = glGetAttribLocation(lineProgram[i], "a_st");
 		}
 
+		// create lookup table as texture for 'length(0..1,0..1)'
+		// using mirrored wrap mode for 'length(-1..1,-1..1)'
 		byte[] pixel = new byte[128 * 128];
 
 		for (int x = 0; x < 128; x++) {
@@ -94,32 +93,11 @@ public final class LineRenderer {
 				if (color > 255)
 					color = 255;
 				pixel[x + y * 128] = (byte) color;
-				//pixel[(127 - x) + (127 - y) * 128] = (byte) color;
 			}
 		}
 
-		int[] textureIds = new int[1];
-		GLES20.glGenTextures(1, textureIds, 0);
-		mTexID = textureIds[0];
-
-		GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTexID);
-
-		GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,
-				GLES20.GL_NEAREST);
-		GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER,
-				GLES20.GL_NEAREST);
-		GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,
-				GLES20.GL_MIRRORED_REPEAT); // Set U Wrapping
-		GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,
-				GLES20.GL_MIRRORED_REPEAT); // Set V Wrapping
-
-		ByteBuffer buf = ByteBuffer.allocateDirect(128 * 128).order(ByteOrder.nativeOrder());
-		buf.put(pixel);
-		buf.position(0);
-		GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_ALPHA, 128, 128, 0, GLES20.GL_ALPHA,
-				GLES20.GL_UNSIGNED_BYTE, buf);
-
-		GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
+		mTexID = GlUtils.loadTexture(pixel, 128, 128, GLES20.GL_ALPHA,
+				GLES20.GL_MIRRORED_REPEAT, GLES20.GL_MIRRORED_REPEAT);
 
 		return true;
 	}
@@ -158,9 +136,16 @@ public final class LineRenderer {
 
 		glUniformMatrix4fv(hLineMatrix[mode], 1, false, matrix, 0);
 
+		// line scale factor for non fixed lines: within a zoom-
+		// level lines would be scaled by the factor 2 via projection. 
+		// though lines should only scale by sqrt(2). this is achieved 
+		// by inverting scaling of extrusion vector with: width/sqrt(s).
+		// within one zoom-level: 1 <= s <= 2
+		float s = scale / div;
+		float lineScale = (float) Math.sqrt(s * 2 / 2.2);
+
 		// scale factor to map one pixel on tile to one pixel on screen:
 		// only works with orthographic projection
-		float s = scale / div;
 		float pixel = 0;
 
 		if (mode == 1)
@@ -170,8 +155,6 @@ public final class LineRenderer {
 		int lineMode = 0;
 		glUniform1i(uLineMode, lineMode);
 
-		// line scale factor (for non fixed lines)
-		float lineScale = (float) Math.sqrt(s);
 		float blurScale = pixel;
 		boolean blur = false;
 		// dont increase scale when max is reached
@@ -199,13 +182,17 @@ public final class LineRenderer {
 			}
 
 			if (line.outline) {
-				// draw outline for linelayers references by this outline
+				// draw linelayers references by this outline
 				for (LineLayer o = ll.outlines; o != null; o = o.outlines) {
 
 					if (o.line.fixed || strokeMaxZoom) {
 						width = (ll.width + o.width) / s;
 					} else {
 						width = ll.width / s + o.width / lineScale;
+
+						// check min size for outline
+						if (o.line.min > 0 && o.width * lineScale < o.line.min * 2)
+							continue;
 					}
 
 					glUniform1f(uLineWidth, width);
@@ -228,7 +215,6 @@ public final class LineRenderer {
 						lineMode = 0;
 						glUniform1i(uLineMode, lineMode);
 					}
-
 					glDrawArrays(GL_TRIANGLE_STRIP, o.offset, o.verticesCnt);
 				}
 			} else {
@@ -239,6 +225,9 @@ public final class LineRenderer {
 					width = ll.width / s;
 				} else {
 					width = ll.width / lineScale;
+
+					if (ll.line.min > 0 && ll.width * lineScale < ll.line.min * 2)
+						width = (ll.width - 0.2f) / lineScale;
 				}
 
 				glUniform1f(uLineWidth, width);
diff --git a/src/org/oscim/theme/renderinstruction/Line.java b/src/org/oscim/theme/renderinstruction/Line.java
index 9888c626..a89f1f96 100644
--- a/src/org/oscim/theme/renderinstruction/Line.java
+++ b/src/org/oscim/theme/renderinstruction/Line.java
@@ -56,14 +56,15 @@ public final class Line extends RenderInstruction {
 		boolean fixed = false;
 		String style = null;
 		float blur = 0;
+		float min = 0;
 
 		if (line != null) {
 			fixed = line.fixed;
 			fade = line.fade;
 			strokeLinecap = line.cap;
 			blur = line.blur;
+			min = line.min;
 		}
-
 		for (int i = 0; i < attributes.getLength(); ++i) {
 			String name = attributes.getLocalName(i);
 			String value = attributes.getValue(i);
@@ -82,6 +83,8 @@ public final class Line extends RenderInstruction {
 				strokeLinecap = Cap.valueOf(value.toUpperCase(Locale.ENGLISH));
 			} else if ("fade".equals(name)) {
 				fade = Integer.parseInt(value);
+			} else if ("min".equals(name)) {
+				min = Float.parseFloat(value);
 			} else if ("fixed".equals(name)) {
 				fixed = Boolean.parseBoolean(value);
 			} else if ("blur".equals(name)) {
@@ -102,14 +105,14 @@ public final class Line extends RenderInstruction {
 				strokeWidth = 1;
 
 			return new Line(line, style, src, stroke, strokeWidth, stipple,
-					strokeLinecap, level, fixed, fade, blur, isOutline);
+					strokeLinecap, level, fixed, fade, blur, isOutline, min);
 		}
 
 		if (!isOutline)
 			validate(strokeWidth);
 
 		return new Line(style, src, stroke, strokeWidth, stipple, strokeLinecap,
-				level, fixed, fade, blur, isOutline);
+				level, fixed, fade, blur, isOutline, min);
 	}
 
 	public Line(int stroke, float width, Cap cap) {
@@ -122,6 +125,7 @@ public final class Line extends RenderInstruction {
 		this.fixed = true;
 		this.fade = -1;
 		this.stipple = 2;
+		this.min = 0;
 		color = GlUtils.colorToFloatP(stroke);
 	}
 
@@ -163,6 +167,8 @@ public final class Line extends RenderInstruction {
 
 	public final int stipple;
 
+	public final float min;
+
 	/**
 	 * @param style
 	 *            ...
@@ -186,10 +192,11 @@ public final class Line extends RenderInstruction {
 	 *            ...
 	 * @param isOutline
 	 *            ...
+	 * @param min ...
 	 */
 	private Line(String style, String src, int stroke, float strokeWidth,
 			int stipple, Cap strokeLinecap, int level, boolean fixed,
-			int fade, float blur, boolean isOutline) {
+			int fade, float blur, boolean isOutline, float min) {
 		super();
 
 		this.style = style;
@@ -221,6 +228,7 @@ public final class Line extends RenderInstruction {
 		this.blur = blur;
 		this.fade = fade;
 		this.stipple = stipple;
+		this.min = min;
 	}
 
 	/**
@@ -248,10 +256,11 @@ public final class Line extends RenderInstruction {
 	 *            ...
 	 * @param isOutline
 	 *            ...
+	 * @param min ...
 	 */
 	private Line(Line line, String style, String src, int stroke, float strokeWidth,
 			int stipple, Cap strokeLinecap, int level, boolean fixed,
-			int fade, float blur, boolean isOutline) {
+			int fade, float blur, boolean isOutline, float min) {
 		super();
 
 		this.style = style;
@@ -268,6 +277,7 @@ public final class Line extends RenderInstruction {
 		this.cap = strokeLinecap;
 		this.blur = blur;
 		this.stipple = stipple;
+		this.min = min;
 	}
 
 	@Override
diff --git a/src/org/oscim/utils/GlUtils.java b/src/org/oscim/utils/GlUtils.java
index 353665e7..e3b1a4a0 100644
--- a/src/org/oscim/utils/GlUtils.java
+++ b/src/org/oscim/utils/GlUtils.java
@@ -14,6 +14,9 @@
  */
 package org.oscim.utils;
 
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
 import org.oscim.renderer.GLRenderer;
 
 import android.graphics.Bitmap;
@@ -38,20 +41,23 @@ public class GlUtils {
 		GLES20.glGenTextures(1, textures, 0);
 
 		int textureID = textures[0];
-		// Log.i(TAG, "new texture " + textureID + " " + textureCnt++);
 
 		GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureID);
 
-		GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,
+		GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
+				GLES20.GL_TEXTURE_MIN_FILTER,
 				GLES20.GL_LINEAR);
 
-		GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER,
+		GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
+				GLES20.GL_TEXTURE_MAG_FILTER,
 				GLES20.GL_LINEAR);
 
-		GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,
+		GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
+				GLES20.GL_TEXTURE_WRAP_S,
 				GLES20.GL_CLAMP_TO_EDGE);
 
-		GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,
+		GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
+				GLES20.GL_TEXTURE_WRAP_T,
 				GLES20.GL_CLAMP_TO_EDGE);
 
 		GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
@@ -59,6 +65,37 @@ public class GlUtils {
 		return textureID;
 	}
 
+	public static int loadTexture(byte[] pixel, int width, int height, int format,
+			int wrap_s, int wrap_t) {
+		int[] textureIds = new int[1];
+		GLES20.glGenTextures(1, textureIds, 0);
+
+		GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureIds[0]);
+
+		GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
+				GLES20.GL_TEXTURE_MIN_FILTER,
+				GLES20.GL_NEAREST);
+		GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
+				GLES20.GL_TEXTURE_MAG_FILTER,
+				GLES20.GL_NEAREST);
+		GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
+				GLES20.GL_TEXTURE_WRAP_S,
+				wrap_s); // Set U Wrapping
+		GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
+				GLES20.GL_TEXTURE_WRAP_T,
+				wrap_t); // Set V Wrapping
+
+		ByteBuffer buf = ByteBuffer.allocateDirect(width * height).order(ByteOrder.nativeOrder());
+		buf.put(pixel);
+		buf.position(0);
+
+		GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, format, width, height, 0, format,
+				GLES20.GL_UNSIGNED_BYTE, buf);
+
+		GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
+		return textureIds[0];
+	}
+
 	/**
 	 * @param shaderType
 	 *            shader type