more work on building layer

This commit is contained in:
Hannes Janetzek 2013-01-03 18:29:13 +01:00
parent 74ca621de0
commit eb278585fa
22 changed files with 1105 additions and 79 deletions

View File

@ -53,9 +53,10 @@ public interface IMapDatabaseCallback {
* length of way data in wayNodes * length of way data in wayNodes
* @param closed * @param closed
* way is closed (means need to add endpoint == startpoint) * way is closed (means need to add endpoint == startpoint)
* @param prio TODO
*/ */
void renderWay(byte layer, Tag[] tags, float[] wayNodes, short[] wayLength, void renderWay(byte layer, Tag[] tags, float[] wayNodes, short[] wayLength,
boolean closed); boolean closed, int prio);
/** /**
* TBD: check if way will be rendered before decoding * TBD: check if way will be rendered before decoding

View File

@ -961,7 +961,7 @@ public class MapDatabase implements IMapDatabase {
&& mWayNodes[1] == mWayNodes[l - 1]; && mWayNodes[1] == mWayNodes[l - 1];
mapDatabaseCallback mapDatabaseCallback
.renderWay(layer, tags, mWayNodes, wayLengths, closed); .renderWay(layer, tags, mWayNodes, wayLengths, closed, 0);
} }
} }

View File

@ -298,7 +298,7 @@ public class MapDatabase implements IMapDatabase {
private static final int TAG_ELEM_INDEX = 12; private static final int TAG_ELEM_INDEX = 12;
private static final int TAG_ELEM_COORDS = 13; private static final int TAG_ELEM_COORDS = 13;
private static final int TAG_ELEM_LAYER = 21; private static final int TAG_ELEM_LAYER = 21;
// private static final int TAG_ELEM_PRIORITY = 31; private static final int TAG_ELEM_PRIORITY = 31;
private short[] mTmpKeys = new short[100]; private short[] mTmpKeys = new short[100];
private short[] mIndices = new short[10]; private short[] mIndices = new short[10];
@ -376,6 +376,8 @@ public class MapDatabase implements IMapDatabase {
int indexCnt = 1; int indexCnt = 1;
int coordCnt = 0; int coordCnt = 0;
int layer = 5; int layer = 5;
int prio = 0;
Tag[] tags = null; Tag[] tags = null;
short[] index = null; short[] index = null;
@ -441,6 +443,10 @@ public class MapDatabase implements IMapDatabase {
layer = decodeVarint32(); layer = decodeVarint32();
break; break;
case TAG_ELEM_PRIORITY:
prio = decodeVarint32();
break;
default: default:
Log.d(TAG, "X invalid type for way: " + tag); Log.d(TAG, "X invalid type for way: " + tag);
} }
@ -457,9 +463,9 @@ public class MapDatabase implements IMapDatabase {
float[] coords = mTmpCoords; float[] coords = mTmpCoords;
if (type == TAG_TILE_LINE) if (type == TAG_TILE_LINE)
mMapGenerator.renderWay((byte) layer, tags, coords, index, false); mMapGenerator.renderWay((byte) layer, tags, coords, index, false, prio);
else if (type == TAG_TILE_POLY) else if (type == TAG_TILE_POLY)
mMapGenerator.renderWay((byte) layer, tags, coords, index, true); mMapGenerator.renderWay((byte) layer, tags, coords, index, true, prio);
else { else {
if (debug) if (debug)
Log.d(TAG, "add poi " + coords[1] + " " + coords[0] + " " + tags[0]); Log.d(TAG, "add poi " + coords[1] + " " + coords[0] + " " + tags[0]);

View File

@ -556,7 +556,7 @@ public class MapDatabase implements IMapDatabase {
if (layer == 0) if (layer == 0)
layer = 5; layer = 5;
mMapGenerator.renderWay((byte) layer, tags, coords, index, polygon); mMapGenerator.renderWay((byte) layer, tags, coords, index, polygon, 0);
return true; return true;
} }

View File

@ -182,7 +182,7 @@ public class MapDatabase implements IMapDatabase {
short[] idx = new short[mIndexPos]; short[] idx = new short[mIndexPos];
System.arraycopy(mIndex, 0, idx, 0, mIndexPos); System.arraycopy(mIndex, 0, idx, 0, mIndexPos);
mapDatabaseCallback.renderWay((byte) 0, mTags, mCoords, idx, polygon); mapDatabaseCallback.renderWay((byte) 0, mTags, mCoords, idx, polygon, 0);
} }
} }
} catch (SQLException e) { } catch (SQLException e) {

View File

@ -100,7 +100,7 @@ public class MapDatabase implements IMapDatabase {
mIndex[2] = 10; mIndex[2] = 10;
mIndex[3] = 0; mIndex[3] = 0;
mapDatabaseCallback.renderWay((byte) 0, mTags, mCoords, mIndex, true); mapDatabaseCallback.renderWay((byte) 0, mTags, mCoords, mIndex, true, 0);
mIndex[0] = 4; mIndex[0] = 4;
mIndex[1] = -1; mIndex[1] = -1;
@ -113,7 +113,7 @@ public class MapDatabase implements IMapDatabase {
Tag[] tags = new Tag[2]; Tag[] tags = new Tag[2];
tags[0] = mTagsWay[0]; tags[0] = mTagsWay[0];
tags[1] = mTagsWay[1]; tags[1] = mTagsWay[1];
mapDatabaseCallback.renderWay((byte) 0, tags, mCoords, mIndex, false); mapDatabaseCallback.renderWay((byte) 0, tags, mCoords, mIndex, false, 0);
// center up // center up
mCoords[0] = size / 2; mCoords[0] = size / 2;
@ -124,7 +124,7 @@ public class MapDatabase implements IMapDatabase {
tags[0] = mTagsWay[0]; tags[0] = mTagsWay[0];
tags[1] = mTagsWay[1]; tags[1] = mTagsWay[1];
mapDatabaseCallback.renderWay((byte) 0, tags, mCoords, mIndex, mapDatabaseCallback.renderWay((byte) 0, tags, mCoords, mIndex,
false); false, 0);
// center down // center down
mCoords[0] = size / 2; mCoords[0] = size / 2;
@ -134,7 +134,7 @@ public class MapDatabase implements IMapDatabase {
tags = new Tag[2]; tags = new Tag[2];
tags[0] = mTagsWay[0]; tags[0] = mTagsWay[0];
tags[1] = mTagsWay[1]; tags[1] = mTagsWay[1];
mapDatabaseCallback.renderWay((byte) 0, tags, mCoords, mIndex, false); mapDatabaseCallback.renderWay((byte) 0, tags, mCoords, mIndex, false, 0);
// left-top to center // left-top to center
mCoords[0] = size / 2; mCoords[0] = size / 2;
@ -144,7 +144,7 @@ public class MapDatabase implements IMapDatabase {
tags = new Tag[2]; tags = new Tag[2];
tags[0] = mTagsWay[0]; tags[0] = mTagsWay[0];
tags[1] = mTagsWay[1]; tags[1] = mTagsWay[1];
mapDatabaseCallback.renderWay((byte) 1, tags, mCoords, mIndex, false); mapDatabaseCallback.renderWay((byte) 1, tags, mCoords, mIndex, false, 0);
// middle horizontal // middle horizontal
mCoords[0] = 0; mCoords[0] = 0;
@ -154,7 +154,7 @@ public class MapDatabase implements IMapDatabase {
tags = new Tag[2]; tags = new Tag[2];
tags[0] = mTagsWay[0]; tags[0] = mTagsWay[0];
tags[1] = mTagsWay[1]; tags[1] = mTagsWay[1];
mapDatabaseCallback.renderWay((byte) 1, tags, mCoords, mIndex, false); mapDatabaseCallback.renderWay((byte) 1, tags, mCoords, mIndex, false, 0);
// middle horizontal // middle horizontal
mCoords[0] = 10; mCoords[0] = 10;
@ -164,7 +164,7 @@ public class MapDatabase implements IMapDatabase {
tags = new Tag[2]; tags = new Tag[2];
tags[0] = mTagsWay[0]; tags[0] = mTagsWay[0];
tags[1] = mTagsWay[1]; tags[1] = mTagsWay[1];
mapDatabaseCallback.renderWay((byte) 1, tags, mCoords, mIndex, false); mapDatabaseCallback.renderWay((byte) 1, tags, mCoords, mIndex, false, 0);
// lon1 = size / 2; // lon1 = size / 2;
// lat1 = size / 2; // lat1 = size / 2;

View File

@ -24,6 +24,7 @@ import org.oscim.database.IMapDatabaseCallback;
import org.oscim.database.QueryResult; import org.oscim.database.QueryResult;
import org.oscim.renderer.MapTile; import org.oscim.renderer.MapTile;
import org.oscim.renderer.WayDecorator; import org.oscim.renderer.WayDecorator;
import org.oscim.renderer.layer.ExtrusionLayer;
import org.oscim.renderer.layer.Layer; import org.oscim.renderer.layer.Layer;
import org.oscim.renderer.layer.Layers; import org.oscim.renderer.layer.Layers;
import org.oscim.renderer.layer.LineLayer; import org.oscim.renderer.layer.LineLayer;
@ -103,6 +104,7 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback {
private float mProjectionScaleFactor; private float mProjectionScaleFactor;
private float mPoiX, mPoiY; private float mPoiX, mPoiY;
private int mPriority;
private Tag mTagEmptyName = new Tag(Tag.TAG_KEY_NAME, null, false); private Tag mTagEmptyName = new Tag(Tag.TAG_KEY_NAME, null, false);
private Tag mTagName; private Tag mTagName;
@ -159,6 +161,14 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback {
mLayers = new Layers(); mLayers = new Layers();
//Log.d(TAG, "loading: " + tile);
//if ((tile.zoomLevel != 17) || (tile.tileX == 68752 && tile.tileY == 42640))
//if ((tile.zoomLevel != 17) || (tile.tileX == 68743 && tile.tileY == 42681))
//if ((tile.zoomLevel != 17) || (tile.tileX == 68736 && tile.tileY == 42653))
// TODO: building with non simple holes (Berlin):
//if ((tile.zoomLevel != 17) || (tile.tileX == 70428 && tile.tileY == 43009)),
//if ((tile.zoomLevel != 17) || (tile.tileX == 70463 && tile.tileY == 42990))
if (mMapDatabase.executeQuery(tile, this) != QueryResult.SUCCESS) { if (mMapDatabase.executeQuery(tile, this) != QueryResult.SUCCESS) {
//Log.d(TAG, "Failed loading: " + tile); //Log.d(TAG, "Failed loading: " + tile);
mLayers.clear(); mLayers.clear();
@ -188,6 +198,9 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback {
mLayers = null; mLayers = null;
mLabels = null; mLabels = null;
if (tile.layers.extrusionLayers != null)
((ExtrusionLayer) tile.layers.extrusionLayers).ready = true;
return true; return true;
} }
@ -226,16 +239,19 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback {
return mMapDatabase; return mMapDatabase;
} }
private boolean mRenderBuildingModel;
private boolean filterTags(Tag[] tags) { private boolean filterTags(Tag[] tags) {
mRenderBuildingModel = false;
for (int i = 0; i < tags.length; i++) { for (int i = 0; i < tags.length; i++) {
String key = tags[i].key; String key = tags[i].key;
if (key == Tag.TAG_KEY_NAME) { if (tags[i].key == Tag.TAG_KEY_NAME) {
mTagName = tags[i]; mTagName = tags[i];
tags[i] = mTagEmptyName; tags[i] = mTagEmptyName;
} else if (mCurrentTile.zoomLevel >= 17 && } else if (mCurrentTile.zoomLevel >= 17 &&
key == TAG_BUILDING) { key == TAG_BUILDING) {
mRenderBuildingModel = true;
return false;
} }
} }
return true; return true;
@ -292,20 +308,19 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback {
@Override @Override
public void renderWay(byte layer, Tag[] tags, float[] coords, short[] indices, public void renderWay(byte layer, Tag[] tags, float[] coords, short[] indices,
boolean closed) { boolean closed, int prio) {
// reset state // reset state
mTagName = null; mTagName = null;
mCurLineLayer = null; mCurLineLayer = null;
mPriority = prio;
mClosed = closed; mClosed = closed;
// replace tags that should not be cached in Rendertheme (e.g. name) // replace tags that should not be cached in Rendertheme (e.g. name)
if (!filterTags(tags)) if (!filterTags(tags))
return; return;
mDrawingLayer = getValidLayer(layer) * mLevels;
// mProjected = false; // mProjected = false;
// mSimplify = 0.5f; // mSimplify = 0.5f;
// if (closed) { // if (closed) {
@ -317,6 +332,7 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback {
// mSimplify = 0; // mSimplify = 0;
// } // }
mDrawingLayer = getValidLayer(layer) * mLevels;
mCoords = coords; mCoords = coords;
mIndices = indices; mIndices = indices;
@ -394,14 +410,24 @@ public class TileGenerator implements IRenderCallback, IMapDatabaseCallback {
@Override @Override
public void renderArea(Area area, int level) { public void renderArea(Area area, int level) {
int numLayer = mDrawingLayer + level;
if (mRenderBuildingModel) {
//Log.d(TAG, "add buildings: " + mCurrentTile + " " + mPriority);
if (mLayers.extrusionLayers == null)
mLayers.extrusionLayers = new ExtrusionLayer(0);
((ExtrusionLayer) mLayers.extrusionLayers).addBuildings(mCoords, mIndices, mPriority);
return;
}
if (!mDebugDrawPolygons) if (!mDebugDrawPolygons)
return; return;
// if (!mProjected && !projectToTile()) // if (!mProjected && !projectToTile())
// return; // return;
int numLayer = mDrawingLayer + level;
PolygonLayer layer = (PolygonLayer) mLayers.getLayer(numLayer, Layer.POLYGON); PolygonLayer layer = (PolygonLayer) mLayers.getLayer(numLayer, Layer.POLYGON);
if (layer == null) if (layer == null)
return; return;

View File

@ -89,8 +89,7 @@ public final class TextureRenderer {
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0); GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
} }
public static Layer draw(Layer layer, float scale, float[] projection, public static Layer draw(Layer layer, float scale, float[] projection, float matrix[]) {
float matrix[], int offset) {
// GlUtils.checkGlError("draw texture >"); // GlUtils.checkGlError("draw texture >");
GLES20.glUseProgram(mTextureProgram); GLES20.glUseProgram(mTextureProgram);
@ -121,7 +120,7 @@ public final class TextureRenderer {
// can only draw MAX_ITEMS in each iteration // can only draw MAX_ITEMS in each iteration
for (int i = 0; i < to.vertices; i += maxVertices) { for (int i = 0; i < to.vertices; i += maxVertices) {
// to.offset * (24(shorts) * 2(short-bytes) / 6(indices) == 8) // to.offset * (24(shorts) * 2(short-bytes) / 6(indices) == 8)
int off = (to.offset + i) * 8 + offset; int off = (to.offset + i) * 8 + tl.offset;
GLES20.glVertexAttribPointer(hTextureVertex, 4, GLES20.glVertexAttribPointer(hTextureVertex, 4,
GLES20.GL_SHORT, false, 12, off); GLES20.GL_SHORT, false, 12, off);

View File

@ -35,6 +35,9 @@ import android.util.Log;
/** /**
* @author Hannes Janetzek * @author Hannes Janetzek
* @TODO
* - this class should probably not be in 'renderer' -> tilemap?
* - make it general for reuse in tile-overlays
*/ */
public class TileManager { public class TileManager {
static final String TAG = TileManager.class.getSimpleName(); static final String TAG = TileManager.class.getSimpleName();

View File

@ -0,0 +1,475 @@
/*
* Copyright 2012, 2013 OpenScienceMap
*
* 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.layer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import org.oscim.renderer.GLRenderer;
import org.oscim.view.MapView;
import org.quake.triangle.TriangleJNI;
import android.opengl.GLES20;
import android.util.Log;
/**
* @author Hannes Janetzek
*/
public class ExtrusionLayer extends Layer {
private final static String TAG = ExtrusionLayer.class.getName();
private static final float S = GLRenderer.COORD_MULTIPLIER;
public int mIndicesBufferID;
public int mVertexBufferID;
public int mNumIndices = 0;
private int mNumVertices = 0;
private VertexPoolItem mVertices, mCurVertices;
private VertexPoolItem mIndices[], mCurIndices[];
public int mIndiceCnt[] = { 0, 0, 0 };
public ExtrusionLayer(int level) {
this.type = Layer.EXTRUSION;
this.layer = level;
mVertices = mCurVertices = VertexPool.get();
mIndices = new VertexPoolItem[3];
mCurIndices = new VertexPoolItem[3];
mIndices[0] = mCurIndices[0] = VertexPool.get();
mIndices[1] = mCurIndices[1] = VertexPool.get();
mIndices[2] = mCurIndices[2] = VertexPool.get();
}
public void addBuildings(float[] points, short[] index, int height) {
int complex = 0;
boolean simple = true;
if (height == 0)
height = 400;
else
height *= 40;
for (int i = 0, pos = 0, n = index.length; i < n; i++) {
int length = index[i];
// end marker
if (length < 0)
break;
// start next polygon
if (length == 0) {
complex = i + 1;
simple = true;
continue;
}
// need at least three points
if (length < 6) {
pos += length;
continue;
}
// check if polygon contains inner rings
//if (simple && ((i < n - 1) && (index[i + 1] > 0)))
// simple = false;
addOutline(points, pos, length, height, simple);
pos += length;
}
}
private void addOutline(float[] points, int pos, int len, float height, boolean simple) {
if (!MapView.enableClosePolygons)
len -= 2;
// add two vertices for last face to make zigzag indices work
boolean addFace = (len % 4 != 0);
// Log.d(TAG, "add: " + addFace + " " + len + " (" + pos + ")");
int vertexCnt = len + (addFace ? 2 : 0);
int indicesCnt = (len >> 1) * 6;
short h = (short) height;
float cx = points[pos + len - 2];
float cy = points[pos + len - 1];
float nx = points[pos + 0];
float ny = points[pos + 1];
float vx = nx - cx;
float vy = ny - cy;
float ca = (float) Math.sqrt(vx * vx + vy * vy);
float pa = ca;
float ux = vx;
float uy = vy;
float vlight = vx > 0 ? (vx / ca) : -(vx / ca) - 0.1f;
short color1 = (short) (200 + (50 * vlight));
short fcolor = color1;
short color2 = 0;
boolean even = true;
short[] vertices = mCurVertices.vertices;
int v = mCurVertices.used;
int convex = 0;
for (int i = 0; i < len; i += 2, v += 8) {
cx = nx;
cy = ny;
if (v == VertexPoolItem.SIZE) {
mCurVertices.used = VertexPoolItem.SIZE;
mCurVertices.next = VertexPool.get();
mCurVertices = mCurVertices.next;
vertices = mCurVertices.vertices;
v = 0;
}
vertices[v + 0] = vertices[v + 4] = (short) (cx * S);
vertices[v + 1] = vertices[v + 5] = (short) (cy * S);
vertices[v + 2] = 0;
vertices[v + 6] = h;
if (i < len - 2) {
nx = points[pos + i + 2];
ny = points[pos + i + 3];
vx = nx - cx;
vy = ny - cy;
ca = (float) Math.sqrt(vx * vx + vy * vy);
if (convex > -1) {
// TODO fix for straight line...
double dir = (vx * ux + vy * uy) / (ca * pa);
if (convex == 0)
convex = dir > 0 ? 1 : 2;
else if (convex == 1)
convex = dir > 0 ? 1 : -1;
else
convex = dir > 0 ? -1 : 2;
}
vlight = vx > 0 ? (vx / ca) : -(vx / ca) - 0.1f;
color2 = (short) (200 + (50 * vlight));
} else {
color2 = fcolor;
}
short c;
if (even)
c = (short) (color1 | color2 << 8);
else
c = (short) (color2 | color1 << 8);
vertices[v + 3] = vertices[v + 7] = c;
pa = ca;
ux = vx;
uy = vy;
color1 = color2;
even = !even;
}
if (addFace) {
if (v == VertexPoolItem.SIZE) {
mCurVertices.used = VertexPoolItem.SIZE;
mCurVertices.next = VertexPool.get();
mCurVertices = mCurVertices.next;
vertices = mCurVertices.vertices;
v = 0;
}
cx = points[pos + 0];
cy = points[pos + 1];
vertices[v + 0] = vertices[v + 4] = (short) (cx * S);
vertices[v + 1] = vertices[v + 5] = (short) (cy * S);
vertices[v + 2] = 0;
vertices[v + 6] = h;
short c = (short) (color1 | fcolor << 8);
vertices[v + 3] = vertices[v + 7] = c;
v += 8;
}
mCurVertices.used = v;
// fill ZigZagQuadIndices(tm)
for (int j = 0; j < 2; j++) {
short[] indices = mCurIndices[j].vertices;
// index id relative to mCurIndices
int i = mCurIndices[j].used;
// vertex id
v = mNumVertices + (j * 2);
for (int k = j * 2; k < len; k += 4) {
short s0 = (short) (v++);
short s1 = (short) (v++);
short s2 = (short) (v++);
short s3 = (short) (v++);
if (i == VertexPoolItem.SIZE) {
mCurIndices[j].used = VertexPoolItem.SIZE;
mCurIndices[j].next = VertexPool.get();
mCurIndices[j] = mCurIndices[j].next;
indices = mCurIndices[j].vertices;
i = 0;
}
if (k + 2 == len) {
// connect last to first (when number of faces is even)
if (!addFace) {
//Log.d(TAG, "connect last " + vertexCnt + " " + len);
s2 -= len;
s3 -= len;
}
}
indices[i++] = s0;
indices[i++] = s1;
indices[i++] = s2;
indices[i++] = s1;
indices[i++] = s3;
indices[i++] = s2;
//System.out.println(" i:" + (mNumIndices + (k * 6))
// + "\t(" + s0 + "," + s1 + "," + s2
// + ")\t(" + s1 + "," + s3 + "," + s2 + ")");
}
mCurIndices[j].used = i;
}
if (simple && (len <= 8 || convex > 0)) {
//Log.d(TAG, len + " is simple " + convex);
// roof indices for convex shapes
int i = mCurIndices[2].used;
short[] indices = mCurIndices[2].vertices;
short first = (short) (mNumVertices + 1);
for (int k = 0; k < len - 4; k += 2) {
if (i == VertexPoolItem.SIZE) {
mCurIndices[2].used = VertexPoolItem.SIZE;
mCurIndices[2].next = VertexPool.get();
mCurIndices[2] = mCurIndices[2].next;
indices = mCurIndices[2].vertices;
i = 0;
}
indices[i++] = first;
//if (convex != 2) {
// cw ?
indices[i++] = (short) (first + k + 4);
indices[i++] = (short) (first + k + 2);
// } else {
// indices[i++] = (short) (first + k + 2);
// indices[i++] = (short) (first + k + 4);
// }
// System.out.println("indice:" + k + "\t" + indices[cnt - 3] + ","
// + indices[cnt - 2]+ "," + indices[cnt - 1]);
indicesCnt += 3;
}
mCurIndices[2].used = i;
} else if (len < 400) {
// triangulate up to 200 points
short first = (short) (mNumVertices + 1);
int used = triangulate(points, pos, len, mCurIndices[2], first);
if (used > 0) {
indicesCnt += used;
// find the last item added..
VertexPoolItem it = mIndices[2];
while (it.next != null)
it = it.next;
mCurIndices[2] = it;
}
// mCurIndices[2].next = VertexPool.get();
// mCurIndices[2] = mCurIndices[2].next;
// short[] indices = mCurIndices[2].vertices;
// int used = triangulate(points, pos, len, indices);
// if (used > 0) {
// short first = (short) (mNumVertices + 1);
// for (int i = 0; i < used; i += 3) {
// indices[i] = (short) (indices[i] * 2 + first);
// short tmp = indices[i + 1];
// indices[i + 1] = (short) (indices[i + 2] * 2 + first);
// indices[i + 2] = (short) (tmp * 2 + first);
// }
// mCurIndices[2].used = used;
// indicesCnt += used;
// }
} else
Log.d(TAG, "skip >>>>>>>>>> : " + len + " <<<<<<<<<<<<<");
//Log.d(TAG, "add building: " + vertexCnt);
mNumVertices += vertexCnt;
mNumIndices += indicesCnt;
}
public void compile(ShortBuffer sbuf) {
if (mNumVertices == 0 || compiled)
return;
mVboIds = new int[2];
GLES20.glGenBuffers(2, mVboIds, 0);
mIndicesBufferID = mVboIds[0];
mVertexBufferID = mVboIds[1];
// upload indices
sbuf.clear();
for (int i = 0; i < 3; i++) {
for (VertexPoolItem vi = mIndices[i]; vi != null; vi = vi.next) {
//System.out.println("put indices: " + vi.used + " " + mNumIndices);
sbuf.put(vi.vertices, 0, vi.used);
mIndiceCnt[i] += vi.used;
}
}
// Log.d(TAG,"put indices: " + mNumIndices + "=="
// + (mIndiceCnt[0] + mIndiceCnt[1] + mIndiceCnt[2])
// + " " + mIndiceCnt[0] + " " + mIndiceCnt[1] + " " + mIndiceCnt[2]);
mNumIndices = mIndiceCnt[0] + mIndiceCnt[1] + mIndiceCnt[2];
sbuf.flip();
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, mIndicesBufferID);
GLES20.glBufferData(GLES20.GL_ELEMENT_ARRAY_BUFFER,
mNumIndices * 2, sbuf, GLES20.GL_DYNAMIC_DRAW);
sbuf.clear();
// upload vertices
for (VertexPoolItem vi = mVertices; vi != null; vi = vi.next) {
//System.out.println("put vertices: " + vi.used + " " + mNumVertices);
sbuf.put(vi.vertices, 0, vi.used);
}
sbuf.flip();
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mVertexBufferID);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER,
mNumVertices * 4 * 2, sbuf, GLES20.GL_DYNAMIC_DRAW);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
for (VertexPoolItem i : mIndices)
VertexPool.release(i);
VertexPool.release(mVertices);
compiled = true;
}
public boolean compiled = false;
int[] mVboIds;
public boolean ready;
@Override
protected void clear() {
if (compiled) {
GLES20.glDeleteBuffers(2, mVboIds, 0);
}
}
public void render() {
}
private static boolean initialized = false;
private static ShortBuffer sBuf;
private static FloatBuffer fBuf;
public static synchronized int triangulate(float[] points, int pos, int len,
VertexPoolItem item, int first) {
int numRings = 1;
if (!initialized) {
// FIXME also cleanup on shutdown!
fBuf = ByteBuffer.allocateDirect(360 * 4).order(ByteOrder.nativeOrder())
.asFloatBuffer();
sBuf = ByteBuffer.allocateDirect(720 * 2).order(ByteOrder.nativeOrder())
.asShortBuffer();
initialized = true;
}
fBuf.clear();
fBuf.put(points, pos, len);
sBuf.clear();
sBuf.put((short) (len >> 1)); // all points
sBuf.put((short) (len >> 1)); // outer ring
//sBuf.put((short)4); // inner ring
int numTris = TriangleJNI.triangulate(fBuf, numRings, sBuf, first);
int numIndices = numTris * 3;
sBuf.limit(numIndices);
sBuf.position(0);
for (int k = 0, cnt = 0; k < numIndices; k += cnt) {
cnt = VertexPoolItem.SIZE - item.used;
if (item.used == VertexPoolItem.SIZE) {
item.next = VertexPool.get();
item = item.next;
}
if (k + cnt > numIndices)
cnt = numIndices - k;
sBuf.get(item.vertices, item.used, cnt);
item.used += cnt;
}
// sBuf.get(sIndices, 0, numIndices);
//
// short[] indices = item.vertices;
// int i = item.used;
//
// for (int k = 0; k < numIndices; k += 3) {
// if (i == VertexPoolItem.SIZE) {
// item.used = VertexPoolItem.SIZE;
// item.next = VertexPool.get();
// item = item.next;
// indices = item.vertices;
// i = 0;
// }
// indices[i++] = sIndices[k + 0];
// indices[i++] = sIndices[k + 1];
// indices[i++] = sIndices[k + 2];
// }
// item.used = i;
return numIndices;
}
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2012 Hannes Janetzek * Copyright 2012, 2013 OpenScienceMap
* *
* This program is free software: you can redistribute it and/or modify it under the * 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 * terms of the GNU Lesser General Public License as published by the Free Software
@ -14,6 +14,9 @@
*/ */
package org.oscim.renderer.layer; package org.oscim.renderer.layer;
/**
* @authorHannes Janetzek
*/
public abstract class Layer { public abstract class Layer {
public final static byte LINE = 0; public final static byte LINE = 0;
public final static byte POLYGON = 1; public final static byte POLYGON = 1;
@ -21,15 +24,21 @@ public abstract class Layer {
public final static byte POITEXT = 3; public final static byte POITEXT = 3;
public final static byte SYMBOL = 4; public final static byte SYMBOL = 4;
public final static byte BITMAP = 5; public final static byte BITMAP = 5;
public final static byte TEXLINE = 6;
public final static byte EXTRUSION = 7;
public byte type; public byte type = -1;
public Layer next; public Layer next;
int layer; int layer;
// number of vertices this layer holds // number of vertices for this layer
public int verticesCnt; public int verticesCnt;
// vertices offset of this layer in VBO
// in case of line and polygon layer:
// - number of VERTICES offset for this layertype in VBO
// otherwise:
// - offset in byte in VBO
public int offset; public int offset;
VertexPoolItem pool; VertexPoolItem pool;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2012 Hannes Janetzek * Copyright 2012, 2013 OpenScienceMap
* *
* This program is free software: you can redistribute it and/or modify it under the * 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 * terms of the GNU Lesser General Public License as published by the Free Software
@ -18,13 +18,22 @@ import java.nio.ShortBuffer;
import android.util.Log; import android.util.Log;
/**
* @author Hannes Janetzek
*/
public class Layers { public class Layers {
// mixed Polygon and Line layers
public Layer layers; public Layer layers;
public int lineOffset;
public Layer textureLayers; public Layer textureLayers;
public int texOffset; public Layer extrusionLayers;
// To not need to switch VertexAttribPointer positions all the time:
// 1. polygons are packed in VBO at offset 0
// 2. lines afterwards at lineOffset
// 3. other layers keep their byte offset in Layer.offset
public int lineOffset;
private Layer mCurLayer; private Layer mCurLayer;
@ -78,10 +87,78 @@ public class Layers {
return ret; return ret;
} }
// public boolean uploadLayers(BufferObject vbo, boolean addFill, boolean limit) {
//
// int newSize = getSize();
// if (newSize == 0) {
// // Log.d(TAG, "empty");
// return true;
// }
//
// GLES20.glBindBuffer(GL_ARRAY_BUFFER, vbo.id);
//
// // use multiple buffers to avoid overwriting buffer while current
// // data is uploaded (or rather the blocking which is probably done to
// // avoid overwriting)
// int curBuffer = uploadCnt++ % rotateBuffers;
//
// ShortBuffer sbuf = shortBuffer[curBuffer];
//
// // add fill coordinates
// if (addFill)
// newSize += 8;
//
// if (sbuf.capacity() < newSize) {
// sbuf = ByteBuffer
// .allocateDirect(newSize * SHORT_BYTES)
// .order(ByteOrder.nativeOrder())
// .asShortBuffer();
//
// shortBuffer[curBuffer] = sbuf;
// } else {
// sbuf.clear();
// // if (addFill)
// // sbuf.position(8);
// }
//
// if (addFill)
// sbuf.put(mFillCoords, 0, 8);
//
// compile(sbuf, addFill);
//
// sbuf.flip();
//
// if (newSize != sbuf.remaining()) {
// Log.d(TAG, "wrong size: "
// + newSize + " "
// + sbuf.position() + " "
// + sbuf.limit() + " "
// + sbuf.remaining());
// return false;
// }
// newSize *= SHORT_BYTES;
//
// // reuse memory allocated for vbo when possible and allocated
// // memory is less then four times the new data
// if (vbo.size > newSize && vbo.size < newSize * 4
// && !limit) {
// GLES20.glBufferSubData(GL_ARRAY_BUFFER, 0, newSize, sbuf);
// } else {
// //mBufferMemoryUsage += newSize - vbo.size;
// vbo.size = newSize;
// GLES20.glBufferData(GL_ARRAY_BUFFER, vbo.size, sbuf, GL_DYNAMIC_DRAW);
// //mBufferMemoryUsage += vbo.size;
// }
//
// return true;
// }
private static int LINE_VERTEX_SHORTS = 4; private static int LINE_VERTEX_SHORTS = 4;
private static int POLY_VERTEX_SHORTS = 2; private static int POLY_VERTEX_SHORTS = 2;
private static int TEXTURE_VERTEX_SHORTS = 6; private static int TEXTURE_VERTEX_SHORTS = 6;
//private static int EXTRUSION_VERTEX_SHORTS = 4;
public int getSize() { public int getSize() {
int size = 0; int size = 0;
@ -91,12 +168,13 @@ public class Layers {
size += l.verticesCnt * LINE_VERTEX_SHORTS; size += l.verticesCnt * LINE_VERTEX_SHORTS;
else else
size += l.verticesCnt * POLY_VERTEX_SHORTS; size += l.verticesCnt * POLY_VERTEX_SHORTS;
} }
for (Layer l = textureLayers; l != null; l = l.next) { for (Layer l = textureLayers; l != null; l = l.next)
size += l.verticesCnt * TEXTURE_VERTEX_SHORTS; size += l.verticesCnt * TEXTURE_VERTEX_SHORTS;
}
//for (Layer l = extrusionLayers; l != null; l = l.next)
// size += l.verticesCnt * EXTRUSION_VERTEX_SHORTS;
return size; return size;
} }
@ -113,18 +191,18 @@ public class Layers {
lineOffset = sbuf.position() * 2; // * short-bytes lineOffset = sbuf.position() * 2; // * short-bytes
addLayerItems(sbuf, layers, Layer.LINE, 0); addLayerItems(sbuf, layers, Layer.LINE, 0);
texOffset = sbuf.position() * 2; // * short-bytes
for (Layer l = textureLayers; l != null; l = l.next) { for (Layer l = textureLayers; l != null; l = l.next) {
TextureLayer sl = (TextureLayer) l; TextureLayer tl = (TextureLayer) l;
sl.compile(sbuf); tl.compile(sbuf);
} }
// FIXME // for (Layer l = extrusionLayers; l != null; l = l.next) {
addLayerItems(sbuf, textureLayers, Layer.SYMBOL, 0); // ExtrusionLayer tl = (ExtrusionLayer) l;
// tl.compile(sbuf);
// }
} }
// optimization for lines and polygon: collect all pool items and add back in one go
private static void addLayerItems(ShortBuffer sbuf, Layer l, byte type, int pos) { private static void addLayerItems(ShortBuffer sbuf, Layer l, byte type, int pos) {
VertexPoolItem last = null, items = null; VertexPoolItem last = null, items = null;
@ -136,7 +214,8 @@ public class Layers {
if (it.next == null) if (it.next == null)
sbuf.put(it.vertices, 0, it.used); sbuf.put(it.vertices, 0, it.used);
else else
sbuf.put(it.vertices); sbuf.put(it.vertices, 0, VertexPoolItem.SIZE);
last = it; last = it;
} }
if (last == null) if (last == null)
@ -155,8 +234,22 @@ public class Layers {
VertexPool.release(items); VertexPool.release(items);
} }
public void clear() { static void addPoolItems(Layer l, ShortBuffer sbuf) {
l.offset = sbuf.position() * 2; // (* short-bytes)
for (VertexPoolItem it = l.pool; it != null; it = it.next) {
if (it.next == null)
sbuf.put(it.vertices, 0, it.used);
else
sbuf.put(it.vertices, 0, VertexPoolItem.SIZE);
}
VertexPool.release(l.pool);
l.pool = null;
}
// cleanup only when layers are not used by tile or overlay anymore!
public void clear() {
while (layers != null) { while (layers != null) {
Layer l = layers; Layer l = layers;
if (l.pool != null) { if (l.pool != null) {
@ -181,5 +274,20 @@ public class Layers {
l = l.next; l = l.next;
} }
textureLayers = null; textureLayers = null;
l = extrusionLayers;
while (l != null) {
l.clear();
if (l.pool != null) {
VertexPool.release(l.pool);
l.pool = null;
l.curItem = null;
}
l = l.next;
}
extrusionLayers = null;
} }
} }

View File

@ -14,8 +14,6 @@
*/ */
package org.oscim.renderer.layer; package org.oscim.renderer.layer;
import java.nio.ShortBuffer;
import org.oscim.renderer.TextureObject; import org.oscim.renderer.TextureObject;
import org.oscim.renderer.TextureRenderer; import org.oscim.renderer.TextureRenderer;
@ -85,14 +83,16 @@ public final class SymbolLayer extends TextureLayer {
symbols = item; symbols = item;
} }
@Override // @Override
void compile(ShortBuffer sbuf) { // void compile(ShortBuffer sbuf) {
if (TextureRenderer.debug) // if (TextureRenderer.debug)
Log.d("...", "compile"); // Log.d("...", "compile");
//
for (TextureObject to = textures; to != null; to = to.next) // for (TextureObject to = textures; to != null; to = to.next)
TextureObject.uploadTexture(to); // TextureObject.uploadTexture(to);
} //
// Layers.addPoolItems(this, sbuf);
// }
private final static int LBIT_MASK = 0xfffffffe; private final static int LBIT_MASK = 0xfffffffe;

View File

@ -14,13 +14,10 @@
*/ */
package org.oscim.renderer.layer; package org.oscim.renderer.layer;
import java.nio.ShortBuffer;
import org.oscim.renderer.TextureObject; import org.oscim.renderer.TextureObject;
import org.oscim.renderer.TextureRenderer; import org.oscim.renderer.TextureRenderer;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.util.FloatMath;
import android.util.Log; import android.util.Log;
public final class TextLayer extends TextureLayer { public final class TextLayer extends TextureLayer {
@ -92,15 +89,6 @@ public final class TextLayer extends TextureLayer {
labels = item; labels = item;
} }
@Override
void compile(ShortBuffer sbuf) {
if (TextureRenderer.debug)
Log.d("...", "compile");
for (TextureObject to = textures; to != null; to = to.next)
TextureObject.uploadTexture(to);
}
@Override @Override
public boolean prepare() { public boolean prepare() {
if (TextureRenderer.debug) if (TextureRenderer.debug)
@ -189,7 +177,7 @@ public final class TextLayer extends TextureLayer {
} else { } else {
float vx = it.x1 - it.x2; float vx = it.x1 - it.x2;
float vy = it.y1 - it.y2; float vy = it.y1 - it.y2;
float a = FloatMath.sqrt(vx * vx + vy * vy); float a = (float) Math.sqrt(vx * vx + vy * vy);
vx = vx / a; vx = vx / a;
vy = vy / a; vy = vy / a;

View File

@ -17,6 +17,9 @@ package org.oscim.renderer.layer;
import java.nio.ShortBuffer; import java.nio.ShortBuffer;
import org.oscim.renderer.TextureObject; import org.oscim.renderer.TextureObject;
import org.oscim.renderer.TextureRenderer;
import android.util.Log;
public abstract class TextureLayer extends Layer { public abstract class TextureLayer extends Layer {
public TextureObject textures; public TextureObject textures;
@ -26,7 +29,15 @@ public abstract class TextureLayer extends Layer {
* @param sbuf * @param sbuf
* buffer to add vertices * buffer to add vertices
*/ */
abstract void compile(ShortBuffer sbuf); void compile(ShortBuffer sbuf) {
if (TextureRenderer.debug)
Log.d("...", "compile");
for (TextureObject to = textures; to != null; to = to.next)
TextureObject.uploadTexture(to);
Layers.addPoolItems(this, sbuf);
}
abstract public boolean prepare(); abstract public boolean prepare();
} }

View File

@ -29,6 +29,15 @@ public class VertexPool {
pool = null; pool = null;
} }
// public static VertexPoolItem get(VertexPoolItem prev) {
// VertexPoolItem it = get();
// if (prev != null) {
// prev.next = it;
// prev.used = VertexPoolItem.SIZE;
// }
// return it;
// }
public static synchronized VertexPoolItem get() { public static synchronized VertexPoolItem get() {
if (pool == null && count > 0) { if (pool == null && count > 0) {

View File

@ -40,9 +40,6 @@ public class BuildingOverlay extends RenderOverlay {
super(mapView); super(mapView);
} }
private int mNumIndices = 0;
private int mNumVertices = 0;
private static int buildingProgram; private static int buildingProgram;
private static int hBuildingVertexPosition; private static int hBuildingVertexPosition;
private static int hBuildingLightPosition; private static int hBuildingLightPosition;
@ -55,8 +52,9 @@ public class BuildingOverlay extends RenderOverlay {
private int mIndicesBufferID; private int mIndicesBufferID;
private int mVertexBufferID; private int mVertexBufferID;
private int mNumIndices = 0;
private int mNumVertices = 0;
private VertexPoolItem mVertices, mCurVertices; private VertexPoolItem mVertices, mCurVertices;
private VertexPoolItem mIndices[], mCurIndices[]; private VertexPoolItem mIndices[], mCurIndices[];
private int mIndiceCnt[] = { 0, 0, 0 }; private int mIndiceCnt[] = { 0, 0, 0 };

View File

@ -0,0 +1,328 @@
/*
* Copyright 2012 OpenScienceMap
*
* 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.overlays;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.ShortBuffer;
import org.oscim.core.MapPosition;
import org.oscim.renderer.GLRenderer;
import org.oscim.renderer.MapTile;
import org.oscim.renderer.TileManager;
import org.oscim.renderer.TileSet;
import org.oscim.renderer.layer.ExtrusionLayer;
import org.oscim.utils.GlUtils;
import org.oscim.view.MapView;
import android.opengl.GLES20;
import android.opengl.Matrix;
import android.util.Log;
/**
* @author Hannes Janetzek
*/
public class BuildingOverlay2 extends RenderOverlay {
private final static String TAG = BuildingOverlay2.class.getName();
public BuildingOverlay2(MapView mapView) {
super(mapView);
}
private static int buildingProgram;
private static int hBuildingVertexPosition;
private static int hBuildingLightPosition;
private static int hBuildingMatrix;
private static int hBuildingColor;
private static int hBuildingMode;
private boolean initialized = false;
private int BUFFERSIZE = 65536 * 2;
private TileSet mTileSet;
private ShortBuffer mShortBuffer;
@Override
public synchronized void update(MapPosition curPos, boolean positionChanged,
boolean tilesChanged) {
mMapView.getMapViewPosition().getMapPosition(mMapPosition, null);
if (!initialized) {
initialized = true;
// Set up the program for rendering buildings
buildingProgram = GlUtils.createProgram(buildingVertexShader,
buildingFragmentShader);
if (buildingProgram == 0) {
Log.e("blah", "Could not create building program.");
return;
}
hBuildingMatrix = GLES20.glGetUniformLocation(buildingProgram, "u_mvp");
hBuildingColor = GLES20.glGetUniformLocation(buildingProgram, "u_color");
hBuildingMode = GLES20.glGetUniformLocation(buildingProgram, "u_mode");
hBuildingVertexPosition = GLES20.glGetAttribLocation(buildingProgram, "a_position");
hBuildingLightPosition = GLES20.glGetAttribLocation(buildingProgram, "a_light");
ByteBuffer buf = ByteBuffer.allocateDirect(BUFFERSIZE)
.order(ByteOrder.nativeOrder());
mShortBuffer = buf.asShortBuffer();
}
int ready = 0;
//if (curPos.zoomLevel < 17)
mTileSet = TileManager.getActiveTiles(mTileSet);
MapTile[] tiles = mTileSet.tiles;
for (int i = 0; i < mTileSet.cnt; i++) {
if (!tiles[i].isVisible || tiles[i].layers == null
|| tiles[i].layers.extrusionLayers == null)
continue;
ExtrusionLayer el = (ExtrusionLayer) tiles[i].layers.extrusionLayers;
if (el.ready && !el.compiled) {
el.compile(mShortBuffer);
GlUtils.checkGlError("...");
}
if (el.compiled)
ready++;
}
isReady = ready > 0;
}
// r: 0.815686275, 0.91372549
// g: 0.901960784
// b: 0.890196078
// sligthly differ adjacent faces to imrpove contrast
float mColor[] = { 0.71872549f, 0.701960784f, 0.690196078f, 0.7f };
float mColor2[] = { 0.71372549f, 0.701960784f, 0.695196078f, 0.7f };
float mRoofColor[] = { 0.81f, 0.80f, 0.79f, 0.7f };
boolean debug = false;
@Override
public synchronized void render(MapPosition pos, float[] mv, float[] proj) {
boolean first = true;
if (debug) {
MapTile[] tiles = mTileSet.tiles;
for (int i = 0; i < mTileSet.cnt; i++) {
if (!tiles[i].isVisible || tiles[i].layers == null
|| tiles[i].layers.extrusionLayers == null)
continue;
ExtrusionLayer el = (ExtrusionLayer) tiles[i].layers.extrusionLayers;
if (!el.compiled)
continue;
if (first) {
GLES20.glUseProgram(buildingProgram);
GLRenderer.enableVertexArrays(hBuildingVertexPosition, hBuildingLightPosition);
GLES20.glUniform1i(hBuildingMode, 0);
GLES20.glUniform4f(hBuildingColor, 0.6f, 0.6f, 0.6f, 0.8f);
first = false;
}
setMatrix(pos, mv, proj, tiles[i], 1);
GLES20.glUniformMatrix4fv(hBuildingMatrix, 1, false, mv, 0);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, el.mIndicesBufferID);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, el.mVertexBufferID);
GLES20.glVertexAttribPointer(hBuildingVertexPosition, 3,
GLES20.GL_SHORT, false, 8, 0);
GLES20.glVertexAttribPointer(hBuildingLightPosition, 2,
GLES20.GL_UNSIGNED_BYTE, false, 8, 6);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, el.mNumIndices,
GLES20.GL_UNSIGNED_SHORT, 0);
}
return;
}
int drawCount = 20;
// draw to depth buffer
MapTile[] tiles = mTileSet.tiles;
for (int i = 0; i < mTileSet.cnt; i++) {
if (!tiles[i].isVisible || tiles[i].layers == null
|| tiles[i].layers.extrusionLayers == null)
continue;
ExtrusionLayer el = (ExtrusionLayer) tiles[i].layers.extrusionLayers;
if (!el.compiled)
continue;
if (first) {
GLES20.glUseProgram(buildingProgram);
GLRenderer.enableVertexArrays(hBuildingVertexPosition, -1);
GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT);
GLES20.glEnable(GLES20.GL_DEPTH_TEST);
GLES20.glEnable(GLES20.GL_CULL_FACE);
GLES20.glEnable(GLES20.GL_POLYGON_OFFSET_FILL);
//GLES20.glCullFace(GLES20.GL_CW);
GLES20.glDepthMask(true);
GLES20.glDepthFunc(GLES20.GL_LESS);
GLES20.glUniform1i(hBuildingMode, 0);
GLES20.glColorMask(false, false, false, false);
first = false;
}
GLES20.glPolygonOffset(0, drawCount--);
// seems there are not infinite offset units possible
// this should suffice for at least two rows, i.e.
// having not two neighbours with the same depth
if (drawCount == 0)
drawCount = 20;
setMatrix(pos, mv, proj, tiles[i], 1);
GLES20.glUniformMatrix4fv(hBuildingMatrix, 1, false, mv, 0);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, el.mIndicesBufferID);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, el.mVertexBufferID);
GLES20.glVertexAttribPointer(hBuildingVertexPosition, 3,
GLES20.GL_SHORT, false, 8, 0);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, el.mNumIndices,
GLES20.GL_UNSIGNED_SHORT, 0);
}
if (first)
return;
// enable color buffer, use depth mask
GLRenderer.enableVertexArrays(hBuildingVertexPosition, hBuildingLightPosition);
GLES20.glColorMask(true, true, true, true);
GLES20.glDepthMask(false);
GLES20.glDepthFunc(GLES20.GL_EQUAL);
drawCount = 20;
for (int i = 0; i < mTileSet.cnt; i++) {
if (!tiles[i].isVisible || tiles[i].layers == null
|| tiles[i].layers.extrusionLayers == null)
continue;
ExtrusionLayer el = (ExtrusionLayer) tiles[i].layers.extrusionLayers;
if (!el.compiled)
continue;
GLES20.glPolygonOffset(0, drawCount--);
if (drawCount == 0)
drawCount = 20;
setMatrix(pos, mv, proj, tiles[i], 1);
GLES20.glUniformMatrix4fv(hBuildingMatrix, 1, false, mv, 0);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, el.mIndicesBufferID);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, el.mVertexBufferID);
GLES20.glVertexAttribPointer(hBuildingVertexPosition, 3,
GLES20.GL_SHORT, false, 8, 0);
GLES20.glVertexAttribPointer(hBuildingLightPosition, 2,
GLES20.GL_UNSIGNED_BYTE, false, 8, 6);
// draw roof
GLES20.glUniform1i(hBuildingMode, 0);
//GLES20.glUniform4f(hBuildingColor, 0.81f, 0.8f, 0.8f, 0.9f);
GLES20.glUniform4fv(hBuildingColor, 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.glUniform4f(hBuildingColor, 0.8f, 0.8f, 0.8f, 1.0f);
//GLES20.glUniform4f(hBuildingColor, 0.9f, 0.905f, 0.9f, 1.0f);
GLES20.glUniform4fv(hBuildingColor, 1, mColor, 0);
GLES20.glUniform1i(hBuildingMode, 1);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, el.mIndiceCnt[0],
GLES20.GL_UNSIGNED_SHORT, 0);
// draw sides 2
//GLES20.glUniform4f(hBuildingColor, 0.9f, 0.9f, 0.905f, 1.0f);
GLES20.glUniform4fv(hBuildingColor, 1, mColor2, 0);
GLES20.glUniform1i(hBuildingMode, 2);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, el.mIndiceCnt[1],
GLES20.GL_UNSIGNED_SHORT, el.mIndiceCnt[0] * 2);
GlUtils.checkGlError("...");
}
if (!first) {
GLES20.glDisable(GLES20.GL_CULL_FACE);
GLES20.glDisable(GLES20.GL_DEPTH_TEST);
GLES20.glDisable(GLES20.GL_POLYGON_OFFSET_FILL);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
}
}
private static void setMatrix(MapPosition mapPosition, float[] matrix, float[] proj,
MapTile tile, float div) {
float x = (float) (tile.pixelX - mapPosition.x * div);
float y = (float) (tile.pixelY - mapPosition.y * div);
float scale = mapPosition.scale / div;
Matrix.setIdentityM(matrix, 0);
// translate relative to map center
matrix[12] = x * scale;
matrix[13] = y * scale;
// scale to tile to world coordinates
scale /= GLRenderer.COORD_MULTIPLIER;
matrix[0] = scale;
matrix[5] = scale;
matrix[10] = scale / 1000f;
Matrix.multiplyMM(matrix, 0, mapPosition.viewMatrix, 0, matrix, 0);
Matrix.multiplyMM(matrix, 0, proj, 0, matrix, 0);
}
final static String buildingVertexShader = ""
+ "precision mediump float;"
+ "uniform mat4 u_mvp;"
+ "uniform vec4 u_color;"
+ "uniform int u_mode;"
+ "uniform float u_scale;"
+ "attribute vec4 a_position;"
+ "attribute vec2 a_light;"
+ "varying vec4 color;"
+ "const float ff = 255.0;"
+ "void main() {"
+ " gl_Position = u_mvp * a_position;"
+ " if (u_mode == 0)"
// roof / depth pass
+ " color = u_color;"
+ " else if (u_mode == 1)"
// sides 1 - use 0xff00
+ " color = vec4(u_color.rgb * (a_light.y / ff), 0.8);"
+ " else"
// sides 2 - use 0x00ff
+ " color = vec4(u_color.rgb * (a_light.x / ff), 0.8);"
+ "}";
final static String buildingFragmentShader = ""
+ "precision lowp float;"
+ "varying vec4 color;"
+ "void main() {"
+ " gl_FragColor = color;"
+ "}";
}

View File

@ -116,9 +116,7 @@ public abstract class RenderOverlay {
} }
for (Layer l = layers.textureLayers; l != null;) { for (Layer l = layers.textureLayers; l != null;) {
l = TextureRenderer.draw(l, (mMapPosition.scale / pos.scale) * div, proj, mv);
l = TextureRenderer.draw(l, (mMapPosition.scale / pos.scale) * div, proj, mv,
layers.texOffset);
} }
} }

