From d0ad2f3bd48674767f88b2047b688faf77eb9678 Mon Sep 17 00:00:00 2001
From: Hannes Janetzek <hannes.janetzek@gmail.com>
Date: Sun, 6 Jan 2013 21:52:10 +0100
Subject: [PATCH] - LineClipper added start(x0,y0), clipNext(x1,y1) 'state'
 clipping mode - use vec4 array for extrusion colors -> set color only once
 for all tiles - use full range for direction vector in extrusion vertex

---
 .../oscim/renderer/layer/ExtrusionLayer.java  |  14 ++-
 .../renderer/overlays/ExtrusionOverlay.java   |  56 +++++----
 src/org/oscim/utils/LineClipper.java          | 110 ++++++++++++------
 3 files changed, 109 insertions(+), 71 deletions(-)

diff --git a/src/org/oscim/renderer/layer/ExtrusionLayer.java b/src/org/oscim/renderer/layer/ExtrusionLayer.java
index 31e29027..42563230 100644
--- a/src/org/oscim/renderer/layer/ExtrusionLayer.java
+++ b/src/org/oscim/renderer/layer/ExtrusionLayer.java
@@ -78,10 +78,11 @@ public class ExtrusionLayer extends Layer {
 		boolean simple = true;
 		int startVertex = mNumVertices;
 
+		// just a guess to make it look ok
 		if (height == 0)
-			height = 400;
+			height = 320;
 		else
-			height *= 40;
+			height *= 30;
 
 		int length = 0;
 		for (int ipos = 0, ppos = 0, n = index.length; ipos < n; ipos++, ppos += length) {
@@ -212,7 +213,8 @@ public class ExtrusionLayer extends Layer {
 		float ux, uy;
 
 		float a = (float) Math.sqrt(vx * vx + vy * vy);
-		short color1 = getColor(vx, a);
+		//float vlight = vx > 0 ? (vx / a) : -(vx / a);
+		short color1 = (short) ((1 + vx / a) * 127);
 		short fcolor = color1;
 		short color2 = 0;
 
@@ -226,6 +228,8 @@ public class ExtrusionLayer extends Layer {
 		short[] vertices = mCurVertices.vertices;
 		int v = mCurVertices.used;
 
+		mClipper.clipStart((int) nx, (int) ny);
+
 		for (int i = 2, n = vertexCnt + 2; i < n; i += 2, v += 8) {
 			cx = nx;
 			cy = ny;
@@ -269,7 +273,7 @@ public class ExtrusionLayer extends Layer {
 
 			// set lighting (by direction)
 			a = (float) Math.sqrt(vx * vx + vy * vy);
-			color2 = getColor(vx, a);
+			color2 = (short) ((1 + vx / a) * 127); //getColor(vx, a);
 
 			short c;
 			if (even == 0)
@@ -294,7 +298,7 @@ public class ExtrusionLayer extends Layer {
 			}
 
 			/* check if face is within tile */
-			if (!mClipper.clip((int) cx, (int) cy, (int) nx, (int) ny)) {
+			if (!mClipper.clipNext((int) nx, (int) ny)) {
 				even = (even + 1) % 2;
 				continue;
 			}
diff --git a/src/org/oscim/renderer/overlays/ExtrusionOverlay.java b/src/org/oscim/renderer/overlays/ExtrusionOverlay.java
index 213aab56..f8d23fe8 100644
--- a/src/org/oscim/renderer/overlays/ExtrusionOverlay.java
+++ b/src/org/oscim/renderer/overlays/ExtrusionOverlay.java
@@ -146,11 +146,15 @@ public class ExtrusionOverlay extends RenderOverlay {
 		return null;
 	}
 
-	boolean debug = false;
+	private boolean debug = false;
+	private final float[] mVPMatrix = new float[16];
 
 	@Override
 	public synchronized void render(MapPosition pos, float[] mv, float[] proj) {
 
+		Matrix.multiplyMM(mVPMatrix, 0, proj, 0, pos.viewMatrix, 0);
+		proj = mVPMatrix;
+
 		MapTile[] tiles = mTiles;
 
 		float div = FastMath.pow(tiles[0].zoomLevel - pos.zoomLevel);
@@ -162,7 +166,7 @@ public class ExtrusionOverlay extends RenderOverlay {
 
 			GLState.enableVertexArrays(hExtrusionVertexPosition, hExtrusionLightPosition);
 			GLES20.glUniform1i(hExtrusionMode, 0);
-			GLES20.glUniform4f(hExtrusionColor, 0.6f, 0.6f, 0.6f, 0.8f);
+			GLES20.glUniform4fv(hExtrusionColor, 4, mColor, 0);
 
 			GLState.test(false, false);
 
@@ -209,6 +213,7 @@ public class ExtrusionOverlay extends RenderOverlay {
 		GLES20.glDepthMask(true);
 		GLES20.glColorMask(false, false, false, false);
 		GLES20.glUniform1i(hExtrusionMode, 0);
+		GLES20.glUniform4fv(hExtrusionColor, 4, mColor, 0);
 
 		// draw to depth buffer
 		for (int i = 0; i < mTileCnt; i++) {
@@ -255,30 +260,23 @@ public class ExtrusionOverlay extends RenderOverlay {
 
 			// draw roof
 			GLES20.glUniform1i(hExtrusionMode, 0);
-			GLES20.glUniform4fv(hExtrusionColor, 1, mRoofColor, 0);
 			GLES20.glDrawElements(GLES20.GL_TRIANGLES, el.mIndiceCnt[2],
 					GLES20.GL_UNSIGNED_SHORT, (el.mIndiceCnt[0] + el.mIndiceCnt[1]) * 2);
 
 			// draw sides 1
-			GLES20.glUniform4fv(hExtrusionColor, 1, mColor, 0);
 			GLES20.glUniform1i(hExtrusionMode, 1);
 			GLES20.glDrawElements(GLES20.GL_TRIANGLES, el.mIndiceCnt[0],
 					GLES20.GL_UNSIGNED_SHORT, 0);
 
 			// draw sides 2
-			GLES20.glUniform4fv(hExtrusionColor, 1, mColor2, 0);
 			GLES20.glUniform1i(hExtrusionMode, 2);
-
 			GLES20.glDrawElements(GLES20.GL_TRIANGLES, el.mIndiceCnt[1],
 					GLES20.GL_UNSIGNED_SHORT, el.mIndiceCnt[0] * 2);
 
-			//GLES20.glDepthFunc(GLES20.GL_LEQUAL);
 			GLES20.glUniform1i(hExtrusionMode, 3);
-			GLES20.glUniform4f(hExtrusionColor, 0.7f, 0.7f, 0.7f, 1.0f);
 			GLES20.glDrawElements(GLES20.GL_LINES, el.mIndiceCnt[3],
 					GLES20.GL_UNSIGNED_SHORT,
 					(el.mIndiceCnt[0] + el.mIndiceCnt[1] + el.mIndiceCnt[2]) * 2);
-			//GLES20.glDepthFunc(GLES20.GL_EQUAL);
 
 			// just a temporary reference!
 			tiles[i] = null;
@@ -309,48 +307,46 @@ public class ExtrusionOverlay extends RenderOverlay {
 		matrix[5] = scale;
 		matrix[10] = scale / 1000f;
 
-		Matrix.multiplyMM(matrix, 0, mapPosition.viewMatrix, 0, matrix, 0);
 		Matrix.multiplyMM(matrix, 0, proj, 0, matrix, 0);
 	}
 
-	// sligthly differ adjacent faces to improve contrast
-	//float mColor[] = { 0.76872549f, 0.751960784f, 0.740196078f, 0.8f };
-	//float mColor2[] = { 0.76372549f, 0.751960784f, 0.745196078f, 0.8f };
+	private final float _a = 0.8f;
 
-	float mColor[] = { 201 / 255f, 200 / 255f, 198 / 255f, 0.8f };
-	float mColor2[] = { 201 / 255f, 200 / 255f, 199 / 255f, 0.8f };
-
-	//float mRoofColor[] = { 0.895f, 0.89f, 0.88f, 0.9f };
-	float _a = 0.8f;
-	float mRoofColor[] = { 236 / 255f * _a, 235 / 255f * _a, 234 / 255f * _a, _a };
+	private final float[] mColor = {
+			// roof color
+			236 / 255f * _a, 235 / 255f * _a, 234 / 255f * _a, _a,
+			// sligthly differ adjacent side faces to improve contrast
+			201 / 255f, 200 / 255f, 198 / 255f, _a,
+			200 / 255f, 200 / 255f, 196 / 255f, _a,
+			// roof outline
+			0.75f, 0.75f, 0.75f, 1.0f
+	};
 
 	final static String extrusionVertexShader = ""
 			+ "precision mediump float;"
 			+ "uniform mat4 u_mvp;"
-			+ "uniform vec4 u_color;"
+			+ "uniform vec4 u_color[4];"
 			+ "uniform int u_mode;"
 			+ "attribute vec4 a_position;"
 			+ "attribute vec2 a_light;"
 			+ "varying vec4 color;"
 			+ "const float ff = 255.0;"
+			+ "const float a = 0.8;"
 			+ "void main() {"
 			+ "  gl_Position = u_mvp * a_position;"
 			+ "  if (u_mode == 0)"
 			//     roof / depth pass
-			+ "    color = u_color;"
-			+ "  else {"
-			//    decrease contrast with distance
-			+ "   float alpha = 0.95 + gl_Position.z * 0.05;"
-			+ "    if (u_mode == 1)"
+			+ "    color = u_color[0];"
+			+ "  else if (u_mode == 1)"
 			//     sides 1 - use 0xff00
-			+ "    color = vec4(u_color.rgb * (a_light.y / ff * alpha), 1.0) * (0.8 * alpha);"
+			+ "    color = vec4(u_color[1].rgb * ((0.90 + (0.5 - (a_light.y / ff)) * 0.2) * a), a);"
 			+ "  else if (u_mode == 2)"
 			//     sides 2 - use 0x00ff
-			+ "    color = vec4(u_color.rgb * (a_light.x / ff * alpha), 1.0) * (0.8 * alpha);"
+			+ "    color = vec4(u_color[2].rgb * ((0.90 + (0.5 - (a_light.x / ff)) * 0.2) * a), a);"
 			+ "  else"
-			//     sides 2 - use 0x00ff
-			+ "    color = u_color * alpha;"
-			+ "}}";
+			//     outline - decrease contrast with distance
+			+ "    color = u_color[3] * (0.98 + gl_Position.z * 0.02);"
+			+ "}";
 
 	//	final static String extrusionVertexAnimShader = ""
 	//			+ "precision mediump float;"
diff --git a/src/org/oscim/utils/LineClipper.java b/src/org/oscim/utils/LineClipper.java
index d795b256..04fdb141 100644
--- a/src/org/oscim/utils/LineClipper.java
+++ b/src/org/oscim/utils/LineClipper.java
@@ -14,8 +14,6 @@
  */
 package org.oscim.utils;
 
-import android.graphics.Point;
-
 /**
  * @author Hannes Janetzek
  *         taken from http://en.wikipedia.org/wiki/Cohen%E2%80%93
@@ -24,14 +22,11 @@ import android.graphics.Point;
 
 public class LineClipper {
 
-	public static final int INSIDE = 0; // 0000
-	public static final int LEFT = 1; // 0001
-	public static final int RIGHT = 2; // 0010
-	public static final int BOTTOM = 4; // 0100
-	public static final int TOP = 8; // 1000
-
-	// Compute the bit code for a point (x, y) using the clip rectangle
-	// bounded diagonally by (xmin, ymin), and (xmax, ymax)
+	private static final int INSIDE = 0; // 0000
+	private static final int LEFT = 1; // 0001
+	private static final int RIGHT = 2; // 0010
+	private static final int BOTTOM = 4; // 0100
+	private static final int TOP = 8; // 1000
 
 	private int xmin, xmax, ymin, ymax;
 
@@ -42,41 +37,71 @@ public class LineClipper {
 		this.ymax = maxy;
 	}
 
-	public boolean clip(Point p1, Point p2) {
-		return clip(p1.x, p1.y, p2.x, p2.y);
+	private int mPrevOutcode;
+	private int mPrevX;
+	private int mPrevY;
+
+	public void clipStart(int x0, int y0) {
+		mPrevX = x0;
+		mPrevY = y0;
+
+		int outcode = INSIDE;
+		if (x0 < xmin)
+			outcode |= LEFT;
+		else if (x0 > xmax)
+			outcode |= RIGHT;
+		if (y0 < ymin)
+			outcode |= BOTTOM;
+		else if (y0 > ymax)
+			outcode |= TOP;
+
+		mPrevOutcode = outcode;
 	}
 
-	public int outCode(int x, int y) {
-		int code;
+	public boolean clipNext(int x1, int y1) {
+		boolean accept;
 
-		code = INSIDE; // initialised as being inside of clip window
+		int outcode = INSIDE;
+		if (x1 < xmin)
+			outcode |= LEFT;
+		else if (x1 > xmax)
+			outcode |= RIGHT;
+		if (y1 < ymin)
+			outcode |= BOTTOM;
+		else if (y1 > ymax)
+			outcode |= TOP;
 
-		if (x < xmin) // to the left of clip window
-			code |= LEFT;
-		else if (x > xmax) // to the right of clip window
-			code |= RIGHT;
-		if (y < ymin) // below the clip window
-			code |= BOTTOM;
-		else if (y > ymax) // above the clip window
-			code |= TOP;
+		if ((mPrevOutcode | outcode) == 0) {
+			// Bitwise OR is 0. Trivially accept
+			accept = true;
+		} else if ((mPrevOutcode & outcode) != 0) {
+			// Bitwise AND is not 0. Trivially reject
+			accept = false;
+		} else {
+			accept = clip(mPrevX, mPrevY, x1, y1, xmin, ymin, xmax, ymax, mPrevOutcode, outcode);
+		}
+		mPrevOutcode = outcode;
+		mPrevX = x1;
+		mPrevY = y1;
 
-		return code;
+		return accept;
 	}
 
 	// CohenSutherland clipping algorithm clips a line from
 	// P0 = (x0, y0) to P1 = (x1, y1) against a rectangle with 
 	// diagonal from (xmin, ymin) to (xmax, ymax).
-	public boolean clip(int x0, int y0, int x1, int y1) {
-		// compute outcodes for P0, P1, and whatever point lies outside the clip rectangle
-		int outcode0 = outCode(x0, y0);
-		int outcode1 = outCode(x1, y1);
+	private static boolean clip(int x0, int y0, int x1, int y1,
+			int xmin, int ymin, int xmax, int ymax, int outcode0, int outcode1) {
+
 		boolean accept = false;
 
 		while (true) {
-			if ((outcode0 | outcode1) == 0) { // Bitwise OR is 0. Trivially accept and get out of loop
+			if ((outcode0 | outcode1) == 0) {
+				// Bitwise OR is 0. Trivially accept and get out of loop
 				accept = true;
 				break;
-			} else if ((outcode0 & outcode1) != 0) { // Bitwise AND is not 0. Trivially reject and get out of loop
+			} else if ((outcode0 & outcode1) != 0) {
+				// Bitwise AND is not 0. Trivially reject and get out of loop
 				break;
 			} else {
 				// failed both tests, so calculate the line segment to clip
@@ -92,32 +117,45 @@ public class LineClipper {
 				if ((outcodeOut & TOP) != 0) { // point is above the clip rectangle
 					x = x0 + (x1 - x0) * (ymax - y0) / (y1 - y0);
 					y = ymax;
-				} else if ((outcodeOut & BOTTOM) != 0) { // point is below the clip rectangle
+				} else if ((outcodeOut & BOTTOM) != 0) {
+					// point is below the clip rectangle
 					x = x0 + (x1 - x0) * (ymin - y0) / (y1 - y0);
 					y = ymin;
-				} else if ((outcodeOut & RIGHT) != 0) { // point is to the right of clip rectangle
+				} else if ((outcodeOut & RIGHT) != 0) {
+					// point is to the right of clip rectangle
 					y = y0 + (y1 - y0) * (xmax - x0) / (x1 - x0);
 					x = xmax;
-				} else if ((outcodeOut & LEFT) != 0) { // point is to the left of clip rectangle
+				} else if ((outcodeOut & LEFT) != 0) {
+					// point is to the left of clip rectangle
 					y = y0 + (y1 - y0) * (xmin - x0) / (x1 - x0);
 					x = xmin;
 				}
 
+				int outcode = INSIDE;
+				if (x < xmin)
+					outcode |= LEFT;
+				else if (x > xmax)
+					outcode |= RIGHT;
+				if (y < ymin)
+					outcode |= BOTTOM;
+				else if (y > ymax)
+					outcode |= TOP;
+
 				// Now we move outside point to intersection point to clip
 				// and get ready for next pass.
 				if (outcodeOut == outcode0) {
 					x0 = x;
 					y0 = y;
-					outcode0 = outCode(x0, y0);
+					outcode0 = outcode;
 				} else {
 					x1 = x;
 					y1 = y;
-					outcode1 = outCode(x1, y1);
+					outcode1 = outcode;
 				}
 			}
 		}
 
-		// TODO do sth with the result x0...
+		// TODO could do sth with the result x0...
 		return accept;
 	}