View File

@ -179,6 +179,10 @@
<line stroke="#9aabae" width="1.0" fixed="true" cap="butt"/> <line stroke="#9aabae" width="1.0" fixed="true" cap="butt"/>
</rule> </rule>
<rule e="way" k="*" v="hospital" zoom-min="14">
<area fill="#f0f0d8" />
</rule>
<rule e="way" k="*" v="parking" zoom-min="14"> <rule e="way" k="*" v="parking" zoom-min="14">
<area fill="#f4f4f4" stroke="#d4d4d4" stroke-width="0.2" /> <area fill="#f4f4f4" stroke="#d4d4d4" stroke-width="0.2" />
</rule> </rule>
@ -472,7 +476,7 @@
<!-- building --> <!-- building -->
<rule e="way" k="building" v="*"> <rule e="way" k="building" v="*">
<rule e="way" k="*" v="*" zoom-min="15"> <rule e="way" k="*" v="*" zoom-min="15" zoom-max="16">
<use-area name="building" fade="15"/> <use-area name="building" fade="15"/>
<use-line name="building" fade="15"/> <use-line name="building" fade="15"/>
<!-- <line stroke="#c9c3c1" width="1.0" fixed="true" cap="butt" fade="15"/> <!-- <line stroke="#c9c3c1" width="1.0" fixed="true" cap="butt" fade="15"/>
@ -926,6 +930,11 @@
<rule e="way" k="debug" v="box"> <rule e="way" k="debug" v="box">
<line stroke="#000000" width="1.5" fixed="true" cap="butt" /> <line stroke="#000000" width="1.5" fixed="true" cap="butt" />
</rule> </rule>
<!-- HACK!!! render building models last -->
<rule e="way" k="building" v="*" zoom-min="17">
<use-area name="building" fade="15"/>
</rule>
</rule> </rule>
<rule e="node" k="*" v="*"> <rule e="node" k="*" v="*">

View File

@ -45,7 +45,7 @@ import org.oscim.overlay.OverlayManager;
import org.oscim.renderer.GLRenderer; import org.oscim.renderer.GLRenderer;
import org.oscim.renderer.GLView; import org.oscim.renderer.GLView;
import org.oscim.renderer.TileManager; import org.oscim.renderer.TileManager;
import org.oscim.renderer.overlays.BuildingOverlay; import org.oscim.renderer.overlays.BuildingOverlay2;
import org.oscim.theme.ExternalRenderTheme; import org.oscim.theme.ExternalRenderTheme;
import org.oscim.theme.InternalRenderTheme; import org.oscim.theme.InternalRenderTheme;
import org.oscim.theme.RenderTheme; import org.oscim.theme.RenderTheme;
@ -184,9 +184,9 @@ public class MapView extends RelativeLayout {
mMapZoomControls.setShowMapZoomControls(true); mMapZoomControls.setShowMapZoomControls(true);
enableRotation = true; enableRotation = true;
mOverlayManager.add(new LabelingOverlay(this));
//mOverlayManager.add(new GenericOverlay(this, new GridOverlay(this))); //mOverlayManager.add(new GenericOverlay(this, new GridOverlay(this)));
mOverlayManager.add(new GenericOverlay(this, new BuildingOverlay(this))); mOverlayManager.add(new GenericOverlay(this, new BuildingOverlay2(this)));
mOverlayManager.add(new LabelingOverlay(this));
// mOverlayManager.add(new GenericOverlay(this, new TestOverlay(this))); // mOverlayManager.add(new GenericOverlay(this, new TestOverlay(this)));

View File

@ -0,0 +1,58 @@
package org.quake.triangle;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
public class TriangleJNI {
public TriangleJNI() {
}
// private static boolean initialized = false;
//
// private static ShortBuffer sBuf;
// private static FloatBuffer fBuf;
//
// public static synchronized int triangulate(float[] points, int pos, int len, short[] indices) {
//
// int numRings = 1;
//
// if (!initialized) {
// fBuf = ByteBuffer.allocateDirect(360 * 4).order(ByteOrder.nativeOrder())
// .asFloatBuffer();
// sBuf = ByteBuffer.allocateDirect(360 * 2).order(ByteOrder.nativeOrder())
// .asShortBuffer();
// initialized = true;
// }
//
// fBuf.clear();
// fBuf.put(points, pos, len);
//
// sBuf.clear();
// sBuf.put((short) (len >> 1)); // all points
// sBuf.put((short) (len >> 1)); // outer ring
// //sBuf.put((short)4); // inner ring
//
// int numTris = TriangleJNI.triangulate(fBuf, numRings, sBuf);
// if (numTris > 100)
// Log.d("triangle", "Triangles: " + numTris);
//
// sBuf.limit(numTris * 3);
// sBuf.position(0);
//
// // for(int i = 0; i < numTris * 3; i+=3){
// // Log.d("triangle", ">>" + sBuf.get()+ " "+ sBuf.get() + " "+ sBuf.get());
// // }
//
// sBuf.get(indices, 0, numTris * 3);
//
// return numTris * 3;
// }
public static native int triangulate(FloatBuffer points, int length, ShortBuffer result,
int ioffset);
static {
System.loadLibrary("triangle-jni");
}
}