diff --git a/src/org/oscim/app/TileMap.java b/src/org/oscim/app/TileMap.java
index 48dba1f6..0d860a7c 100755
--- a/src/org/oscim/app/TileMap.java
+++ b/src/org/oscim/app/TileMap.java
@@ -45,13 +45,15 @@ import android.widget.TextView;
import android.widget.Toast;
/**
- * A map application which uses the features from the mapsforge map library. The map can be centered to the current
- * location. A simple file browser for selecting the map file is also included. Some preferences can be adjusted via the
- * {@link EditPreferences} activity.
+ * A map application which uses the features from the mapsforge map library. The
+ * map can be centered to the current location. A simple file browser for
+ * selecting the map file is also included. Some preferences can be adjusted via
+ * the {@link EditPreferences} activity.
*/
public class TileMap extends MapActivity {
// implements ActionBar.OnNavigationListener {
- // private static final String BUNDLE_CENTER_AT_FIRST_FIX = "centerAtFirstFix";
+ // private static final String BUNDLE_CENTER_AT_FIRST_FIX =
+ // "centerAtFirstFix";
private static final String BUNDLE_SHOW_MY_LOCATION = "showMyLocation";
private static final String BUNDLE_SNAP_TO_LOCATION = "snapToLocation";
private static final int DIALOG_ENTER_COORDINATES = 0;
@@ -408,7 +410,8 @@ public class TileMap extends MapActivity {
editText.setText(Double.toString(mapCenter.getLongitude()));
SeekBar zoomlevel = (SeekBar) dialog.findViewById(R.id.zoomLevel);
- zoomlevel.setMax(20); // FIXME mMapView.getMapGenerator().getZoomLevelMax());
+ zoomlevel.setMax(20); // FIXME
+ // mMapView.getMapGenerator().getZoomLevelMax());
zoomlevel.setProgress(mMapView.getMapPosition().getZoomLevel());
final TextView textView = (TextView) dialog.findViewById(R.id.zoomlevelValue);
@@ -417,34 +420,42 @@ public class TileMap extends MapActivity {
// } else if (id == DIALOG_INFO_MAP_FILE) {
// MapInfo mapInfo = mMapView.getMapDatabase().getMapInfo();
//
- // TextView textView = (TextView) dialog.findViewById(R.id.infoMapFileViewName);
+ // TextView textView = (TextView)
+ // dialog.findViewById(R.id.infoMapFileViewName);
// textView.setText(mMapView.getMapFile());
//
- // textView = (TextView) dialog.findViewById(R.id.infoMapFileViewSize);
+ // textView = (TextView)
+ // dialog.findViewById(R.id.infoMapFileViewSize);
// textView.setText(FileUtils.formatFileSize(mapInfo.fileSize,
// getResources()));
//
- // textView = (TextView) dialog.findViewById(R.id.infoMapFileViewVersion);
+ // textView = (TextView)
+ // dialog.findViewById(R.id.infoMapFileViewVersion);
// textView.setText(String.valueOf(mapInfo.fileVersion));
//
- // // textView = (TextView) dialog.findViewById(R.id.infoMapFileViewDebug);
+ // // textView = (TextView)
+ // dialog.findViewById(R.id.infoMapFileViewDebug);
// // if (mapFileInfo.debugFile) {
// // textView.setText(R.string.info_map_file_debug_yes);
// // } else {
// // textView.setText(R.string.info_map_file_debug_no);
// // }
//
- // textView = (TextView) dialog.findViewById(R.id.infoMapFileViewDate);
+ // textView = (TextView)
+ // dialog.findViewById(R.id.infoMapFileViewDate);
// Date date = new Date(mapInfo.mapDate);
// textView.setText(DateFormat.getDateTimeInstance().format(date));
//
- // textView = (TextView) dialog.findViewById(R.id.infoMapFileViewArea);
+ // textView = (TextView)
+ // dialog.findViewById(R.id.infoMapFileViewArea);
// BoundingBox boundingBox = mapInfo.boundingBox;
// textView.setText(boundingBox.getMinLatitude() + ", "
// + boundingBox.getMinLongitude() + " - \n"
- // + boundingBox.getMaxLatitude() + ", " + boundingBox.getMaxLongitude());
+ // + boundingBox.getMaxLatitude() + ", " +
+ // boundingBox.getMaxLongitude());
//
- // textView = (TextView) dialog.findViewById(R.id.infoMapFileViewStartPosition);
+ // textView = (TextView)
+ // dialog.findViewById(R.id.infoMapFileViewStartPosition);
// GeoPoint startPosition = mapInfo.startPosition;
// if (startPosition == null) {
// textView.setText(null);
@@ -453,7 +464,8 @@ public class TileMap extends MapActivity {
// + startPosition.getLongitude());
// }
//
- // textView = (TextView) dialog.findViewById(R.id.infoMapFileViewStartZoomLevel);
+ // textView = (TextView)
+ // dialog.findViewById(R.id.infoMapFileViewStartZoomLevel);
// Byte startZoomLevel = mapInfo.startZoomLevel;
// if (startZoomLevel == null) {
// textView.setText(null);
@@ -465,10 +477,12 @@ public class TileMap extends MapActivity {
// .findViewById(R.id.infoMapFileViewLanguagePreference);
// textView.setText(mapInfo.languagePreference);
//
- // textView = (TextView) dialog.findViewById(R.id.infoMapFileViewComment);
+ // textView = (TextView)
+ // dialog.findViewById(R.id.infoMapFileViewComment);
// textView.setText(mapInfo.comment);
//
- // textView = (TextView) dialog.findViewById(R.id.infoMapFileViewCreatedBy);
+ // textView = (TextView)
+ // dialog.findViewById(R.id.infoMapFileViewCreatedBy);
// textView.setText(mapInfo.createdBy);
} else {
super.onPrepareDialog(id, dialog);
@@ -483,13 +497,17 @@ public class TileMap extends MapActivity {
.getDefaultSharedPreferences(this);
// MapScaleBar mapScaleBar = mapView.getMapScaleBar();
- // mapScaleBar.setShowMapScaleBar(preferences.getBoolean("showScaleBar", false));
- // String scaleBarUnitDefault = getString(R.string.preferences_scale_bar_unit_default);
- // String scaleBarUnit = preferences.getString("scaleBarUnit", scaleBarUnitDefault);
+ // mapScaleBar.setShowMapScaleBar(preferences.getBoolean("showScaleBar",
+ // false));
+ // String scaleBarUnitDefault =
+ // getString(R.string.preferences_scale_bar_unit_default);
+ // String scaleBarUnit = preferences.getString("scaleBarUnit",
+ // scaleBarUnitDefault);
// mapScaleBar.setImperialUnits(scaleBarUnit.equals("imperial"));
// if (preferences.contains("mapGenerator")) {
- // String name = preferences.getString("mapGenerator", MapGeneratorInternal.SW_RENDERER.name());
+ // String name = preferences.getString("mapGenerator",
+ // MapGeneratorInternal.SW_RENDERER.name());
// MapGeneratorInternal mapGeneratorInternalNew;
// try {
// mapGeneratorInternalNew = MapGeneratorInternal.valueOf(name);
@@ -498,7 +516,8 @@ public class TileMap extends MapActivity {
// }
//
// if (mapGeneratorInternalNew != mapGeneratorInternal) {
- // TileGenerator mapGenerator = MapGeneratorFactory.createMapGenerator(mapGeneratorInternalNew);
+ // TileGenerator mapGenerator =
+ // MapGeneratorFactory.createMapGenerator(mapGeneratorInternalNew);
// mapView.setMapGenerator(mapGenerator);
// mapGeneratorInternal = mapGeneratorInternalNew;
// }
@@ -525,7 +544,8 @@ public class TileMap extends MapActivity {
}
// try {
- // String textScaleDefault = getString(R.string.preferences_text_scale_default);
+ // String textScaleDefault =
+ // getString(R.string.preferences_text_scale_default);
// mMapView.setTextScale(Float.parseFloat(preferences.getString("textScale",
// textScaleDefault)));
// } catch (NumberFormatException e) {
@@ -596,7 +616,8 @@ public class TileMap extends MapActivity {
}
/**
- * Uses the UI thread to display the given text message as toast notification.
+ * Uses the UI thread to display the given text message as toast
+ * notification.
*
* @param text
* the text message to display
diff --git a/src/org/oscim/database/oscimap/MapDatabase.java b/src/org/oscim/database/oscimap/MapDatabase.java
index c0e90b38..5693cf28 100644
--- a/src/org/oscim/database/oscimap/MapDatabase.java
+++ b/src/org/oscim/database/oscimap/MapDatabase.java
@@ -65,8 +65,8 @@ public class MapDatabase implements IMapDatabase {
private static final String CACHE_FILE = "%d-%d-%d.tile";
private static final String SERVER_ADDR = "city.informatik.uni-bremen.de";
- private static final String URL = "/osci/map-live/";
- // private static final String URL = "/osci/oscim/";
+ // private static final String URL = "/osci/map-live/";
+ private static final String URL = "/osci/oscim/";
private final static float REF_TILE_SIZE = 4096.0f;
diff --git a/src/org/oscim/database/pbmap/MapDatabase.java b/src/org/oscim/database/pbmap/MapDatabase.java
index 1426b481..cacd1dad 100644
--- a/src/org/oscim/database/pbmap/MapDatabase.java
+++ b/src/org/oscim/database/pbmap/MapDatabase.java
@@ -91,10 +91,13 @@ public class MapDatabase implements IMapDatabase {
private static final String CACHE_FILE = "%d-%d-%d.tile";
private static final String SERVER_ADDR = "city.informatik.uni-bremen.de";
- // private static final String URL = "http://city.informatik.uni-bremen.de:8020/test/%d/%d/%d.osmtile";
+ // private static final String URL =
+ // "http://city.informatik.uni-bremen.de:8020/test/%d/%d/%d.osmtile";
private static final String URL = "http://city.informatik.uni-bremen.de/osmstache/test/%d/%d/%d.osmtile";
- // private static final String URL = "http://city.informatik.uni-bremen.de/tiles/tiles.py///test/%d/%d/%d.osmtile";
- // private static final String URL = "http://city.informatik.uni-bremen.de/osmstache/gis2/%d/%d/%d.osmtile";
+ // private static final String URL =
+ // "http://city.informatik.uni-bremen.de/tiles/tiles.py///test/%d/%d/%d.osmtile";
+ // private static final String URL =
+ // "http://city.informatik.uni-bremen.de/osmstache/gis2/%d/%d/%d.osmtile";
private final static float REF_TILE_SIZE = 4096.0f;
@@ -360,7 +363,7 @@ public class MapDatabase implements IMapDatabase {
return file;
}
- // /////////////// hand sewed tile protocol buffers decoder ///////////////////
+ // /////////////// hand sewed tile protocol buffers decoder ////////////////
private static final int BUFFER_SIZE = 65536;
private final byte[] mReadBuffer = new byte[BUFFER_SIZE];
@@ -604,7 +607,7 @@ public class MapDatabase implements IMapDatabase {
lastY = lat + lastY;
mMapGenerator.renderPointOfInterest(layer,
- tags, lastY / scale, lastX / scale);
+ tags, Tile.TILE_SIZE - lastY / scale, lastX / scale);
cnt += 2;
}
return cnt;
@@ -800,7 +803,7 @@ public class MapDatabase implements IMapDatabase {
} else {
y = ((result >>> 1) ^ -(result & 1));
lastY = lastY + y;
- coords[cnt++] = lastY / scale;
+ coords[cnt++] = Tile.TILE_SIZE - lastY / scale;
even = true;
}
}
@@ -940,7 +943,8 @@ public class MapDatabase implements IMapDatabase {
return result;
}
- // ///////////////////////// Lightweight HttpClient ///////////////////////////////////////
+ // ///////////////////////// Lightweight HttpClient
+ // ///////////////////////////////////////
// would have written simple tcp server/client for this...
private int mMaxReq = 0;
@@ -1080,7 +1084,8 @@ public class MapDatabase implements IMapDatabase {
len += pos;
// this does the same but with a few more allocations:
- // byte[] request = String.format(REQUEST, Integer.valueOf(tile.zoomLevel),
+ // byte[] request = String.format(REQUEST,
+ // Integer.valueOf(tile.zoomLevel),
// Integer.valueOf(tile.tileX), Integer.valueOf(tile.tileY)).getBytes();
try {
@@ -1138,7 +1143,7 @@ public class MapDatabase implements IMapDatabase {
}
- // //////////////////////////// Tile cache ////////////////////////////////////
+ // //////////////////////////// Tile cache ///////////////////////////////
private boolean cacheRead(Tile tile, File f) {
if (f.exists() && f.length() > 0) {
@@ -1212,7 +1217,10 @@ public class MapDatabase implements IMapDatabase {
mCacheFile = null;
}
- /* All code below is taken from or based on Google's Protocol Buffers implementation: */
+ /*
+ * All code below is taken from or based on Google's Protocol Buffers
+ * implementation:
+ */
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
diff --git a/src/org/oscim/database/test/MapDatabase.java b/src/org/oscim/database/test/MapDatabase.java
index 0a1211fb..fe4e0d3c 100644
--- a/src/org/oscim/database/test/MapDatabase.java
+++ b/src/org/oscim/database/test/MapDatabase.java
@@ -38,6 +38,8 @@ public class MapDatabase implements IMapDatabase {
// private Tag[] mTags = { new Tag("boundary", "administrative"), new
// Tag("admin_level", "2") };
private Tag[] mTags = { new Tag("natural", "water") };
+ private Tag[] mTagsWay = { new Tag("highway", "primary"), new Tag("name", "Highway Rd") };
+
private Tag[] mNameTags;
private final MapInfo mMapInfo =
@@ -50,10 +52,12 @@ public class MapDatabase implements IMapDatabase {
@Override
public QueryResult executeQuery(JobTile tile, IMapDatabaseCallback mapDatabaseCallback) {
- float lat1 = -0.5f;
- float lon1 = -0.5f;
- float lat2 = Tile.TILE_SIZE + 0.5f;
- float lon2 = Tile.TILE_SIZE + 0.5f;
+ int size = Tile.TILE_SIZE;
+
+ float lat1 = -1;
+ float lon1 = -1;
+ float lat2 = size + 1;
+ float lon2 = size + 1;
mCoords[0] = lon1;
mCoords[1] = lat1;
@@ -70,13 +74,13 @@ public class MapDatabase implements IMapDatabase {
mCoords[8] = lon1;
mCoords[9] = lat1;
- mIndex[0] = 8;
- mIndex[1] = 2;
+ mIndex[0] = 10;
+ mIndex[1] = 0;
lon1 = 40;
- lon2 = Tile.TILE_SIZE - 40;
+ lon2 = size - 40;
lat1 = 40;
- lat2 = Tile.TILE_SIZE - 40;
+ lat2 = size - 40;
mCoords[10] = lon1;
mCoords[11] = lat1;
@@ -93,19 +97,84 @@ public class MapDatabase implements IMapDatabase {
mCoords[18] = lon1;
mCoords[19] = lat1;
- mIndex[2] = 8;
- mIndex[3] = 2;
+ mIndex[2] = 10;
+ mIndex[3] = 0;
mapDatabaseCallback.renderWay((byte) 0, mTags, mCoords, mIndex, true);
- lon1 = Tile.TILE_SIZE / 2;
- lat1 = Tile.TILE_SIZE / 2;
+ mIndex[0] = 4;
+ mIndex[1] = -1;
- mNameTags = new Tag[2];
- mNameTags[0] = new Tag("place", "city");
- mNameTags[1] = new Tag("name", tile.toString());
- mapDatabaseCallback.renderPointOfInterest((byte) 0, mNameTags, (int) lat1,
- (int) lon1);
+ // middle horizontal
+ mCoords[0] = 0;
+ mCoords[1] = size / 2;
+ mCoords[2] = size;
+ mCoords[3] = size / 2;
+ Tag[] tags = new Tag[2];
+ tags[0] = mTagsWay[0];
+ tags[1] = mTagsWay[1];
+ mapDatabaseCallback.renderWay((byte) 0, tags, mCoords, mIndex, false);
+
+ // center up
+ mCoords[0] = size / 2;
+ mCoords[1] = -size / 2;
+ mCoords[2] = size / 2;
+ mCoords[3] = size / 2;
+ tags = new Tag[2];
+ tags[0] = mTagsWay[0];
+ tags[1] = mTagsWay[1];
+ mapDatabaseCallback.renderWay((byte) 0, tags, mCoords, mIndex,
+ false);
+
+ // center down
+ mCoords[0] = size / 2;
+ mCoords[1] = size / 2;
+ mCoords[2] = size / 2;
+ mCoords[3] = size / 2 + size;
+ tags = new Tag[2];
+ tags[0] = mTagsWay[0];
+ tags[1] = mTagsWay[1];
+ mapDatabaseCallback.renderWay((byte) 0, tags, mCoords, mIndex, false);
+
+ // left-top to center
+ mCoords[0] = size / 2;
+ mCoords[1] = size / 2;
+ mCoords[2] = 10;
+ mCoords[3] = 10;
+ tags = new Tag[2];
+ tags[0] = mTagsWay[0];
+ tags[1] = mTagsWay[1];
+ mapDatabaseCallback.renderWay((byte) 1, tags, mCoords, mIndex, false);
+
+ // middle horizontal
+ mCoords[0] = 0;
+ mCoords[1] = 10;
+ mCoords[2] = size;
+ mCoords[3] = 10;
+ tags = new Tag[2];
+ tags[0] = mTagsWay[0];
+ tags[1] = mTagsWay[1];
+ mapDatabaseCallback.renderWay((byte) 1, tags, mCoords, mIndex, false);
+
+ // middle horizontal
+ mCoords[0] = 10;
+ mCoords[1] = 0;
+ mCoords[2] = 10;
+ mCoords[3] = size;
+ tags = new Tag[2];
+ tags[0] = mTagsWay[0];
+ tags[1] = mTagsWay[1];
+ mapDatabaseCallback.renderWay((byte) 1, tags, mCoords, mIndex, false);
+
+ // lon1 = size / 2;
+ // lat1 = size / 2;
+
+ // mNameTags = new Tag[2];
+ // mNameTags[0] = new Tag("place", "city");
+ // mNameTags[1] = new Tag("name", tile.toString());
+ // mapDatabaseCallback.renderPointOfInterest((byte) 0, mNameTags, (int)
+ // lat1,
+ // (int) lon1);
return QueryResult.SUCCESS;
}
diff --git a/src/org/oscim/utils/GLSurfaceView.java b/src/org/oscim/utils/GLSurfaceView.java
deleted file mode 100644
index 5601345e..00000000
--- a/src/org/oscim/utils/GLSurfaceView.java
+++ /dev/null
@@ -1,1887 +0,0 @@
-package org.oscim.utils;
-
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import java.io.Writer;
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-
-import javax.microedition.khronos.egl.EGL10;
-import javax.microedition.khronos.egl.EGL11;
-import javax.microedition.khronos.egl.EGLConfig;
-import javax.microedition.khronos.egl.EGLContext;
-import javax.microedition.khronos.egl.EGLDisplay;
-import javax.microedition.khronos.egl.EGLSurface;
-import javax.microedition.khronos.opengles.GL;
-import javax.microedition.khronos.opengles.GL10;
-
-import android.content.Context;
-import android.opengl.GLDebugHelper;
-import android.opengl.GLSurfaceView.EGLConfigChooser;
-import android.opengl.GLSurfaceView.Renderer;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.SurfaceHolder;
-import android.view.SurfaceView;
-
-/**
- * An implementation of SurfaceView that uses the dedicated surface for
- * displaying OpenGL rendering.
- *
- * A GLSurfaceView provides the following features:
- *
- *
- * - Manages a surface, which is a special piece of memory that can be
- * composited into the Android view system.
- *
- Manages an EGL display, which enables OpenGL to render into a surface.
- *
- Accepts a user-provided Renderer object that does the actual rendering.
- *
- Renders on a dedicated thread to decouple rendering performance from the
- * UI thread.
- *
- Supports both on-demand and continuous rendering.
- *
- Optionally wraps, traces, and/or error-checks the renderer's OpenGL
- * calls.
- *
- *
- *
Developer Guides
- *
- * For more information about how to use OpenGL, read the OpenGL developer guide.
- *
- *
Using GLSurfaceView
- *
- * Typically you use GLSurfaceView by subclassing it and overriding one or more
- * of the View system input event methods. If your application does not need to
- * override event methods then GLSurfaceView can be used as-is. For the most
- * part GLSurfaceView behavior is customized by calling "set" methods rather
- * than by subclassing. For example, unlike a regular View, drawing is delegated
- * to a separate Renderer object which is registered with the GLSurfaceView
- * using the {@link #setRenderer(Renderer)} call.
- *
- *
Initializing GLSurfaceView
All you have to do to initialize a
- * GLSurfaceView is call {@link #setRenderer(Renderer)}. However, if desired,
- * you can modify the default behavior of GLSurfaceView by calling one or more
- * of these methods before calling setRenderer:
- *
- * - {@link #setDebugFlags(int)}
- *
- {@link #setEGLConfigChooser(boolean)}
- *
- {@link #setEGLConfigChooser(EGLConfigChooser)}
- *
- {@link #setEGLConfigChooser(int, int, int, int, int, int)}
- *
- {@link #setGLWrapper(GLWrapper)}
- *
- *
- *
Specifying the android.view.Surface
By default GLSurfaceView will
- * create a PixelFormat.RGB_565 format surface. If a translucent surface is
- * required, call getHolder().setFormat(PixelFormat.TRANSLUCENT). The exact
- * format of a TRANSLUCENT surface is device dependent, but it will be a
- * 32-bit-per-pixel surface with 8 bits per component.
- *
- *
Choosing an EGL Configuration
A given Android device may support
- * multiple EGLConfig rendering configurations. The available configurations may
- * differ in how may channels of data are present, as well as how many bits are
- * allocated to each channel. Therefore, the first thing GLSurfaceView has to do
- * when starting to render is choose what EGLConfig to use.
- *
- * By default GLSurfaceView chooses a EGLConfig that has an RGB_565 pixel
- * format, with at least a 16-bit depth buffer and no stencil.
- *
- * If you would prefer a different EGLConfig you can override the default
- * behavior by calling one of the setEGLConfigChooser methods.
- *
- *
Debug Behavior
You can optionally modify the behavior of
- * GLSurfaceView by calling one or more of the debugging methods
- * {@link #setDebugFlags(int)}, and {@link #setGLWrapper}. These methods may be
- * called before and/or after setRenderer, but typically they are called before
- * setRenderer so that they take effect immediately.
- *
- *
Setting a Renderer
Finally, you must call {@link #setRenderer} to
- * register a {@link Renderer}. The renderer is responsible for doing the actual
- * OpenGL rendering.
- *
- *
Rendering Mode
Once the renderer is set, you can control whether the
- * renderer draws continuously or on-demand by calling {@link #setRenderMode}.
- * The default is continuous rendering.
- *
- *
Activity Life-cycle
A GLSurfaceView must be notified when the
- * activity is paused and resumed. GLSurfaceView clients are required to call
- * {@link #onPause()} when the activity pauses and {@link #onResume()} when the
- * activity resumes. These calls allow GLSurfaceView to pause and resume the
- * rendering thread, and also allow GLSurfaceView to release and recreate the
- * OpenGL display.
- *
- *
Handling events
- *
- * To handle an event you will typically subclass GLSurfaceView and override the
- * appropriate method, just as you would with any other View. However, when
- * handling the event, you may need to communicate with the Renderer object
- * that's running in the rendering thread. You can do this using any standard
- * Java cross-thread communication mechanism. In addition, one relatively easy
- * way to communicate with your renderer is to call
- * {@link #queueEvent(Runnable)}. For example:
- *
- *
- * class MyGLSurfaceView extends GLSurfaceView {
- *
- * private MyRenderer mMyRenderer;
- *
- * public void start() {
- * mMyRenderer = ...;
- * setRenderer(mMyRenderer);
- * }
- *
- * public boolean onKeyDown(int keyCode, KeyEvent event) {
- * if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
- * queueEvent(new Runnable() {
- * // This method will be called on the rendering
- * // thread:
- * public void run() {
- * mMyRenderer.handleDpadCenter();
- * }
- * });
- * return true;
- * }
- * return super.onKeyDown(keyCode, event);
- * }
- * }
- *
- *
- *
- */
-public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
- private final static String TAG = "GLSurfaceView";
- private final static boolean LOG_ATTACH_DETACH = false;
- private final static boolean LOG_THREADS = true;
- private final static boolean LOG_PAUSE_RESUME = false;
- private final static boolean LOG_SURFACE = false;
- private final static boolean LOG_RENDERER = false;
- private final static boolean LOG_RENDERER_DRAW_FRAME = false;
- private final static boolean LOG_EGL = false;
- /**
- * The renderer only renders when the surface is created, or when
- * {@link #requestRender} is called.
- *
- * @see #getRenderMode()
- * @see #setRenderMode(int)
- * @see #requestRender()
- */
- public final static int RENDERMODE_WHEN_DIRTY = 0;
- /**
- * The renderer is called continuously to re-render the scene.
- *
- * @see #getRenderMode()
- * @see #setRenderMode(int)
- */
- public final static int RENDERMODE_CONTINUOUSLY = 1;
-
- /**
- * Check glError() after every GL call and throw an exception if glError
- * indicates that an error has occurred. This can be used to help track down
- * which OpenGL ES call is causing an error.
- *
- * @see #getDebugFlags
- * @see #setDebugFlags
- */
- public final static int DEBUG_CHECK_GL_ERROR = 1;
-
- /**
- * Log GL calls to the system log at "verbose" level with tag
- * "GLSurfaceView".
- *
- * @see #getDebugFlags
- * @see #setDebugFlags
- */
- public final static int DEBUG_LOG_GL_CALLS = 2;
-
- /**
- * Standard View constructor. In order to render something, you must call
- * {@link #setRenderer} to register a renderer.
- *
- * @param context
- * ...
- */
- public GLSurfaceView(Context context) {
- super(context);
- init();
- }
-
- /**
- * Standard View constructor. In order to render something, you must call
- * {@link #setRenderer} to register a renderer.
- *
- * @param context
- * ....
- * @param attrs
- * ...
- */
- public GLSurfaceView(Context context, AttributeSet attrs) {
- super(context, attrs);
- init();
- }
-
- @Override
- protected void finalize() throws Throwable {
- try {
- if (mGLThread != null) {
- // GLThread may still be running if this view was never
- // attached to a window.
- mGLThread.requestExitAndWait();
- }
- } finally {
- super.finalize();
- }
- }
-
- private void init() {
- // Install a SurfaceHolder.Callback so we get notified when the
- // underlying surface is created and destroyed
- SurfaceHolder holder = getHolder();
- holder.addCallback(this);
- // setFormat is done by SurfaceView in SDK 2.3 and newer. Uncomment
- // this statement if back-porting to 2.2 or older:
- // holder.setFormat(PixelFormat.RGB_565);
- //
- // setType is not needed for SDK 2.0 or newer. Uncomment this
- // statement if back-porting this code to older SDKs.
- // holder.setType(SurfaceHolder.SURFACE_TYPE_GPU);
- }
-
- /**
- * Set the glWrapper. If the glWrapper is not null, its
- * {@link GLWrapper#wrap(GL)} method is called whenever a surface is
- * created. A GLWrapper can be used to wrap the GL object that's passed to
- * the renderer. Wrapping a GL object enables examining and modifying the
- * behavior of the GL calls made by the renderer.
- *
- * Wrapping is typically used for debugging purposes.
- *
- * The default value is null.
- *
- * @param glWrapper
- * the new GLWrapper
- */
- public void setGLWrapper(GLWrapper glWrapper) {
- mGLWrapper = glWrapper;
- }
-
- /**
- * Set the debug flags to a new value. The value is constructed by
- * OR-together zero or more of the DEBUG_CHECK_* constants. The debug flags
- * take effect whenever a surface is created. The default value is zero.
- *
- * @param debugFlags
- * the new debug flags
- * @see #DEBUG_CHECK_GL_ERROR
- * @see #DEBUG_LOG_GL_CALLS
- */
- public void setDebugFlags(int debugFlags) {
- mDebugFlags = debugFlags;
- }
-
- /**
- * Get the current value of the debug flags.
- *
- * @return the current value of the debug flags.
- */
- public int getDebugFlags() {
- return mDebugFlags;
- }
-
- /**
- * Control whether the EGL context is preserved when the GLSurfaceView is
- * paused and resumed.
- *
- * If set to true, then the EGL context may be preserved when the
- * GLSurfaceView is paused. Whether the EGL context is actually preserved or
- * not depends upon whether the Android device that the program is running
- * on can support an arbitrary number of EGL contexts or not. Devices that
- * can only support a limited number of EGL contexts must release the EGL
- * context in order to allow multiple applications to share the GPU.
- *
- * If set to false, the EGL context will be released when the GLSurfaceView
- * is paused, and recreated when the GLSurfaceView is resumed.
- *
- * The default is false.
- *
- * @param preserveOnPause
- * preserve the EGL context when paused
- */
- public void setPreserveEGLContextOnPause(boolean preserveOnPause) {
- mPreserveEGLContextOnPause = preserveOnPause;
- }
-
- /**
- * @return true if the EGL context will be preserved when paused
- */
- public boolean getPreserveEGLContextOnPause() {
- return mPreserveEGLContextOnPause;
- }
-
- /**
- * Set the renderer associated with this view. Also starts the thread that
- * will call the renderer, which in turn causes the rendering to start.
- *
- * This method should be called once and only once in the life-cycle of a
- * GLSurfaceView.
- *
- * The following GLSurfaceView methods can only be called before
- * setRenderer is called:
- *
- * - {@link #setEGLConfigChooser(boolean)}
- *
- {@link #setEGLConfigChooser(EGLConfigChooser)}
- *
- {@link #setEGLConfigChooser(int, int, int, int, int, int)}
- *
- *
- * The following GLSurfaceView methods can only be called after
- * setRenderer is called:
- *
- * - {@link #getRenderMode()}
- *
- {@link #onPause()}
- *
- {@link #onResume()}
- *
- {@link #queueEvent(Runnable)}
- *
- {@link #requestRender()}
- *
- {@link #setRenderMode(int)}
- *
- *
- * @param renderer
- * the renderer to use to perform OpenGL drawing.
- */
- public void setRenderer(Renderer renderer) {
- checkRenderThreadState();
- if (mEGLConfigChooser == null) {
- mEGLConfigChooser = new SimpleEGLConfigChooser(true);
- }
- if (mEGLContextFactory == null) {
- mEGLContextFactory = new DefaultContextFactory();
- }
- if (mEGLWindowSurfaceFactory == null) {
- mEGLWindowSurfaceFactory = new DefaultWindowSurfaceFactory();
- }
- mRenderer = renderer;
- mGLThread = new GLThread(mThisWeakRef);
- mGLThread.start();
- }
-
- /**
- * Install a custom EGLContextFactory.
- *
- * If this method is called, it must be called before
- * {@link #setRenderer(Renderer)} is called.
- *
- * If this method is not called, then by default a context will be created
- * with no shared context and with a null attribute list.
- */
- public void setEGLContextFactory(EGLContextFactory factory) {
- checkRenderThreadState();
- mEGLContextFactory = factory;
- }
-
- /**
- * Install a custom EGLWindowSurfaceFactory.
- *
- * If this method is called, it must be called before
- * {@link #setRenderer(Renderer)} is called.
- *
- * If this method is not called, then by default a window surface will be
- * created with a null attribute list.
- */
- public void setEGLWindowSurfaceFactory(EGLWindowSurfaceFactory factory) {
- checkRenderThreadState();
- mEGLWindowSurfaceFactory = factory;
- }
-
- /**
- * Install a custom EGLConfigChooser.
- *
- * If this method is called, it must be called before
- * {@link #setRenderer(Renderer)} is called.
- *
- * If no setEGLConfigChooser method is called, then by default the view will
- * choose an EGLConfig that is compatible with the current
- * android.view.Surface, with a depth buffer depth of at least 16 bits.
- *
- * @param configChooser
- */
- public void setEGLConfigChooser(EGLConfigChooser configChooser) {
- checkRenderThreadState();
- mEGLConfigChooser = configChooser;
- }
-
- /**
- * Install a config chooser which will choose a config as close to 16-bit
- * RGB as possible, with or without an optional depth buffer as close to
- * 16-bits as possible.
- *
- * If this method is called, it must be called before
- * {@link #setRenderer(Renderer)} is called.
- *
- * If no setEGLConfigChooser method is called, then by default the view will
- * choose an RGB_565 surface with a depth buffer depth of at least 16 bits.
- *
- * @param needDepth
- */
- public void setEGLConfigChooser(boolean needDepth) {
- setEGLConfigChooser(new SimpleEGLConfigChooser(needDepth));
- }
-
- /**
- * Install a config chooser which will choose a config with at least the
- * specified depthSize and stencilSize, and exactly the specified redSize,
- * greenSize, blueSize and alphaSize.
- *
- * If this method is called, it must be called before
- * {@link #setRenderer(Renderer)} is called.
- *
- * If no setEGLConfigChooser method is called, then by default the view will
- * choose an RGB_565 surface with a depth buffer depth of at least 16 bits.
- */
- public void setEGLConfigChooser(int redSize, int greenSize, int blueSize,
- int alphaSize, int depthSize, int stencilSize) {
- setEGLConfigChooser(new ComponentSizeChooser(redSize, greenSize,
- blueSize, alphaSize, depthSize, stencilSize));
- }
-
- /**
- * Inform the default EGLContextFactory and default EGLConfigChooser which
- * EGLContext client version to pick.
- *
- * Use this method to create an OpenGL ES 2.0-compatible context. Example:
- *
- *
- * public MyView(Context context) {
- * super(context);
- * setEGLContextClientVersion(2); // Pick an OpenGL ES 2.0 context.
- * setRenderer(new MyRenderer());
- * }
- *
- *
- * Note: Activities which require OpenGL ES 2.0 should indicate this by
- * setting @lt;uses-feature android:glEsVersion="0x00020000" /> in the
- * activity's AndroidManifest.xml file.
- *
- * If this method is called, it must be called before
- * {@link #setRenderer(Renderer)} is called.
- *
- * This method only affects the behavior of the default EGLContexFactory and
- * the default EGLConfigChooser. If
- * {@link #setEGLContextFactory(EGLContextFactory)} has been called, then
- * the supplied EGLContextFactory is responsible for creating an OpenGL ES
- * 2.0-compatible context. If {@link #setEGLConfigChooser(EGLConfigChooser)}
- * has been called, then the supplied EGLConfigChooser is responsible for
- * choosing an OpenGL ES 2.0-compatible config.
- *
- * @param version
- * The EGLContext client version to choose. Use 2 for OpenGL ES
- * 2.0
- */
- public void setEGLContextClientVersion(int version) {
- checkRenderThreadState();
- mEGLContextClientVersion = version;
- }
-
- /**
- * Set the rendering mode. When renderMode is RENDERMODE_CONTINUOUSLY, the
- * renderer is called repeatedly to re-render the scene. When renderMode is
- * RENDERMODE_WHEN_DIRTY, the renderer only rendered when the surface is
- * created, or when {@link #requestRender} is called. Defaults to
- * RENDERMODE_CONTINUOUSLY.
- *
- * Using RENDERMODE_WHEN_DIRTY can improve battery life and overall system
- * performance by allowing the GPU and CPU to idle when the view does not
- * need to be updated.
- *
- * This method can only be called after {@link #setRenderer(Renderer)}
- *
- * @param renderMode
- * one of the RENDERMODE_X constants
- * @see #RENDERMODE_CONTINUOUSLY
- * @see #RENDERMODE_WHEN_DIRTY
- */
- public void setRenderMode(int renderMode) {
- mGLThread.setRenderMode(renderMode);
- }
-
- /**
- * Get the current rendering mode. May be called from any thread. Must not
- * be called before a renderer has been set.
- *
- * @return the current rendering mode.
- * @see #RENDERMODE_CONTINUOUSLY
- * @see #RENDERMODE_WHEN_DIRTY
- */
- public int getRenderMode() {
- return mGLThread.getRenderMode();
- }
-
- /**
- * Request that the renderer render a frame. This method is typically used
- * when the render mode has been set to {@link #RENDERMODE_WHEN_DIRTY}, so
- * that frames are only rendered on demand. May be called from any thread.
- * Must not be called before a renderer has been set.
- */
- public void requestRender() {
- mGLThread.requestRender();
- }
-
- /**
- * This method is part of the SurfaceHolder.Callback interface, and is not
- * normally called or subclassed by clients of GLSurfaceView.
- */
- public void surfaceCreated(SurfaceHolder holder) {
- mGLThread.surfaceCreated();
- }
-
- /**
- * This method is part of the SurfaceHolder.Callback interface, and is not
- * normally called or subclassed by clients of GLSurfaceView.
- */
- public void surfaceDestroyed(SurfaceHolder holder) {
- // Surface will be destroyed when we return
- mGLThread.surfaceDestroyed();
- }
-
- /**
- * This method is part of the SurfaceHolder.Callback interface, and is not
- * normally called or subclassed by clients of GLSurfaceView.
- */
- public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
- mGLThread.onWindowResize(w, h);
- }
-
- /**
- * Inform the view that the activity is paused. The owner of this view must
- * call this method when the activity is paused. Calling this method will
- * pause the rendering thread. Must not be called before a renderer has been
- * set.
- */
- public void onPause() {
- mGLThread.onPause();
- }
-
- /**
- * Inform the view that the activity is resumed. The owner of this view must
- * call this method when the activity is resumed. Calling this method will
- * recreate the OpenGL display and resume the rendering thread. Must not be
- * called before a renderer has been set.
- */
- public void onResume() {
- mGLThread.onResume();
- }
-
- /**
- * Queue a runnable to be run on the GL rendering thread. This can be used
- * to communicate with the Renderer on the rendering thread. Must not be
- * called before a renderer has been set.
- *
- * @param r
- * the runnable to be run on the GL rendering thread.
- */
- public void queueEvent(Runnable r) {
- mGLThread.queueEvent(r);
- }
-
- /**
- * This method is used as part of the View class and is not normally called
- * or subclassed by clients of GLSurfaceView.
- */
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- if (LOG_ATTACH_DETACH) {
- Log.d(TAG, "onAttachedToWindow reattach =" + mDetached);
- }
- if (mDetached && (mRenderer != null)) {
- int renderMode = RENDERMODE_CONTINUOUSLY;
- if (mGLThread != null) {
- renderMode = mGLThread.getRenderMode();
- }
- mGLThread = new GLThread(mThisWeakRef);
- if (renderMode != RENDERMODE_CONTINUOUSLY) {
- mGLThread.setRenderMode(renderMode);
- }
- mGLThread.start();
- }
- mDetached = false;
- }
-
- /**
- * This method is used as part of the View class and is not normally called
- * or subclassed by clients of GLSurfaceView. Must not be called before a
- * renderer has been set.
- */
- @Override
- protected void onDetachedFromWindow() {
- if (LOG_ATTACH_DETACH) {
- Log.d(TAG, "onDetachedFromWindow");
- }
- if (mGLThread != null) {
- mGLThread.requestExitAndWait();
- }
- mDetached = true;
- super.onDetachedFromWindow();
- }
-
- // ----------------------------------------------------------------------
-
- /**
- * An interface used to wrap a GL interface.
- *
- * Typically used for implementing debugging and tracing on top of the
- * default GL interface. You would typically use this by creating your own
- * class that implemented all the GL methods by delegating to another GL
- * instance. Then you could add your own behavior before or after calling
- * the delegate. All the GLWrapper would do was instantiate and return the
- * wrapper GL instance:
- *
- *
- * class MyGLWrapper implements GLWrapper {
- * GL wrap(GL gl) {
- * return new MyGLImplementation(gl);
- * }
- * static class MyGLImplementation implements GL,GL10,GL11,... {
- * ...
- * }
- * }
- *
- *
- * @see #setGLWrapper(GLWrapper)
- */
- public interface GLWrapper {
- /**
- * Wraps a gl interface in another gl interface.
- *
- * @param gl
- * a GL interface that is to be wrapped.
- * @return either the input argument or another GL object that wraps the
- * input argument.
- */
- GL wrap(GL gl);
- }
-
- /**
- * An interface for customizing the eglCreateContext and eglDestroyContext
- * calls.
- *
- * This interface must be implemented by clients wishing to call
- * {@link GLSurfaceView#setEGLContextFactory(EGLContextFactory)}
- */
- public interface EGLContextFactory {
- EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig);
-
- void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context);
- }
-
- private final class DefaultContextFactory implements EGLContextFactory {
- private int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
-
- @Override
- public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig config) {
- int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, mEGLContextClientVersion,
- EGL10.EGL_NONE };
-
- return egl.eglCreateContext(display, config, EGL10.EGL_NO_CONTEXT,
- mEGLContextClientVersion != 0 ? attrib_list : null);
- }
-
- @Override
- public void destroyContext(EGL10 egl, EGLDisplay display,
- EGLContext context) {
- if (!egl.eglDestroyContext(display, context)) {
- Log.e("DefaultContextFactory", "display:" + display + " context: "
- + context);
- if (LOG_THREADS) {
- Log.i("DefaultContextFactory", "tid="
- + Thread.currentThread().getId());
- }
- EglHelper.throwEglException("eglDestroyContex", egl.eglGetError());
- }
- }
- }
-
- /**
- * An interface for customizing the eglCreateWindowSurface and
- * eglDestroySurface calls.
- *
- * This interface must be implemented by clients wishing to call
- * {@link GLSurfaceView#setEGLWindowSurfaceFactory(EGLWindowSurfaceFactory)}
- */
- public interface EGLWindowSurfaceFactory {
- /**
- * @param egl
- * ...
- * @param display
- * ...
- * @param config
- * ...
- * @param nativeWindow
- * ...
- * @return null if the surface cannot be constructed.
- */
- EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display, EGLConfig config,
- Object nativeWindow);
-
- void destroySurface(EGL10 egl, EGLDisplay display, EGLSurface surface);
- }
-
- private static class DefaultWindowSurfaceFactory implements EGLWindowSurfaceFactory {
-
- @Override
- public EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display,
- EGLConfig config, Object nativeWindow) {
- EGLSurface result = null;
- try {
- result = egl.eglCreateWindowSurface(display, config, nativeWindow, null);
- } catch (IllegalArgumentException e) {
- // This exception indicates that the surface flinger surface
- // is not valid. This can happen if the surface flinger surface
- // has
- // been torn down, but the application has not yet been
- // notified via SurfaceHolder.Callback.surfaceDestroyed.
- // In theory the application should be notified first,
- // but in practice sometimes it is not. See b/4588890
- Log.e(TAG, "eglCreateWindowSurface", e);
- }
- return result;
- }
-
- @Override
- public void destroySurface(EGL10 egl, EGLDisplay display,
- EGLSurface surface) {
- egl.eglDestroySurface(display, surface);
- }
- }
-
- private abstract class BaseConfigChooser
- implements EGLConfigChooser {
- public BaseConfigChooser(int[] configSpec) {
- mConfigSpec = filterConfigSpec(configSpec);
- }
-
- @Override
- public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
- int[] num_config = new int[1];
- if (!egl.eglChooseConfig(display, mConfigSpec, null, 0,
- num_config)) {
- throw new IllegalArgumentException("eglChooseConfig failed");
- }
-
- int numConfigs = num_config[0];
-
- if (numConfigs <= 0) {
- throw new IllegalArgumentException(
- "No configs match configSpec");
- }
-
- EGLConfig[] configs = new EGLConfig[numConfigs];
- if (!egl.eglChooseConfig(display, mConfigSpec, configs, numConfigs,
- num_config)) {
- throw new IllegalArgumentException("eglChooseConfig#2 failed");
- }
- EGLConfig config = chooseConfig(egl, display, configs);
- if (config == null) {
- throw new IllegalArgumentException("No config chosen");
- }
- return config;
- }
-
- abstract EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
- EGLConfig[] configs);
-
- protected int[] mConfigSpec;
-
- private int[] filterConfigSpec(int[] configSpec) {
- if (mEGLContextClientVersion != 2) {
- return configSpec;
- }
- /*
- * We know none of the subclasses define EGL_RENDERABLE_TYPE. And we
- * know the configSpec is well formed.
- */
- int len = configSpec.length;
- int[] newConfigSpec = new int[len + 2];
- System.arraycopy(configSpec, 0, newConfigSpec, 0, len - 1);
- newConfigSpec[len - 1] = EGL10.EGL_RENDERABLE_TYPE;
- newConfigSpec[len] = 4; /* EGL_OPENGL_ES2_BIT */
- newConfigSpec[len + 1] = EGL10.EGL_NONE;
- return newConfigSpec;
- }
- }
-
- /**
- * Choose a configuration with exactly the specified r,g,b,a sizes, and at
- * least the specified depth and stencil sizes.
- */
- private class ComponentSizeChooser extends BaseConfigChooser {
- public ComponentSizeChooser(int redSize, int greenSize, int blueSize,
- int alphaSize, int depthSize, int stencilSize) {
- super(new int[] {
- EGL10.EGL_RED_SIZE, redSize,
- EGL10.EGL_GREEN_SIZE, greenSize,
- EGL10.EGL_BLUE_SIZE, blueSize,
- EGL10.EGL_ALPHA_SIZE, alphaSize,
- EGL10.EGL_DEPTH_SIZE, depthSize,
- EGL10.EGL_STENCIL_SIZE, stencilSize,
- EGL10.EGL_NONE });
- mValue = new int[1];
- mRedSize = redSize;
- mGreenSize = greenSize;
- mBlueSize = blueSize;
- mAlphaSize = alphaSize;
- mDepthSize = depthSize;
- mStencilSize = stencilSize;
- }
-
- @Override
- public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
- EGLConfig[] configs) {
- for (EGLConfig config : configs) {
- int d = findConfigAttrib(egl, display, config,
- EGL10.EGL_DEPTH_SIZE, 0);
- int s = findConfigAttrib(egl, display, config,
- EGL10.EGL_STENCIL_SIZE, 0);
- if ((d >= mDepthSize) && (s >= mStencilSize)) {
- int r = findConfigAttrib(egl, display, config,
- EGL10.EGL_RED_SIZE, 0);
- int g = findConfigAttrib(egl, display, config,
- EGL10.EGL_GREEN_SIZE, 0);
- int b = findConfigAttrib(egl, display, config,
- EGL10.EGL_BLUE_SIZE, 0);
- int a = findConfigAttrib(egl, display, config,
- EGL10.EGL_ALPHA_SIZE, 0);
- if ((r == mRedSize) && (g == mGreenSize)
- && (b == mBlueSize) && (a == mAlphaSize)) {
- return config;
- }
- }
- }
- return null;
- }
-
- private int findConfigAttrib(EGL10 egl, EGLDisplay display,
- EGLConfig config, int attribute, int defaultValue) {
-
- if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) {
- return mValue[0];
- }
- return defaultValue;
- }
-
- private int[] mValue;
- // Subclasses can adjust these values:
- protected int mRedSize;
- protected int mGreenSize;
- protected int mBlueSize;
- protected int mAlphaSize;
- protected int mDepthSize;
- protected int mStencilSize;
- }
-
- /**
- * This class will choose a RGB_565 surface with or without a depth buffer.
- */
- private class SimpleEGLConfigChooser extends ComponentSizeChooser {
- public SimpleEGLConfigChooser(boolean withDepthBuffer) {
- super(5, 6, 5, 0, withDepthBuffer ? 16 : 0, 0);
- }
- }
-
- /**
- * An EGL helper class.
- */
-
- private static class EglHelper {
- public EglHelper(WeakReference glSurfaceViewWeakRef) {
- mGLSurfaceViewWeakRef = glSurfaceViewWeakRef;
- }
-
- /**
- * Initialize EGL for a given configuration spec.
- */
- public void start() {
- if (LOG_EGL) {
- Log.w("EglHelper", "start() tid=" + Thread.currentThread().getId());
- }
- /*
- * Get an EGL instance
- */
- mEgl = (EGL10) EGLContext.getEGL();
-
- /*
- * Get to the default display.
- */
- mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
-
- if (mEglDisplay == EGL10.EGL_NO_DISPLAY) {
- throw new RuntimeException("eglGetDisplay failed");
- }
-
- /*
- * We can now initialize EGL for that display
- */
- int[] version = new int[2];
- if (!mEgl.eglInitialize(mEglDisplay, version)) {
- throw new RuntimeException("eglInitialize failed");
- }
- GLSurfaceView view = mGLSurfaceViewWeakRef.get();
- if (view == null) {
- mEglConfig = null;
- mEglContext = null;
- } else {
- mEglConfig = view.mEGLConfigChooser.chooseConfig(mEgl, mEglDisplay);
-
- /*
- * Create an EGL context. We want to do this as rarely as we
- * can, because an EGL context is a somewhat heavy object.
- */
- mEglContext = view.mEGLContextFactory.createContext(mEgl, mEglDisplay,
- mEglConfig);
- }
- if (mEglContext == null || mEglContext == EGL10.EGL_NO_CONTEXT) {
- mEglContext = null;
- throwEglException("createContext");
- }
- if (LOG_EGL) {
- Log.w("EglHelper", "createContext " + mEglContext + " tid="
- + Thread.currentThread().getId());
- }
-
- mEglSurface = null;
- }
-
- /**
- * Create an egl surface for the current SurfaceHolder surface. If a
- * surface already exists, destroy it before creating the new surface.
- *
- * @return true if the surface was created successfully.
- */
- public boolean createSurface() {
- if (LOG_EGL) {
- Log.w("EglHelper", "createSurface() tid="
- + Thread.currentThread().getId());
- }
- /*
- * Check preconditions.
- */
- if (mEgl == null) {
- throw new RuntimeException("egl not initialized");
- }
- if (mEglDisplay == null) {
- throw new RuntimeException("eglDisplay not initialized");
- }
- if (mEglConfig == null) {
- throw new RuntimeException("mEglConfig not initialized");
- }
-
- /*
- * The window size has changed, so we need to create a new surface.
- */
- destroySurfaceImp();
-
- /*
- * Create an EGL surface we can render into.
- */
- GLSurfaceView view = mGLSurfaceViewWeakRef.get();
- if (view != null) {
- mEglSurface = view.mEGLWindowSurfaceFactory.createWindowSurface(mEgl,
- mEglDisplay, mEglConfig, view.getHolder());
- } else {
- mEglSurface = null;
- }
-
- if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) {
- int error = mEgl.eglGetError();
- if (error == EGL10.EGL_BAD_NATIVE_WINDOW) {
- Log.e("EglHelper",
- "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
- }
- return false;
- }
-
- /*
- * Before we can issue GL commands, we need to make sure the context
- * is current and bound to a surface.
- */
- if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
- /*
- * Could not make the context current, probably because the
- * underlying SurfaceView surface has been destroyed.
- */
- logEglErrorAsWarning("EGLHelper", "eglMakeCurrent", mEgl.eglGetError());
- return false;
- }
-
- return true;
- }
-
- /**
- * Create a GL object for the current EGL context.
- *
- * @return ...
- */
- GL createGL() {
-
- GL gl = mEglContext.getGL();
- GLSurfaceView view = mGLSurfaceViewWeakRef.get();
- if (view != null) {
- if (view.mGLWrapper != null) {
- gl = view.mGLWrapper.wrap(gl);
- }
-
- if ((view.mDebugFlags & (DEBUG_CHECK_GL_ERROR | DEBUG_LOG_GL_CALLS)) != 0) {
- int configFlags = 0;
- Writer log = null;
- if ((view.mDebugFlags & DEBUG_CHECK_GL_ERROR) != 0) {
- configFlags |= GLDebugHelper.CONFIG_CHECK_GL_ERROR;
- }
- if ((view.mDebugFlags & DEBUG_LOG_GL_CALLS) != 0) {
- log = new LogWriter();
- }
- gl = GLDebugHelper.wrap(gl, configFlags, log);
- }
- }
- return gl;
- }
-
- /**
- * Display the current render surface.
- *
- * @return the EGL error code from eglSwapBuffers.
- */
- public int swap() {
- if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
- return mEgl.eglGetError();
- }
- return EGL10.EGL_SUCCESS;
- }
-
- public void destroySurface() {
- if (LOG_EGL) {
- Log.w("EglHelper", "destroySurface() tid="
- + Thread.currentThread().getId());
- }
- destroySurfaceImp();
- }
-
- private void destroySurfaceImp() {
- if (mEglSurface != null && mEglSurface != EGL10.EGL_NO_SURFACE) {
- mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
- EGL10.EGL_NO_SURFACE,
- EGL10.EGL_NO_CONTEXT);
- GLSurfaceView view = mGLSurfaceViewWeakRef.get();
- if (view != null) {
- view.mEGLWindowSurfaceFactory.destroySurface(mEgl, mEglDisplay,
- mEglSurface);
- }
- mEglSurface = null;
- }
- }
-
- public void finish() {
- if (LOG_EGL) {
- Log.w("EglHelper", "finish() tid=" + Thread.currentThread().getId());
- }
- if (mEglContext != null) {
- GLSurfaceView view = mGLSurfaceViewWeakRef.get();
- if (view != null) {
- view.mEGLContextFactory
- .destroyContext(mEgl, mEglDisplay, mEglContext);
- }
- mEglContext = null;
- }
- if (mEglDisplay != null) {
- mEgl.eglTerminate(mEglDisplay);
- mEglDisplay = null;
- }
- }
-
- private void throwEglException(String function) {
- throwEglException(function, mEgl.eglGetError());
- }
-
- public static void throwEglException(String function, int error) {
- String message = formatEglError(function, error);
- if (LOG_THREADS) {
- Log.e("EglHelper", "throwEglException tid="
- + Thread.currentThread().getId() + " "
- + message);
- }
- throw new RuntimeException(message);
- }
-
- public static void logEglErrorAsWarning(String tag, String function, int error) {
- Log.w(tag, formatEglError(function, error));
- }
-
- public static String formatEglError(String function, int error) {
- return function + " failed: "; // +
- // EGLLogWrapper.getErrorString(error);
- }
-
- private WeakReference mGLSurfaceViewWeakRef;
- EGL10 mEgl;
- EGLDisplay mEglDisplay;
- EGLSurface mEglSurface;
- EGLConfig mEglConfig;
- EGLContext mEglContext;
-
- }
-
- /**
- * A generic GL Thread. Takes care of initializing EGL and GL. Delegates to
- * a Renderer instance to do the actual drawing. Can be configured to render
- * continuously or on request. All potentially blocking synchronization is
- * done through the sGLThreadManager object. This avoids multiple-lock
- * ordering issues.
- */
- static class GLThread extends Thread {
- GLThread(WeakReference glSurfaceViewWeakRef) {
- super();
- mWidth = 0;
- mHeight = 0;
- mRequestRender = true;
- mRenderMode = RENDERMODE_CONTINUOUSLY;
- mGLSurfaceViewWeakRef = glSurfaceViewWeakRef;
- }
-
- @Override
- public void run() {
- setName("GLThread " + getId());
- if (LOG_THREADS) {
- Log.i("GLThread", "starting tid=" + getId());
- }
-
- try {
- guardedRun();
- } catch (InterruptedException e) {
- // fall thru and exit normally
- } finally {
- sGLThreadManager.threadExiting(this);
- }
- }
-
- /*
- * This private method should only be called inside a
- * synchronized(sGLThreadManager) block.
- */
- private void stopEglSurfaceLocked() {
- if (mHaveEglSurface) {
- mHaveEglSurface = false;
- mEglHelper.destroySurface();
- }
- }
-
- /*
- * This private method should only be called inside a
- * synchronized(sGLThreadManager) block.
- */
- private void stopEglContextLocked() {
- if (mHaveEglContext) {
- mEglHelper.finish();
- mHaveEglContext = false;
- sGLThreadManager.releaseEglContextLocked(this);
- }
- }
-
- private void guardedRun() throws InterruptedException {
- mEglHelper = new EglHelper(mGLSurfaceViewWeakRef);
- mHaveEglContext = false;
- mHaveEglSurface = false;
- try {
- GL10 gl = null;
- boolean createEglContext = false;
- boolean createEglSurface = false;
- boolean createGlInterface = false;
- boolean lostEglContext = false;
- boolean sizeChanged = false;
- boolean wantRenderNotification = false;
- boolean doRenderNotification = false;
- boolean askedToReleaseEglContext = false;
- int w = 0;
- int h = 0;
- Runnable event = null;
-
- while (true) {
- synchronized (sGLThreadManager) {
- while (true) {
- if (mShouldExit) {
- return;
- }
-
- if (!mEventQueue.isEmpty()) {
- event = mEventQueue.remove(0);
- break;
- }
-
- // Update the pause state.
- boolean pausing = false;
- if (mPaused != mRequestPaused) {
- pausing = mRequestPaused;
- mPaused = mRequestPaused;
- sGLThreadManager.notifyAll();
- if (LOG_PAUSE_RESUME) {
- Log.i("GLThread", "mPaused is now " + mPaused
- + " tid=" + getId());
- }
- }
-
- // Do we need to give up the EGL context?
- if (mShouldReleaseEglContext) {
- if (LOG_SURFACE) {
- Log.i("GLThread",
- "releasing EGL context because asked to tid="
- + getId());
- }
- stopEglSurfaceLocked();
- stopEglContextLocked();
- mShouldReleaseEglContext = false;
- askedToReleaseEglContext = true;
- }
-
- // Have we lost the EGL context?
- if (lostEglContext) {
- stopEglSurfaceLocked();
- stopEglContextLocked();
- lostEglContext = false;
- }
-
- // When pausing, release the EGL surface:
- if (pausing && mHaveEglSurface) {
- if (LOG_SURFACE) {
- Log.i("GLThread",
- "releasing EGL surface because paused tid="
- + getId());
- }
- stopEglSurfaceLocked();
- }
-
- // When pausing, optionally release the EGL Context:
- if (pausing && mHaveEglContext) {
- GLSurfaceView view = mGLSurfaceViewWeakRef.get();
- boolean preserveEglContextOnPause = view == null ?
- false : view.mPreserveEGLContextOnPause;
- if (!preserveEglContextOnPause
- || sGLThreadManager
- .shouldReleaseEGLContextWhenPausing()) {
- stopEglContextLocked();
- if (LOG_SURFACE) {
- Log.i("GLThread",
- "releasing EGL context because paused tid="
- + getId());
- }
- }
- }
-
- // When pausing, optionally terminate EGL:
- if (pausing) {
- if (sGLThreadManager.shouldTerminateEGLWhenPausing()) {
- mEglHelper.finish();
- if (LOG_SURFACE) {
- Log.i("GLThread",
- "terminating EGL because paused tid="
- + getId());
- }
- }
- }
-
- // Have we lost the SurfaceView surface?
- if ((!mHasSurface) && (!mWaitingForSurface)) {
- if (LOG_SURFACE) {
- Log.i("GLThread",
- "noticed surfaceView surface lost tid="
- + getId());
- }
- if (mHaveEglSurface) {
- stopEglSurfaceLocked();
- }
- mWaitingForSurface = true;
- mSurfaceIsBad = false;
- sGLThreadManager.notifyAll();
- }
-
- // Have we acquired the surface view surface?
- if (mHasSurface && mWaitingForSurface) {
- if (LOG_SURFACE) {
- Log.i("GLThread",
- "noticed surfaceView surface acquired tid="
- + getId());
- }
- mWaitingForSurface = false;
- sGLThreadManager.notifyAll();
- }
-
- if (doRenderNotification) {
- if (LOG_SURFACE) {
- Log.i("GLThread", "sending render notification tid="
- + getId());
- }
- wantRenderNotification = false;
- doRenderNotification = false;
- mRenderComplete = true;
- sGLThreadManager.notifyAll();
- }
-
- // Ready to draw?
- if (readyToDraw()) {
-
- // If we don't have an EGL context, try to
- // acquire one.
- if (!mHaveEglContext) {
- if (askedToReleaseEglContext) {
- askedToReleaseEglContext = false;
- } else if (sGLThreadManager
- .tryAcquireEglContextLocked(this)) {
- try {
- mEglHelper.start();
- } catch (RuntimeException t) {
- sGLThreadManager
- .releaseEglContextLocked(this);
- throw t;
- }
- mHaveEglContext = true;
- createEglContext = true;
-
- sGLThreadManager.notifyAll();
- }
- }
-
- if (mHaveEglContext && !mHaveEglSurface) {
- mHaveEglSurface = true;
- createEglSurface = true;
- createGlInterface = true;
- sizeChanged = true;
- }
-
- if (mHaveEglSurface) {
- if (mSizeChanged) {
- sizeChanged = true;
- w = mWidth;
- h = mHeight;
- wantRenderNotification = true;
- if (LOG_SURFACE) {
- Log.i("GLThread",
- "noticing that we want render notification tid="
- + getId());
- }
-
- // Destroy and recreate the EGL surface.
- createEglSurface = true;
-
- mSizeChanged = false;
- }
- mRequestRender = false;
- sGLThreadManager.notifyAll();
- break;
- }
- }
-
- // By design, this is the only place in a GLThread
- // thread where we wait().
- if (LOG_THREADS) {
- Log.i("GLThread", "waiting tid=" + getId()
- + " mHaveEglContext: " + mHaveEglContext
- + " mHaveEglSurface: " + mHaveEglSurface
- + " mPaused: " + mPaused
- + " mHasSurface: " + mHasSurface
- + " mSurfaceIsBad: " + mSurfaceIsBad
- + " mWaitingForSurface: " + mWaitingForSurface
- + " mWidth: " + mWidth
- + " mHeight: " + mHeight
- + " mRequestRender: " + mRequestRender
- + " mRenderMode: " + mRenderMode);
- }
- sGLThreadManager.wait();
- }
- } // end of synchronized(sGLThreadManager)
-
- if (event != null) {
- event.run();
- event = null;
- continue;
- }
-
- if (createEglSurface) {
- if (LOG_SURFACE) {
- Log.w("GLThread", "egl createSurface");
- }
- if (!mEglHelper.createSurface()) {
- synchronized (sGLThreadManager) {
- mSurfaceIsBad = true;
- sGLThreadManager.notifyAll();
- }
- continue;
- }
- createEglSurface = false;
- }
-
- if (createGlInterface) {
- gl = (GL10) mEglHelper.createGL();
-
- sGLThreadManager.checkGLDriver(gl);
- createGlInterface = false;
- }
-
- if (createEglContext) {
- if (LOG_RENDERER) {
- Log.w("GLThread", "onSurfaceCreated");
- }
- GLSurfaceView view = mGLSurfaceViewWeakRef.get();
- if (view != null) {
- view.mRenderer.onSurfaceCreated(gl, mEglHelper.mEglConfig);
- }
- createEglContext = false;
- }
-
- if (sizeChanged) {
- if (LOG_RENDERER) {
- Log.w("GLThread", "onSurfaceChanged(" + w + ", " + h + ")");
- }
- GLSurfaceView view = mGLSurfaceViewWeakRef.get();
- if (view != null) {
- view.mRenderer.onSurfaceChanged(gl, w, h);
- }
- sizeChanged = false;
- }
-
- if (LOG_RENDERER_DRAW_FRAME) {
- Log.w("GLThread", "onDrawFrame tid=" + getId());
- }
- {
- GLSurfaceView view = mGLSurfaceViewWeakRef.get();
- if (view != null) {
- view.mRenderer.onDrawFrame(gl);
- }
- }
- int swapError = mEglHelper.swap();
- switch (swapError) {
- case EGL10.EGL_SUCCESS:
- break;
- case EGL11.EGL_CONTEXT_LOST:
- if (LOG_SURFACE) {
- Log.i("GLThread", "egl context lost tid=" + getId());
- }
- lostEglContext = true;
- break;
- default:
- // Other errors typically mean that the current
- // surface is bad,
- // probably because the SurfaceView surface has been
- // destroyed,
- // but we haven't been notified yet.
- // Log the error to help developers understand why
- // rendering stopped.
- EglHelper.logEglErrorAsWarning("GLThread", "eglSwapBuffers",
- swapError);
-
- synchronized (sGLThreadManager) {
- mSurfaceIsBad = true;
- sGLThreadManager.notifyAll();
- }
- break;
- }
-
- if (wantRenderNotification) {
- doRenderNotification = true;
- }
- }
-
- } finally {
- /*
- * clean-up everything...
- */
- synchronized (sGLThreadManager) {
- stopEglSurfaceLocked();
- stopEglContextLocked();
- }
- }
- }
-
- public boolean ableToDraw() {
- return mHaveEglContext && mHaveEglSurface && readyToDraw();
- }
-
- private boolean readyToDraw() {
- return (!mPaused) && mHasSurface && (!mSurfaceIsBad)
- && (mWidth > 0) && (mHeight > 0)
- && (mRequestRender || (mRenderMode == RENDERMODE_CONTINUOUSLY));
- }
-
- public void setRenderMode(int renderMode) {
- if (!((RENDERMODE_WHEN_DIRTY <= renderMode) && (renderMode <= RENDERMODE_CONTINUOUSLY))) {
- throw new IllegalArgumentException("renderMode");
- }
- synchronized (sGLThreadManager) {
- mRenderMode = renderMode;
- sGLThreadManager.notifyAll();
- }
- }
-
- public int getRenderMode() {
- synchronized (sGLThreadManager) {
- return mRenderMode;
- }
- }
-
- public void requestRender() {
- synchronized (sGLThreadManager) {
- mRequestRender = true;
- sGLThreadManager.notifyAll();
- }
- }
-
- public void surfaceCreated() {
- synchronized (sGLThreadManager) {
- if (LOG_THREADS) {
- Log.i("GLThread", "surfaceCreated tid=" + getId());
- }
- mHasSurface = true;
- sGLThreadManager.notifyAll();
- while ((mWaitingForSurface) && (!mExited)) {
- try {
- sGLThreadManager.wait();
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- }
- }
- }
- }
-
- public void surfaceDestroyed() {
- synchronized (sGLThreadManager) {
- if (LOG_THREADS) {
- Log.i("GLThread", "surfaceDestroyed tid=" + getId());
- }
- mHasSurface = false;
- sGLThreadManager.notifyAll();
- while ((!mWaitingForSurface) && (!mExited)) {
- try {
- sGLThreadManager.wait();
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- }
- }
- }
- }
-
- public void onPause() {
- synchronized (sGLThreadManager) {
- if (LOG_PAUSE_RESUME) {
- Log.i("GLThread", "onPause tid=" + getId());
- }
- mRequestPaused = true;
- sGLThreadManager.notifyAll();
- while ((!mExited) && (!mPaused)) {
- if (LOG_PAUSE_RESUME) {
- Log.i("Main thread", "onPause waiting for mPaused.");
- }
- try {
- sGLThreadManager.wait();
- } catch (InterruptedException ex) {
- Thread.currentThread().interrupt();
- }
- }
- }
- }
-
- public void onResume() {
- synchronized (sGLThreadManager) {
- if (LOG_PAUSE_RESUME) {
- Log.i("GLThread", "onResume tid=" + getId());
- }
- mRequestPaused = false;
- mRequestRender = true;
- mRenderComplete = false;
- sGLThreadManager.notifyAll();
- while ((!mExited) && mPaused && (!mRenderComplete)) {
- if (LOG_PAUSE_RESUME) {
- Log.i("Main thread", "onResume waiting for !mPaused.");
- }
- try {
- sGLThreadManager.wait();
- } catch (InterruptedException ex) {
- Thread.currentThread().interrupt();
- }
- }
- }
- }
-
- public void onWindowResize(int w, int h) {
- synchronized (sGLThreadManager) {
- mWidth = w;
- mHeight = h;
- mSizeChanged = true;
- mRequestRender = true;
- mRenderComplete = false;
- sGLThreadManager.notifyAll();
-
- // Wait for thread to react to resize and render a frame
- while (!mExited && !mPaused && !mRenderComplete
- && ableToDraw()) {
- if (LOG_SURFACE) {
- Log.i("Main thread",
- "onWindowResize waiting for render complete from tid="
- + getId());
- }
- try {
- sGLThreadManager.wait();
- } catch (InterruptedException ex) {
- Thread.currentThread().interrupt();
- }
- }
- }
- }
-
- public void requestExitAndWait() {
- // don't call this from GLThread thread or it is a guaranteed
- // deadlock!
- synchronized (sGLThreadManager) {
- mShouldExit = true;
- sGLThreadManager.notifyAll();
- while (!mExited) {
- try {
- sGLThreadManager.wait();
- } catch (InterruptedException ex) {
- Thread.currentThread().interrupt();
- }
- }
- }
- }
-
- public void requestReleaseEglContextLocked() {
- mShouldReleaseEglContext = true;
- sGLThreadManager.notifyAll();
- }
-
- /**
- * Queue an "event" to be run on the GL rendering thread.
- *
- * @param r
- * the runnable to be run on the GL rendering thread.
- */
- public void queueEvent(Runnable r) {
- if (r == null) {
- throw new IllegalArgumentException("r must not be null");
- }
- synchronized (sGLThreadManager) {
- mEventQueue.add(r);
- sGLThreadManager.notifyAll();
- }
- }
-
- // Once the thread is started, all accesses to the following member
- // variables are protected by the sGLThreadManager monitor
- private boolean mShouldExit;
- private boolean mExited;
- private boolean mRequestPaused;
- private boolean mPaused;
- private boolean mHasSurface;
- private boolean mSurfaceIsBad;
- private boolean mWaitingForSurface;
- private boolean mHaveEglContext;
- private boolean mHaveEglSurface;
- private boolean mShouldReleaseEglContext;
- private int mWidth;
- private int mHeight;
- private int mRenderMode;
- private boolean mRequestRender;
- private boolean mRenderComplete;
- private ArrayList mEventQueue = new ArrayList();
- private boolean mSizeChanged = true;
-
- // End of member variables protected by the sGLThreadManager monitor.
-
- private EglHelper mEglHelper;
-
- /**
- * Set once at thread construction time, nulled out when the parent view
- * is garbage called. This weak reference allows the GLSurfaceView to be
- * garbage collected while the GLThread is still alive.
- */
- private WeakReference mGLSurfaceViewWeakRef;
-
- }
-
- static class LogWriter extends Writer {
-
- @Override
- public void close() {
- flushBuilder();
- }
-
- @Override
- public void flush() {
- flushBuilder();
- }
-
- @Override
- public void write(char[] buf, int offset, int count) {
- for (int i = 0; i < count; i++) {
- char c = buf[offset + i];
- if (c == '\n') {
- flushBuilder();
- }
- else {
- mBuilder.append(c);
- }
- }
- }
-
- private void flushBuilder() {
- if (mBuilder.length() > 0) {
- Log.v("GLSurfaceView", mBuilder.toString());
- mBuilder.delete(0, mBuilder.length());
- }
- }
-
- private StringBuilder mBuilder = new StringBuilder();
- }
-
- private void checkRenderThreadState() {
- if (mGLThread != null) {
- throw new IllegalStateException(
- "setRenderer has already been called for this instance.");
- }
- }
-
- private static class GLThreadManager {
- private static String TAG = "GLThreadManager";
-
- public synchronized void threadExiting(GLThread thread) {
- if (LOG_THREADS) {
- Log.i("GLThread", "exiting tid=" + thread.getId());
- }
- thread.mExited = true;
- if (mEglOwner == thread) {
- mEglOwner = null;
- }
- notifyAll();
- }
-
- /*
- * Tries once to acquire the right to use an EGL context. Does not
- * block. Requires that we are already in the sGLThreadManager monitor
- * when this is called.
- * @return true if the right to use an EGL context was acquired.
- */
- public boolean tryAcquireEglContextLocked(GLThread thread) {
- if (mEglOwner == thread || mEglOwner == null) {
- mEglOwner = thread;
- notifyAll();
- return true;
- }
- checkGLESVersion();
- if (mMultipleGLESContextsAllowed) {
- return true;
- }
- // Notify the owning thread that it should release the context.
- // TODO: implement a fairness policy. Currently
- // if the owning thread is drawing continuously it will just
- // reacquire the EGL context.
- if (mEglOwner != null) {
- mEglOwner.requestReleaseEglContextLocked();
- }
- return false;
- }
-
- /*
- * Releases the EGL context. Requires that we are already in the
- * sGLThreadManager monitor when this is called.
- */
- public void releaseEglContextLocked(GLThread thread) {
- if (mEglOwner == thread) {
- mEglOwner = null;
- }
- notifyAll();
- }
-
- public synchronized boolean shouldReleaseEGLContextWhenPausing() {
- // Release the EGL context when pausing even if
- // the hardware supports multiple EGL contexts.
- // Otherwise the device could run out of EGL contexts.
- return mLimitedGLESContexts;
- }
-
- public synchronized boolean shouldTerminateEGLWhenPausing() {
- checkGLESVersion();
- return !mMultipleGLESContextsAllowed;
- }
-
- public synchronized void checkGLDriver(GL10 gl) {
- if (!mGLESDriverCheckComplete) {
- checkGLESVersion();
- String renderer = gl.glGetString(GL10.GL_RENDERER);
- if (mGLESVersion < kGLES_20) {
- mMultipleGLESContextsAllowed =
- !renderer.startsWith(kMSM7K_RENDERER_PREFIX);
- notifyAll();
- }
- mLimitedGLESContexts = !mMultipleGLESContextsAllowed;
- if (LOG_SURFACE) {
- Log.w(TAG, "checkGLDriver renderer = \"" + renderer
- + "\" multipleContextsAllowed = "
- + mMultipleGLESContextsAllowed
- + " mLimitedGLESContexts = " + mLimitedGLESContexts);
- }
- mGLESDriverCheckComplete = true;
- }
- }
-
- private void checkGLESVersion() {
- // if (!mGLESVersionCheckComplete) {
- // mGLESVersion = SystemProperties.getInt(
- // "ro.opengles.version",
- // ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
- // if (mGLESVersion >= kGLES_20) {
- // mMultipleGLESContextsAllowed = true;
- // }
- // if (LOG_SURFACE) {
- // Log.w(TAG, "checkGLESVersion mGLESVersion =" +
- // " " + mGLESVersion + " mMultipleGLESContextsAllowed = "
- // + mMultipleGLESContextsAllowed);
- // }
- // mGLESVersionCheckComplete = true;
- // }
- }
-
- /**
- * This check was required for some pre-Android-3.0 hardware. Android
- * 3.0 provides support for hardware-accelerated views, therefore
- * multiple EGL contexts are supported on all Android 3.0+ EGL drivers.
- */
- private boolean mGLESVersionCheckComplete;
- private int mGLESVersion;
- private boolean mGLESDriverCheckComplete;
- private boolean mMultipleGLESContextsAllowed;
- private boolean mLimitedGLESContexts;
- private static final int kGLES_20 = 0x20000;
- private static final String kMSM7K_RENDERER_PREFIX =
- "Q3Dimension MSM7500 ";
- private GLThread mEglOwner;
- }
-
- /* package */static final GLThreadManager sGLThreadManager = new GLThreadManager();
-
- private final WeakReference mThisWeakRef =
- new WeakReference(this);
- private GLThread mGLThread;
- private Renderer mRenderer;
- private boolean mDetached;
- private EGLConfigChooser mEGLConfigChooser;
- private EGLContextFactory mEGLContextFactory;
- private EGLWindowSurfaceFactory mEGLWindowSurfaceFactory;
- private GLWrapper mGLWrapper;
- private int mDebugFlags;
- private int mEGLContextClientVersion;
- private boolean mPreserveEGLContextOnPause;
-}
diff --git a/src/org/oscim/view/Compass.java b/src/org/oscim/view/Compass.java
index b90063c7..ba7d94b7 100644
--- a/src/org/oscim/view/Compass.java
+++ b/src/org/oscim/view/Compass.java
@@ -29,7 +29,7 @@ public class Compass {
mAngle = event.values[0];
if (mMapView != null) {
- mMapView.getMapPosition().setRotation(mAngle);
+ mMapView.getMapPosition().setRotation(-mAngle);
mMapView.redrawMap();
}
}
diff --git a/src/org/oscim/view/MapView.java b/src/org/oscim/view/MapView.java
index b65b5fd4..4332b5be 100644
--- a/src/org/oscim/view/MapView.java
+++ b/src/org/oscim/view/MapView.java
@@ -57,6 +57,8 @@ public class MapView extends FrameLayout {
public static final boolean debugFrameTime = false;
public static final boolean testRegionZoom = false;
+ public static final boolean staticLabeling = true;
+
private static final boolean debugDatabase = false;
RegionLookup mRegionLookup;
@@ -82,8 +84,6 @@ public class MapView extends FrameLayout {
private String mRenderTheme;
private Map mMapOptions;
- // private final Handler mHandler;
-
/**
* @param context
* the enclosing MapActivity instance.
diff --git a/src/org/oscim/view/MapViewPosition.java b/src/org/oscim/view/MapViewPosition.java
index 8fef7a3b..619cdaa7 100644
--- a/src/org/oscim/view/MapViewPosition.java
+++ b/src/org/oscim/view/MapViewPosition.java
@@ -27,9 +27,10 @@ import android.util.Log;
* together with its zoom level.
*/
public class MapViewPosition {
- // private static final String TAG = "MapViewPosition";
+ private static final String TAG = "MapViewPosition";
public final static int MAX_ZOOMLEVEL = 17;
+ public final static int MIN_ZOOMLEVEL = 2;
private final static float MAX_ANGLE = 20;
@@ -68,7 +69,7 @@ public class MapViewPosition {
void setViewport(int width, int height) {
Matrix.frustumM(mProjMatrix, 0, -0.5f * width, 0.5f * width,
- -0.5f * height, 0.5f * height, 1, 2);
+ 0.5f * height, -0.5f * height, 1, 2);
Matrix.translateM(mProjMatrix, 0, 0, 0, -1);
@@ -92,14 +93,14 @@ public class MapViewPosition {
// && mapPosition.scale == mScale
// && mapPosition.angle == mRotation)
// return false;
+ byte z = mZoomLevel;
mapPosition.lat = mLatitude;
mapPosition.lon = mLongitude;
mapPosition.angle = mRotation;
- mapPosition.zoomLevel = mZoomLevel;
mapPosition.scale = mScale;
+ mapPosition.zoomLevel = z;
- byte z = mZoomLevel;
mapPosition.x = MercatorProjection.longitudeToPixelX(mLongitude, z);
mapPosition.y = MercatorProjection.latitudeToPixelY(mLatitude, z);
@@ -138,13 +139,12 @@ public class MapViewPosition {
if (mv[3] != 0) {
float w = 1 / mv[3];
- float xx = mv[0] * w;
- float yy = mv[1] * w;
-
- coords[position] = xx;
- coords[position + 1] = yy;
+ coords[position] = mv[0] * w;
+ coords[position + 1] = mv[1] * w;
+ } else {
+ // else what?
+ Log.d(TAG, "... what?");
}
- // else what?
}
private void updateMatrix() {
@@ -152,7 +152,7 @@ public class MapViewPosition {
// tilt map
float tilt = mTilt;
- Matrix.setRotateM(mTmpMatrix, 0, -tilt / (mHeight / 2), 1, 0, 0);
+ Matrix.setRotateM(mTmpMatrix, 0, tilt / (mHeight / 2), 1, 0, 0);
// apply first rotation, then tilt
Matrix.multiplyMM(mRotateMatrix, 0, mTmpMatrix, 0, mRotateMatrix, 0);
@@ -177,10 +177,10 @@ public class MapViewPosition {
float tilt = FloatMath.sin((float) Math.toRadians(mTilt)) * 4;
- unproject(-1, 1, tilt, mBBoxCoords, 0); // top-left
- unproject(1, 1, tilt, mBBoxCoords, 2); // top-right
- unproject(1, -1, -tilt, mBBoxCoords, 4); // bottom-right
- unproject(-1, -1, -tilt, mBBoxCoords, 6); // bottom-left
+ unproject(-1, 1, -tilt, mBBoxCoords, 0); // top-left
+ unproject(1, 1, -tilt, mBBoxCoords, 2); // top-right
+ unproject(1, -1, tilt, mBBoxCoords, 4); // bottom-right
+ unproject(-1, -1, tilt, mBBoxCoords, 6); // bottom-left
byte z = mZoomLevel;
double pixelX = MercatorProjection.longitudeToPixelX(mLongitude, z);
@@ -333,8 +333,8 @@ public class MapViewPosition {
if (mMapView.enableRotation || mMapView.enableCompass) {
double rad = Math.toRadians(mRotation);
- double x = dx * Math.cos(rad) + dy * -Math.sin(rad);
- double y = dx * Math.sin(rad) + dy * Math.cos(rad);
+ double x = dx * Math.cos(rad) + dy * Math.sin(rad);
+ double y = dx * -Math.sin(rad) + dy * Math.cos(rad);
dx = x;
dy = y;
}
@@ -357,7 +357,7 @@ public class MapViewPosition {
moveMap(cx, cy);
// Log.d("MapViewPosition", "rotate:" + angle + " " + (mRotation -
// angle));
- mRotation -= angle;
+ mRotation += angle;
updateMatrix();
}
@@ -426,12 +426,13 @@ public class MapViewPosition {
int z = FastMath.log2((int) newScale);
- if (z <= 0 || (z >= MAX_ZOOMLEVEL && mScale >= 8))
+ if (z < MIN_ZOOMLEVEL || (z >= MAX_ZOOMLEVEL && mScale >= 8))
return false;
if (z > MAX_ZOOMLEVEL) {
- // z16 shows everything, just increase scaling
- if (mScale * scale > 8)
+ // z17 shows everything, just increase scaling
+ // need to fix this for ScanBox
+ if (mScale * scale > 2) // 8)
return false;
mScale *= scale;
diff --git a/src/org/oscim/view/overlay/Overlay.java b/src/org/oscim/view/overlay/Overlay.java
deleted file mode 100644
index 4d5a2a04..00000000
--- a/src/org/oscim/view/overlay/Overlay.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2012, 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 .
- */
-package org.oscim.view.overlay;
-
-public class Overlay {
-
- synchronized void move() {
-
- }
-
- synchronized void addBitmap() {
-
- }
-
- synchronized boolean onTouch() {
-
- return true;
- }
-
- synchronized void draw() {
-
- }
-}
diff --git a/src/org/oscim/view/overlay/TiledOverlay.java b/src/org/oscim/view/overlay/TiledOverlay.java
deleted file mode 100644
index a3c68284..00000000
--- a/src/org/oscim/view/overlay/TiledOverlay.java
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright 2010, 2011, 2012 mapsforge.org
- *
- * 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 .
- */
-package org.oscim.view.overlay;
-
-public class TiledOverlay extends Overlay {
-
-}
diff --git a/src/org/oscim/view/renderer/GLRenderer.java b/src/org/oscim/view/renderer/GLRenderer.java
index 91b6f7e1..00802c26 100644
--- a/src/org/oscim/view/renderer/GLRenderer.java
+++ b/src/org/oscim/view/renderer/GLRenderer.java
@@ -21,7 +21,6 @@ import static android.opengl.GLES20.GL_DYNAMIC_DRAW;
import static android.opengl.GLES20.GL_ONE;
import static android.opengl.GLES20.GL_ONE_MINUS_SRC_ALPHA;
import static android.opengl.GLES20.GL_POLYGON_OFFSET_FILL;
-import static android.opengl.GLES20.GL_STENCIL_BUFFER_BIT;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
@@ -63,7 +62,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
private final MapView mMapView;
private final MapViewPosition mMapViewPosition;
- private static final MapPosition mMapPosition = new MapPosition();
+ private static MapPosition mMapPosition;
private static ArrayList mVBOs;
@@ -82,7 +81,8 @@ public class GLRenderer implements GLSurfaceView.Renderer {
// mNextTiles is set by TileLoader and swapped with
// mDrawTiles in onDrawFrame in GL thread.
- private static TilesData mNextTiles, mDrawTiles;
+ private static TilesData mNextTiles;
+ /* package */static TilesData mDrawTiles;
// flag set by updateVisibleList when current visible tiles
// changed. used in onDrawFrame to flip mNextTiles/mDrawTiles
@@ -95,9 +95,78 @@ public class GLRenderer implements GLSurfaceView.Renderer {
private static boolean mUpdateColor = false;
- // lock to synchronize Main- and GL-Thread
+ // drawlock to synchronize Main- and GL-Thread
static ReentrantLock tilelock = new ReentrantLock();
- static ReentrantLock lock = new ReentrantLock();
+ static ReentrantLock drawlock = new ReentrantLock();
+
+ /* package */static int mHolderCount;
+
+ // scanline fill class used to check tile visibility
+ private static ScanBox mScanBox = new ScanBox() {
+ @Override
+ void setVisible(int y, int x1, int x2) {
+ int cnt = mDrawTiles.cnt;
+
+ MapTile[] tiles = mDrawTiles.tiles;
+
+ for (int i = 0; i < cnt; i++) {
+ MapTile t = tiles[i];
+ if (t.tileY == y && t.tileX >= x1 && t.tileX < x2)
+ t.isVisible = true;
+ }
+
+ int xmax = 1 << mZoom;
+ if (x1 >= 0 && x2 < xmax)
+ return;
+
+ // add placeholder tiles to show both sides
+ // of date line...
+ for (int x = x1; x < x2; x++) {
+ MapTile holder = null;
+ MapTile tile = null;
+ boolean found = false;
+
+ int xx = x;
+
+ if (x >= 0 && x < xmax)
+ continue;
+
+ if (x < 0)
+ xx = xmax + x;
+ else
+ xx = x - xmax;
+
+ if (xx < 0 || xx >= xmax)
+ continue;
+
+ for (int i = cnt; i < cnt + mHolderCount; i++)
+ if (tiles[i].tileX == x && tiles[i].tileY == y) {
+ found = true;
+ break;
+ }
+
+ if (found)
+ continue;
+
+ for (int i = 0; i < cnt; i++)
+ if (tiles[i].tileX == xx && tiles[i].tileY == y) {
+ tile = tiles[i];
+ break;
+ }
+
+ if (tile == null)
+ continue;
+
+ // Log.d(TAG, "add placeholder " + y + " " + x + ">>" + xx + " "
+ // + tile);
+
+ holder = new MapTile(x, y, mZoom);
+ holder.isVisible = true;
+ holder.holder = tile;
+ tiles[cnt + mHolderCount++] = holder;
+ }
+ }
+ };
/**
* @param mapView
@@ -108,8 +177,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
mMapView = mapView;
mMapViewPosition = mapView.getMapViewPosition();
- // mMapPosition = new MapPosition();
-
+ mMapPosition = new MapPosition();
mMapPosition.init();
Matrix.setIdentityM(mMVPMatrix, 0);
@@ -141,63 +209,38 @@ public class GLRenderer implements GLSurfaceView.Renderer {
}
/**
- * called by TileLoader when list of active tiles changed
+ * Called by TileLoader when list of active tiles changed. the list is
+ * copied to mNextTiles to be used in next call to onDrawFrame
*
* @param tiles
* active tiles
- * @return mNextTiles (the previously active tiles)
*/
- static TilesData updateTiles(TilesData tiles) {
- GLRenderer.tilelock.lock();
+ static void updateTiles(TilesData tiles) {
- // unlock previously active tiles
- for (int i = 0; i < mNextTiles.cnt; i++) {
- MapTile t = mNextTiles.tiles[i];
- boolean found = false;
-
- for (int j = 0; j < tiles.cnt; j++) {
- if (tiles.tiles[j] == t) {
- found = true;
- break;
- }
- }
- if (found)
- continue;
-
- for (int j = 0; j < mDrawTiles.cnt; j++) {
- if (mDrawTiles.tiles[j] == t) {
- found = true;
- break;
- }
- }
- if (found)
- continue;
-
- t.unlock();
- }
-
- TilesData tmp = mNextTiles;
- mNextTiles = tiles;
+ MapTile[] newTiles = tiles.tiles;
// lock tiles (and their proxies) to not be removed from cache
- for (int i = 0; i < mNextTiles.cnt; i++) {
- MapTile t = mNextTiles.tiles[i];
- if (!t.isLocked)
- t.lock();
- }
+ for (int i = 0, n = tiles.cnt; i < n; i++)
+ newTiles[i].lock();
- for (int j = 0; j < mDrawTiles.cnt; j++) {
- MapTile t = mDrawTiles.tiles[j];
- if (!t.isLocked)
- t.lock();
- }
+ // dont flip next/drawTiles while copying
+ GLRenderer.tilelock.lock();
- // GLThread flips mNextTiles with mDrawTiles
+ MapTile[] nextTiles = mNextTiles.tiles;
+
+ // unlock previously active tiles
+ for (int i = 0, n = mNextTiles.cnt; i < n; i++)
+ nextTiles[i].unlock();
+
+ // copy newTiles to nextTiles
+ System.arraycopy(newTiles, 0, nextTiles, 0, tiles.cnt);
+
+ mNextTiles.cnt = tiles.cnt;
+
+ // flip next/drawTiles in next onDrawFrame
mUpdateTiles = true;
GLRenderer.tilelock.unlock();
-
- return tmp;
}
/**
@@ -267,7 +310,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
// add fill coordinates
newSize += 8;
- // FIXME probably not a good idea to do this in gl thread...
+ // probably not a good idea to do this in gl thread...
if (sbuf.capacity() < newSize) {
ByteBuffer bbuf = ByteBuffer.allocateDirect(newSize * SHORT_BYTES)
.order(ByteOrder.nativeOrder());
@@ -317,7 +360,6 @@ public class GLRenderer implements GLSurfaceView.Renderer {
if (tile.vbo.size > newSize && tile.vbo.size < newSize * 4
&& mBufferMemoryUsage < LIMIT_BUFFERS) {
GLES20.glBufferSubData(GL_ARRAY_BUFFER, 0, newSize, sbuf);
- // Log.d(TAG, "reuse buffer " + tile.vbo.size + " " + newSize);
} else {
mBufferMemoryUsage -= tile.vbo.size;
tile.vbo.size = newSize;
@@ -385,68 +427,26 @@ public class GLRenderer implements GLSurfaceView.Renderer {
CACHE_TILES -= 50;
}
- private static boolean isVisible(MapTile tile) {
- float dx, dy, scale, div = 1;
- MapPosition mapPosition = mMapPosition;
- int diff = mapPosition.zoomLevel - tile.zoomLevel;
-
- if (diff < 0)
- div = (1 << -diff);
- else if (diff > 0)
- div = (1.0f / (1 << diff));
-
- scale = mapPosition.scale / div;
- dx = (float) (tile.pixelX - mapPosition.x * div);
- dy = (float) (tile.pixelY - mapPosition.y * div);
-
- int size = Tile.TILE_SIZE;
- int sx = (int) (dx * scale);
- int sy = (int) (dy * scale);
-
- // FIXME little hack, need to do scanline check or sth
- // this kindof works for typical screen aspect
- if (mRotate) {
- int ssize = mWidth > mHeight ? mWidth : mHeight;
- ssize += Tile.TILE_SIZE;
- if (sy > ssize / 2 || sx > ssize / 2
- || sx + size * scale < -ssize / 2
- || sy + size * scale < -ssize / 2) {
- tile.isVisible = false;
- return false;
- }
- } else {
- if (sy > mHeight / 2 || sx > mWidth / 2
- || sx + size * scale < -mWidth / 2
- || sy + size * scale < -mHeight / 2) {
- tile.isVisible = false;
- return false;
- }
- }
- tile.isVisible = true;
-
- return true;
- }
-
private static boolean mRotate = false;
private static void setMatrix(float[] matrix, MapTile tile,
float div, boolean project) {
- float x, y, scale;
-
MapPosition mapPosition = mMapPosition;
- scale = mapPosition.scale / (div * COORD_MULTIPLIER);
- x = (float) (tile.pixelX - mapPosition.x * div);
- y = (float) (tile.pixelY - mapPosition.y * 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);
- // scale to tile to world coordinates
- Matrix.scaleM(matrix, 0, scale, scale, 1);
-
// translate relative to map center
- Matrix.translateM(matrix, 0, x * COORD_MULTIPLIER,
- -(y + Tile.TILE_SIZE) * COORD_MULTIPLIER, 0);
+ matrix[12] = x * scale;
+ matrix[13] = y * scale;
+
+ // scale to tile to world coordinates
+ scale /= COORD_MULTIPLIER;
+ matrix[0] = scale;
+ matrix[5] = scale;
if (mRotate)
Matrix.multiplyMM(matrix, 0, mapPosition.rotation, 0, matrix, 0);
@@ -471,11 +471,17 @@ public class GLRenderer implements GLSurfaceView.Renderer {
// prevent main thread recreating all tiles (updateMap)
// while rendering is going. not have seen this happen
// yet though
- GLRenderer.lock.lock();
+ GLRenderer.drawlock.lock();
if (MapView.debugFrameTime)
start = SystemClock.uptimeMillis();
+ if (mUpdateColor) {
+ float cc[] = mClearColor;
+ GLES20.glClearColor(cc[0], cc[1], cc[2], cc[3]);
+ mUpdateColor = false;
+ }
+
// Note: it seems faster to also clear the stencil buffer even
// when not needed. probaly otherwise it is masked out from the
// depth buffer as they share the same memory region afaik
@@ -496,14 +502,17 @@ public class GLRenderer implements GLSurfaceView.Renderer {
}
if (mDrawTiles == null || mDrawTiles.cnt == 0) {
- GLRenderer.lock.unlock();
+ GLRenderer.drawlock.unlock();
return;
}
+ mRotate = mMapView.enableRotation || mMapView.enableCompass;
+
// get current MapPosition, set mTileCoords (mapping of screen to model
// coordinates)
MapPosition mapPosition = mMapPosition;
- boolean changed = mMapViewPosition.getMapPosition(mapPosition, mTileCoords);
+ float[] coords = mTileCoords;
+ boolean changed = mMapViewPosition.getMapPosition(mapPosition, coords);
int tileCnt = mDrawTiles.cnt;
MapTile[] tiles = mDrawTiles.tiles;
@@ -517,29 +526,19 @@ public class GLRenderer implements GLSurfaceView.Renderer {
// zoom-level changed.
float div = scaleDiv(tiles[0]);
- mRotate = mMapView.enableRotation || mMapView.enableCompass;
-
float s = Tile.TILE_SIZE;
float scale = mapPosition.scale / div;
- float px = (float) (mapPosition.x * div);
- float py = (float) (mapPosition.y * div);
+ double px = mapPosition.x * div;
+ double py = mapPosition.y * div;
- mTileCoords[0] = (px + mTileCoords[0] / scale) / s;
- mTileCoords[1] = (py - mTileCoords[1] / scale) / s;
- mTileCoords[2] = (px + mTileCoords[2] / scale) / s;
- mTileCoords[3] = (py - mTileCoords[3] / scale) / s;
- mTileCoords[4] = (px + mTileCoords[4] / scale) / s;
- mTileCoords[5] = (py - mTileCoords[5] / scale) / s;
- mTileCoords[6] = (px + mTileCoords[6] / scale) / s;
- mTileCoords[7] = (py - mTileCoords[7] / scale) / s;
+ for (int i = 0; i < 8; i += 2) {
+ coords[i + 0] = (float) ((px + coords[i + 0] / scale) / s);
+ coords[i + 1] = (float) ((py + coords[i + 1] / scale) / s);
+ }
- byte z = tiles[0].zoomLevel;
- ScanBox.scan(mTileCoords, mDrawTiles, 1 << z);
- }
-
- if (mUpdateColor && mClearColor != null) {
- GLES20.glClearColor(mClearColor[0], mClearColor[1], mClearColor[2], mClearColor[3]);
- mUpdateColor = false;
+ mHolderCount = 0;
+ mScanBox.scan(coords, tiles[0].zoomLevel);
+ tileCnt += mHolderCount;
}
uploadCnt = 0;
@@ -554,15 +553,21 @@ public class GLRenderer implements GLSurfaceView.Renderer {
if (!tile.isVisible)
continue;
- if (tile.texture == null && TextRenderer.drawToTexture(tile))
- updateTextures++;
+ if (MapView.staticLabeling) {
+ if (tile.texture == null && TextRenderer.drawToTexture(tile))
+ updateTextures++;
+ }
if (tile.newData) {
uploadTileData(tile);
continue;
}
-
- if (!tile.isReady) {
+ if (tile.holder != null) {
+ if (tile.holder.newData) {
+ uploadTileData(tile.holder);
+ }
+ tile.isReady = tile.holder.isReady;
+ } else if (!tile.isReady) {
// check near relatives if they can serve as proxy
MapTile rel = tile.rel.parent.tile;
if (rel != null && rel.newData) {
@@ -583,22 +588,26 @@ public class GLRenderer implements GLSurfaceView.Renderer {
if (uploadCnt > 0)
checkBufferUsage();
- if (updateTextures > 0)
- TextRenderer.compileTextures();
+ if (MapView.staticLabeling) {
+ if (updateTextures > 0)
+ TextRenderer.compileTextures();
+ }
GLES20.glEnable(GL_DEPTH_TEST);
GLES20.glEnable(GL_POLYGON_OFFSET_FILL);
for (int i = 0; i < tileCnt; i++) {
- if (tiles[i].isVisible && tiles[i].isReady)
- drawTile(tiles[i]);
+ MapTile t = tiles[i];
+ if (t.isVisible && t.isReady)
+ drawTile(t);
}
// proxies are clipped to the region where nothing was drawn to depth
// buffer. TODO draw all parent before grandparent
for (int i = 0; i < tileCnt; i++) {
- if (tiles[i].isVisible && !tiles[i].isReady)
- drawProxyTile(tiles[i]);
+ MapTile t = tiles[i];
+ if (t.isVisible && !t.isReady && (t.holder == null))
+ drawProxyTile(t);
}
// GlUtils.checkGlError("end draw");
@@ -608,56 +617,52 @@ public class GLRenderer implements GLSurfaceView.Renderer {
mDrawCount = 0;
mDrawSerial++;
- GLES20.glEnable(GL_BLEND);
- int z = mapPosition.zoomLevel;
- float s = mapPosition.scale;
+ if (MapView.staticLabeling) {
+ GLES20.glEnable(GL_BLEND);
+ int z = mapPosition.zoomLevel;
+ float s = mapPosition.scale;
- int zoomLevelDiff = Math.max(z - TileGenerator.STROKE_MAX_ZOOM_LEVEL, 0);
- float scale = (float) Math.pow(1.4, zoomLevelDiff);
- if (scale < 1)
- scale = 1;
+ int zoomLevelDiff = Math.max(z - TileGenerator.STROKE_MAX_ZOOM_LEVEL, 0);
+ float scale = (float) Math.pow(1.4, zoomLevelDiff);
+ if (scale < 1)
+ scale = 1;
- if (z >= TileGenerator.STROKE_MAX_ZOOM_LEVEL)
- TextRenderer.beginDraw(FloatMath.sqrt(s) / scale, mProjMatrix);
- else
- TextRenderer.beginDraw(s, mProjMatrix);
+ if (z >= TileGenerator.STROKE_MAX_ZOOM_LEVEL)
+ TextRenderer.beginDraw(scale / FloatMath.sqrt(s), mProjMatrix);
+ else
+ TextRenderer.beginDraw(1 / s, mProjMatrix);
- for (int i = 0; i < tileCnt; i++) {
- if (!tiles[i].isVisible || tiles[i].texture == null)
- continue;
+ for (int i = 0; i < tileCnt; i++) {
+ MapTile t = tiles[i];
+ if (!t.isVisible)
+ continue;
- setMatrix(mMVPMatrix, tiles[i], 1, false);
- TextRenderer.drawTile(tiles[i], mMVPMatrix);
+ if (t.holder == null) {
+ if (t.texture != null) {
+ setMatrix(mMVPMatrix, t, 1, false);
+ TextRenderer.drawTile(t, mMVPMatrix);
+ }
+ } else {
+ if (t.holder.texture != null) {
+ setMatrix(mMVPMatrix, t, 1, false);
+ TextRenderer.drawTile(t.holder, mMVPMatrix);
+ }
+ }
+ }
+ TextRenderer.endDraw();
}
- TextRenderer.endDraw();
// TODO call overlay renderer here
- // s = 0.5f;
- // mTileCoords[0] = -s;
- // mTileCoords[1] = s;
- // mTileCoords[2] = s;
- // mTileCoords[3] = s;
- // mTileCoords[4] = -s;
- // mTileCoords[5] = -s;
- // mTileCoords[6] = s;
- // mTileCoords[7] = -s;
- //
- // Matrix.setIdentityM(mMVPMatrix, 0);
- // // Matrix.scaleM(mMVPMatrix, 0, 0.99f, 0.99f, 1);
- // // Matrix.multiplyMM(mMVPMatrix, 0, mRotateMatrix, 0, mMVPMatrix, 0);
- // // Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0);
- // PolygonRenderer.debugDraw(mMVPMatrix, mTileCoords);
-
if (MapView.debugFrameTime) {
GLES20.glFinish();
Log.d(TAG, "draw took " + (SystemClock.uptimeMillis() - start));
}
- GLRenderer.lock.unlock();
+ GLRenderer.drawlock.unlock();
}
- // used to not draw a tile twice per frame...
- private static byte mDrawSerial = 0;
+ // used to not draw a tile twice per frame.
+ private static int mDrawSerial = 0;
private static void drawTile(MapTile tile) {
// draw parents only once
@@ -665,15 +670,16 @@ public class GLRenderer implements GLSurfaceView.Renderer {
return;
float div = scaleDiv(tile);
+ float[] mvp = mMVPMatrix;
+ MapPosition pos = mMapPosition;
tile.lastDraw = mDrawSerial;
- int z = mMapPosition.zoomLevel;
- float s = mMapPosition.scale;
- float[] mvp = mMVPMatrix;
-
setMatrix(mvp, tile, div, true);
+ if (tile.holder != null)
+ tile = tile.holder;
+
GLES20.glPolygonOffset(0, mDrawCount++);
GLES20.glBindBuffer(GL_ARRAY_BUFFER, tile.vbo.id);
@@ -696,21 +702,22 @@ public class GLRenderer implements GLSurfaceView.Renderer {
if (pl != null && pnext < lnext) {
GLES20.glDisable(GL_BLEND);
- pl = PolygonRenderer.drawPolygons(pl, lnext, mvp, z, s, !clipped);
+ pl = PolygonRenderer.drawPolygons(pos, pl, lnext, mvp, !clipped);
clipped = true;
} else {
// FIXME
if (!clipped) {
- PolygonRenderer.drawPolygons(null, 0, mvp, z, s, true);
+ PolygonRenderer.drawPolygons(pos, null, 0, mvp, true);
clipped = true;
}
GLES20.glEnable(GL_BLEND);
- ll = LineRenderer.drawLines(tile, ll, pnext, mvp, div, z, s, simpleShader);
+ ll = LineRenderer.drawLines(pos, ll, pnext, mvp, div,
+ simpleShader, tile.lineOffset);
}
}
}
- // TODO could use tile.proxies here
+ // TODO should check tile.proxies here
private static boolean drawProxyChild(MapTile tile) {
int drawn = 0;
for (int i = 0; i < 4; i++) {
@@ -721,10 +728,10 @@ public class GLRenderer implements GLSurfaceView.Renderer {
if (c == null)
continue;
- if (!isVisible(c)) {
- drawn++;
- continue;
- }
+ // if (!isVisible(c)) {
+ // drawn++;
+ // continue;
+ // }
if (c.isReady) {
drawTile(c);
@@ -789,10 +796,11 @@ public class GLRenderer implements GLSurfaceView.Renderer {
mHeight = height;
float s = 0.5f;
- // use this to scale only the view to see which tiles are rendered
+ // use this to scale only the view to see better which tiles are
+ // rendered
// s = 1.0f;
Matrix.frustumM(mProjMatrix, 0, -s * width, s * width,
- -s * height, s * height, 1, 2);
+ s * height, -s * height, 1, 2);
Matrix.translateM(mProjMatrix, 0, 0, 0, -1);
// set to zero: we modify the z value with polygon-offset for clipping
@@ -805,7 +813,6 @@ public class GLRenderer implements GLSurfaceView.Renderer {
mMapView.redrawMap();
return;
}
-
mNewSurface = false;
mBufferMemoryUsage = 0;
@@ -827,17 +834,10 @@ public class GLRenderer implements GLSurfaceView.Renderer {
// Set up textures
TextRenderer.setup(numTiles);
- if (mClearColor != null) {
- GLES20.glClearColor(mClearColor[0], mClearColor[1],
- mClearColor[2], mClearColor[3]);
- } else {
- GLES20.glClearColor(0.98f, 0.98f, 0.97f, 1.0f);
- }
-
- GlUtils.checkGlError("onSurfaceChanged");
-
- GLES20.glClear(GL_STENCIL_BUFFER_BIT);
+ if (mClearColor != null)
+ mUpdateColor = true;
+ // FIXME this should be synchronized
mMapView.redrawMap();
}
@@ -858,6 +858,7 @@ public class GLRenderer implements GLSurfaceView.Renderer {
TextRenderer.init();
mNewSurface = true;
+ // mUpdateColor = true;
// glEnable(GL_SCISSOR_TEST);
// glScissor(0, 0, mWidth, mHeight);
@@ -870,3 +871,46 @@ public class GLRenderer implements GLSurfaceView.Renderer {
private boolean mNewSurface;
}
+
+//
+// private static boolean isVisible(MapTile tile) {
+// float dx, dy, scale, div = 1;
+// MapPosition mapPosition = mMapPosition;
+// int diff = mapPosition.zoomLevel - tile.zoomLevel;
+//
+// if (diff < 0)
+// div = (1 << -diff);
+// else if (diff > 0)
+// div = (1.0f / (1 << diff));
+//
+// scale = mapPosition.scale / div;
+// dx = (float) (tile.pixelX - mapPosition.x * div);
+// dy = (float) (tile.pixelY - mapPosition.y * div);
+//
+// int size = Tile.TILE_SIZE;
+// int sx = (int) (dx * scale);
+// int sy = (int) (dy * scale);
+//
+// // FIXME little hack, need to do scanline check or sth
+// // this kindof works for typical screen aspect
+// if (mRotate) {
+// int ssize = mWidth > mHeight ? mWidth : mHeight;
+// ssize += Tile.TILE_SIZE;
+// if (sy > ssize / 2 || sx > ssize / 2
+// || sx + size * scale < -ssize / 2
+// || sy + size * scale < -ssize / 2) {
+// tile.isVisible = false;
+// return false;
+// }
+// } else {
+// if (sy > mHeight / 2 || sx > mWidth / 2
+// || sx + size * scale < -mWidth / 2
+// || sy + size * scale < -mHeight / 2) {
+// tile.isVisible = false;
+// return false;
+// }
+// }
+// tile.isVisible = true;
+//
+// return true;
+// }
diff --git a/src/org/oscim/view/renderer/LineRenderer.java b/src/org/oscim/view/renderer/LineRenderer.java
index a8b4a2d3..8060eeb6 100644
--- a/src/org/oscim/view/renderer/LineRenderer.java
+++ b/src/org/oscim/view/renderer/LineRenderer.java
@@ -18,6 +18,7 @@ import java.nio.ShortBuffer;
import org.oscim.theme.renderinstruction.Line;
import org.oscim.utils.GlUtils;
+import org.oscim.view.MapPosition;
import android.opengl.GLES20;
import android.util.FloatMath;
@@ -74,26 +75,25 @@ class LineRenderer {
return true;
}
- // static int mSimple = 1;
+ static LineLayer drawLines(MapPosition pos, LineLayer layer, int next,
+ float[] matrix, float div, int mode, int bufferOffset) {
- static LineLayer drawLines(MapTile tile, LineLayer layer, int next, float[] matrix,
- float div, double zoom, float scale, int mode) {
- // int mode = mSimple;
+ int zoom = pos.zoomLevel;
+ float scale = pos.scale;
if (layer == null)
return null;
- // TODO should use fast line program when view is not tilted
GLES20.glUseProgram(lineProgram[mode]);
GLES20.glEnableVertexAttribArray(hLineVertexPosition[mode]);
GLES20.glEnableVertexAttribArray(hLineTexturePosition[mode]);
GLES20.glVertexAttribPointer(hLineVertexPosition[mode], 2, GLES20.GL_SHORT,
- false, 8, tile.lineOffset + LINE_VERTICES_DATA_POS_OFFSET);
+ false, 8, bufferOffset + LINE_VERTICES_DATA_POS_OFFSET);
GLES20.glVertexAttribPointer(hLineTexturePosition[mode], 2, GLES20.GL_SHORT,
- false, 8, tile.lineOffset + LINE_VERTICES_DATA_TEX_OFFSET);
+ false, 8, bufferOffset + LINE_VERTICES_DATA_TEX_OFFSET);
GLES20.glUniformMatrix4fv(hLineMatrix[mode], 1, false, matrix, 0);
diff --git a/src/org/oscim/view/renderer/MapRenderer.java b/src/org/oscim/view/renderer/MapRenderer.java
index 9af9416f..d34bd040 100644
--- a/src/org/oscim/view/renderer/MapRenderer.java
+++ b/src/org/oscim/view/renderer/MapRenderer.java
@@ -17,13 +17,12 @@ package org.oscim.view.renderer;
import java.util.ArrayList;
import java.util.Collections;
-import org.oscim.core.MercatorProjection;
import org.oscim.core.Tile;
-import org.oscim.database.MapInfo;
import org.oscim.theme.RenderTheme;
import org.oscim.utils.GlConfigChooser;
import org.oscim.view.MapPosition;
import org.oscim.view.MapView;
+import org.oscim.view.MapViewPosition;
import org.oscim.view.generator.JobTile;
import android.content.Context;
@@ -37,9 +36,13 @@ public class MapRenderer extends GLSurfaceView {
private GLRenderer mRenderer;
private static final int MAX_TILES_IN_QUEUE = 40;
+ private static final int CACHE_THRESHOLD = 50;
private static MapView mMapView;
+ private static final MapPosition mMapPosition = new MapPosition();
+ private final MapViewPosition mMapViewPosition;
+
// new jobs for the MapWorkers
private static ArrayList mJobList;
@@ -49,16 +52,21 @@ public class MapRenderer extends GLSurfaceView {
// tiles that have new data to upload, see passTile()
private static ArrayList mTilesLoaded;
- // current center tile, values used to check if position has
+ // TODO current boundary tiles, values used to check if position has
// changed for updating current tile list
- private static long mTileX, mTileY;
- private static float mPrevScale;
- private static byte mPrevZoom;
+
private static boolean mInitial;
// private static MapPosition mCurPosition, mDrawPosition;
private static int mWidth = 0, mHeight = 0;
+ // maps zoom-level to available zoom-levels in MapDatabase
+ // e.g. 16->16, 15->16, 14->13, 13->13, 12->13,....
+ // private static int[] mZoomLevels;
+
+ private static float[] mTileCoords = new float[8];
+ private static int[] mBoundaryTiles = new int[8];
+
// used for passing tiles to be rendered from TileLoader(Main-Thread) to
// GLThread
static final class TilesData {
@@ -70,16 +78,61 @@ public class MapRenderer extends GLSurfaceView {
}
}
- private static TilesData mCurrentTiles;
+ /* package */static TilesData mCurrentTiles;
- // maps zoom-level to available zoom-levels in MapDatabase
- // e.g. 16->16, 15->16, 14->13, 13->13, 12->13,....
- private static int[] mZoomLevels;
+ private static ScanBox mScanBox = new ScanBox() {
+
+ @Override
+ void setVisible(int y, int x1, int x2) {
+ MapTile[] tiles = mCurrentTiles.tiles;
+ int cnt = mCurrentTiles.cnt;
+ int max = mCurrentTiles.tiles.length;
+ int xmax = 1 << mZoom;
+
+ for (int x = x1; x < x2; x++) {
+ // MapTile holder = null;
+ MapTile tile = null;
+
+ // boolean found = false;
+ if (cnt == max) {
+ Log.d(TAG, "reached max currentTiles " + max);
+ break;
+ }
+ int xx = x;
+
+ if (x < 0 || x >= xmax) {
+ // flip-around date line
+ if (x < 0)
+ xx = xmax + x;
+ else
+ xx = x - xmax;
+
+ if (xx < 0 || xx >= xmax) {
+ // Log.d(TAG, "tile out of bounds " + y + " " + xx);
+ continue;
+ }
+ }
+
+ for (int i = 0; i < cnt; i++)
+ if (tiles[i].tileX == xx && tiles[i].tileY == y) {
+ tile = tiles[i];
+ break;
+ }
+
+ if (tile == null) {
+ tile = addTile(xx, y, mZoom, 0);
+ tiles[cnt++] = tile;
+ }
+ }
+ mCurrentTiles.cnt = cnt;
+ }
+ };
public MapRenderer(Context context, MapView mapView) {
super(context);
mMapView = mapView;
+ mMapViewPosition = mapView.getMapViewPosition();
Log.d(TAG, "init GLSurfaceLayer");
setEGLConfigChooser(new GlConfigChooser());
@@ -116,16 +169,9 @@ public class MapRenderer extends GLSurfaceView {
if (mMapView == null)
return;
- MapPosition mapPosition = mMapView.getMapPosition().getMapPosition();
-
- if (mapPosition == null) {
- Log.d(TAG, "X no map position");
- return;
- }
-
- if (clear) {
+ if (clear || mInitial) {
// make sure onDrawFrame is not running
- GLRenderer.lock.lock();
+ GLRenderer.drawlock.lock();
// remove all tiles references
Log.d(TAG, "CLEAR");
for (MapTile t : mTiles)
@@ -134,74 +180,71 @@ public class MapRenderer extends GLSurfaceView {
mTiles.clear();
mTilesLoaded.clear();
QuadTree.init();
- mInitial = true;
- GLRenderer.lock.unlock();
- }
-
- if (mInitial) {
// set up TileData arrays that are passed to gl-thread
- int numTiles = (mWidth / (Tile.TILE_SIZE / 2) + 2)
- * (mHeight / (Tile.TILE_SIZE / 2) + 2);
+ int num = mWidth;
+ if (mWidth < mHeight)
+ num = mHeight;
+
+ int size = Tile.TILE_SIZE >> 1;
+
+ int numTiles = (num * num) / (size * size) * 4;
mRenderer.clearTiles(numTiles);
mCurrentTiles = new TilesData(numTiles);
- MapInfo mapInfo = mMapView.getMapDatabase().getMapInfo();
- if (mapInfo != null)
- mZoomLevels = mapInfo.zoomLevel;
- }
+ // MapInfo mapInfo = mMapView.getMapDatabase().getMapInfo();
+ // if (mapInfo != null)
+ // mZoomLevels = mapInfo.zoomLevel;
+ GLRenderer.drawlock.unlock();
- byte zoomLevel = mapPosition.zoomLevel;
- float scale = mapPosition.scale;
-
- long tileX = MercatorProjection.pixelXToTileX(mapPosition.x, zoomLevel)
- * Tile.TILE_SIZE;
- long tileY = MercatorProjection.pixelYToTileY(mapPosition.y, zoomLevel)
- * Tile.TILE_SIZE;
-
- int zdir = 0;
- if (mInitial || mPrevZoom != zoomLevel) {
changedPos = true;
-
- } else if (tileX != mTileX || tileY != mTileY) {
- if (mPrevScale - scale > 0 && scale > 1.2)
- zdir = 1;
- changedPos = true;
-
- } else if (mPrevScale - scale > 0.2 || mPrevScale - scale < -0.2) {
- if (mPrevScale - scale > 0 && scale > 1.2)
- zdir = 1;
- changedPos = true;
- }
-
- if (mInitial) {
mInitial = false;
}
- mTileX = tileX;
- mTileY = tileY;
- mPrevZoom = zoomLevel;
+ MapPosition mapPosition = mMapPosition;
+ mMapViewPosition.getMapPosition(mapPosition, mTileCoords);
- // GLRenderer.updatePosition(mapPosition);
+ float s = Tile.TILE_SIZE;
+ // load some additional tiles more than currently visible
+ float scale = mapPosition.scale * 0.75f;
+ double px = mapPosition.x;
+ double py = mapPosition.y;
+ float[] coords = mTileCoords;
+ int zdir = 0;
- if (!MapView.debugFrameTime)
- requestRender();
+ for (int i = 0; i < 8; i += 2) {
+ coords[i + 0] = (float) ((px + coords[i + 0] / scale) / s);
+ coords[i + 1] = (float) ((py + coords[i + 1] / scale) / s);
+ }
+
+ for (int i = 0; i < 8; i++)
+ if (mBoundaryTiles[i] != (int) coords[i]) {
+ changedPos = true;
+ break;
+ }
+
+ for (int i = 0; i < 8; i++)
+ mBoundaryTiles[i] = (int) coords[i];
+
+ // TODO all following should probably be done in an idler instead
+ // to drain queued events. need to check how android handles things.
if (changedPos) {
- mPrevScale = scale;
-
updateVisibleList(mapPosition, zdir);
if (!MapView.debugFrameTime)
requestRender();
int remove = mTiles.size() - GLRenderer.CACHE_TILES;
- if (remove > 50)
+ if (remove > CACHE_THRESHOLD)
limitCache(mapPosition, remove);
- }
- limitLoadQueue();
+ limitLoadQueue();
+ } else {
+ if (!MapView.debugFrameTime)
+ requestRender();
+ }
}
/**
@@ -214,118 +257,15 @@ public class MapRenderer extends GLSurfaceView {
* zoom direction
*/
private static void updateVisibleList(MapPosition mapPosition, int zdir) {
- double x = mapPosition.x;
- double y = mapPosition.y;
- byte zoomLevel = mapPosition.zoomLevel;
- float scale = mapPosition.scale;
-
- double add = 1.0f / scale;
- int offsetX = (int) ((mWidth >> 1) * add) + Tile.TILE_SIZE;
- int offsetY = (int) ((mHeight >> 1) * add) + Tile.TILE_SIZE;
-
- long pixelRight = (long) x + offsetX;
- long pixelBottom = (long) y + offsetY;
- long pixelLeft = (long) x - offsetX;
- long pixelTop = (long) y - offsetY;
-
- int tileLeft = MercatorProjection.pixelXToTileX(pixelLeft, zoomLevel);
- int tileTop = MercatorProjection.pixelYToTileY(pixelTop, zoomLevel);
- int tileRight = MercatorProjection.pixelXToTileX(pixelRight, zoomLevel);
- int tileBottom = MercatorProjection.pixelYToTileY(pixelBottom, zoomLevel);
mJobList.clear();
-
// set non processed tiles to isLoading == false
mMapView.addJobs(null);
-
- int tiles = 0;
- int max = mCurrentTiles.tiles.length - 1;
-
- boolean fetchChildren = false;
- boolean fetchParent = false;
- boolean fetchProxy = false;
- if (mZoomLevels != null) {
- // check MapDatabase zoom-level-mapping
- if (mZoomLevels[zoomLevel] == 0) {
- mCurrentTiles.cnt = 0;
- mCurrentTiles = GLRenderer.updateTiles(mCurrentTiles);
- return;
- }
-
- if (mZoomLevels[zoomLevel] > zoomLevel) {
- fetchChildren = true;
- fetchProxy = true;
-
- } else if (mZoomLevels[zoomLevel] < zoomLevel) {
- fetchParent = true;
- fetchProxy = true;
- }
- }
-
- for (int yy = tileTop; yy <= tileBottom; yy++) {
- for (int xx = tileLeft; xx <= tileRight; xx++) {
-
- if (tiles == max)
- break;
-
- MapTile tile = QuadTree.getTile(xx, yy, zoomLevel);
-
- if (tile == null) {
- tile = new MapTile(xx, yy, zoomLevel);
-
- QuadTree.add(tile);
- mTiles.add(tile);
- }
-
- if (!fetchProxy && !tile.isActive()) {
- mJobList.add(tile);
- }
-
- mCurrentTiles.tiles[tiles++] = tile;
-
- if (fetchChildren) {
- byte z = (byte) (zoomLevel + 1);
- for (int i = 0; i < 4; i++) {
- int cx = (xx << 1) + (i % 2);
- int cy = (yy << 1) + (i >> 1);
-
- MapTile c = QuadTree.getTile(cx, cy, z);
-
- if (c == null) {
- c = new MapTile(cx, cy, z);
-
- QuadTree.add(c);
- mTiles.add(c);
- }
-
- if (!c.isActive()) {
- mJobList.add(c);
- }
- }
- }
-
- if (fetchParent || (!fetchProxy && zdir > 0 && zoomLevel > 0)) {
- // prefetch parent
- MapTile p = tile.rel.parent.tile;
-
- if (p == null) {
- p = new MapTile(xx >> 1, yy >> 1, (byte) (zoomLevel - 1));
-
- QuadTree.add(p);
- mTiles.add(p);
- mJobList.add(p);
-
- } else if (!p.isActive()) {
- if (!mJobList.contains(p))
- mJobList.add(p);
- }
- }
- }
- }
-
- // pass new tile list to glThread
- mCurrentTiles.cnt = tiles;
- mCurrentTiles = GLRenderer.updateTiles(mCurrentTiles);
+ mCurrentTiles.cnt = 0;
+ mScanBox.scan(mTileCoords, mapPosition.zoomLevel);
+ // Log.d(TAG, "visible: " + mCurrentTiles.cnt + "/" +
+ // mCurrentTiles.tiles.length);
+ GLRenderer.updateTiles(mCurrentTiles);
// note: this sets isLoading == true for all job tiles
if (mJobList.size() > 0) {
@@ -335,6 +275,67 @@ public class MapRenderer extends GLSurfaceView {
}
}
+ /* package */
+ static MapTile addTile(int x, int y, byte zoomLevel, int zdir) {
+ MapTile tile;
+
+ tile = QuadTree.getTile(x, y, zoomLevel);
+
+ if (tile == null) {
+ tile = new MapTile(x, y, zoomLevel);
+
+ QuadTree.add(tile);
+ mTiles.add(tile);
+ }
+
+ // if (!fetchProxy && !tile.isActive()) {
+ if (!tile.isActive()) {
+ mJobList.add(tile);
+ }
+
+ // mCurrentTiles.tiles[tiles++] = tile;
+
+ // if (fetchChildren) {
+ // byte z = (byte) (zoomLevel + 1);
+ // for (int i = 0; i < 4; i++) {
+ // int cx = (xx << 1) + (i % 2);
+ // int cy = (yy << 1) + (i >> 1);
+ //
+ // MapTile c = QuadTree.getTile(cx, cy, z);
+ //
+ // if (c == null) {
+ // c = new MapTile(cx, cy, z);
+ //
+ // QuadTree.add(c);
+ // mTiles.add(c);
+ // }
+ //
+ // if (!c.isActive()) {
+ // mJobList.add(c);
+ // }
+ // }
+ // }
+
+ // if (fetchParent || (!fetchProxy && zdir > 0 && zoomLevel > 0)) {
+ if (zdir > 0 && zoomLevel > 0) {
+ // prefetch parent
+ MapTile p = tile.rel.parent.tile;
+
+ if (p == null) {
+ p = new MapTile(x >> 1, y >> 1, (byte) (zoomLevel - 1));
+
+ QuadTree.add(p);
+ mTiles.add(p);
+ mJobList.add(p);
+
+ } else if (!p.isActive()) {
+ if (!mJobList.contains(p))
+ mJobList.add(p);
+ }
+ }
+ return tile;
+ }
+
private static void clearTile(MapTile t) {
t.newData = false;
@@ -407,8 +408,6 @@ public class MapRenderer extends GLSurfaceView {
}
private static void limitCache(MapPosition mapPosition, int remove) {
- int removes = remove;
-
int size = mTiles.size();
// remove orphaned tiles
@@ -418,44 +417,46 @@ public class MapRenderer extends GLSurfaceView {
if (t.isLocked() || t.isActive()) {
i++;
} else {
- // Log.d(TAG, "remove empty tile" + cur);
+ // Log.d(TAG, "remove empty tile" + t);
clearTile(t);
mTiles.remove(i);
- removes--;
+ remove--;
size--;
}
}
- // Log.d(TAG, "remove tiles: " + removes + " " + size);
-
- if (removes <= 0)
+ if (remove <= 0)
return;
updateTileDistances(mTiles, mapPosition);
Collections.sort(mTiles);
- for (int i = 1; i <= removes; i++) {
+ for (int i = 1; i < remove; i++) {
MapTile t = mTiles.remove(size - i);
synchronized (t) {
if (t.isLocked()) {
// dont remove tile used by renderthread
- Log.d(TAG, "X not removing " + t + " " + t.isLocked + " "
- + t.distance);
+ Log.d(TAG, "X not removing " + t
+ // + " " + t.isLocked
+ + " " + t.distance);
mTiles.add(t);
-
- // } else if (t.isLoading) {
- // // FIXME if we add tile back on next limit cache
- // // this will be removed. clearTile could interfere with
- // // MapGenerator... clear in passTile().
- // Log.d(TAG, "X cancel loading " + t + " " + t.distance);
- // t.isLoading = false;
- // // mTiles.add(t);
- } else {
- clearTile(t);
+ continue;
}
+
+ if (t.isLoading) {
+ // NOTE: if we add tile back then on next limitCache
+ // the tile will be removed. clearTile could interfere with
+ // MapGenerator. so clear in passTile() instead.
+ // mTiles.add(t);
+ t.isLoading = false;
+ Log.d(TAG, "X cancel loading " + t + " " + t.distance);
+ continue;
+ }
+
+ clearTile(t);
}
}
}
@@ -524,8 +525,8 @@ public class MapRenderer extends GLSurfaceView {
MapTile tile = (MapTile) jobTile;
if (!tile.isLoading) {
- // no one should be able to use this tile now, mapgenerator passed
- // it, glthread does nothing until newdata is set.
+ // no one should be able to use this tile now, TileGenerator passed
+ // it, GL-Thread does nothing until newdata is set.
Log.d(TAG, "passTile: canceled " + tile);
synchronized (mTilesLoaded) {
mTilesLoaded.add(tile);
@@ -573,4 +574,78 @@ public class MapRenderer extends GLSurfaceView {
super.onSizeChanged(w, h, oldw, oldh);
}
+ // private static void updateVisibleList(MapPosition mapPosition, int zdir)
+ // {
+ // double x = mapPosition.x;
+ // double y = mapPosition.y;
+ // byte zoomLevel = mapPosition.zoomLevel;
+ // float scale = mapPosition.scale;
+ //
+ // double add = 1.0f / scale;
+ // int offsetX = (int) ((mWidth >> 1) * add) + Tile.TILE_SIZE;
+ // int offsetY = (int) ((mHeight >> 1) * add) + Tile.TILE_SIZE;
+ //
+ // long pixelRight = (long) x + offsetX;
+ // long pixelBottom = (long) y + offsetY;
+ // long pixelLeft = (long) x - offsetX;
+ // long pixelTop = (long) y - offsetY;
+ //
+ // int tileLeft = MercatorProjection.pixelXToTileX(pixelLeft, zoomLevel);
+ // int tileTop = MercatorProjection.pixelYToTileY(pixelTop, zoomLevel);
+ // int tileRight = MercatorProjection.pixelXToTileX(pixelRight, zoomLevel);
+ // int tileBottom = MercatorProjection.pixelYToTileY(pixelBottom,
+ // zoomLevel);
+ //
+ // mJobList.clear();
+ //
+ // // set non processed tiles to isLoading == false
+ // mMapView.addJobs(null);
+ //
+ // int tiles = 0;
+ // int max = mCurrentTiles.tiles.length - 1;
+ //
+ // // boolean fetchChildren = false;
+ // // boolean fetchParent = false;
+ // // boolean fetchProxy = false;
+ // // if (mZoomLevels != null) {
+ // // // check MapDatabase zoom-level-mapping
+ // // if (mZoomLevels[zoomLevel] == 0) {
+ // // mCurrentTiles.cnt = 0;
+ // // mCurrentTiles = GLRenderer.updateTiles(mCurrentTiles);
+ // // return;
+ // // }
+ // //
+ // // if (mZoomLevels[zoomLevel] > zoomLevel) {
+ // // fetchChildren = true;
+ // // fetchProxy = true;
+ // //
+ // // } else if (mZoomLevels[zoomLevel] < zoomLevel) {
+ // // fetchParent = true;
+ // // fetchProxy = true;
+ // // }
+ // // }
+ //
+ // for (int yy = tileTop; yy <= tileBottom; yy++) {
+ // for (int xx = tileLeft; xx <= tileRight; xx++) {
+ //
+ // if (tiles == max)
+ // break;
+ //
+ // // MapTile tile =
+ // addTile(xx, yy, zoomLevel, zdir);
+ // // mCurrentTiles.tiles[tiles++] = tile;
+ // }
+ // }
+ //
+ // // pass new tile list to glThread
+ // mCurrentTiles.cnt = tiles;
+ // mCurrentTiles = GLRenderer.updateTiles(mCurrentTiles);
+ //
+ // // note: this sets isLoading == true for all job tiles
+ // if (mJobList.size() > 0) {
+ // updateTileDistances(mJobList, mapPosition);
+ // Collections.sort(mJobList);
+ // mMapView.addJobs(mJobList);
+ // }
+ // }
}
diff --git a/src/org/oscim/view/renderer/MapTile.java b/src/org/oscim/view/renderer/MapTile.java
index a8845808..202cfec0 100644
--- a/src/org/oscim/view/renderer/MapTile.java
+++ b/src/org/oscim/view/renderer/MapTile.java
@@ -41,7 +41,7 @@ class MapTile extends JobTile {
/**
* tile is used by render thread. set by updateVisibleList (main thread).
*/
- boolean isLocked;
+ // boolean isLocked;
/**
* tile has new data to upload to gl
@@ -63,29 +63,38 @@ class MapTile extends JobTile {
*/
QuadTree rel;
- byte lastDraw = 0;
+ int lastDraw = 0;
// keep track which tiles are locked as proxy for this tile
final static int PROXY_PARENT = 16;
final static int PROXY_GRAMPA = 32;
+ final static int PROXY_HOLDER = 64;
// 1-8: children
byte proxies;
// counting the tiles that use this tile as proxy
byte refs;
+ byte locked;
+
+ // this tile sits in fo another tile. e.g. x:-1,y:0,z:1 for x:1,y:0
+ MapTile holder;
+
boolean isActive() {
return isLoading || newData || isReady;
}
boolean isLocked() {
- return isLocked || refs > 0;
+ return locked > 0 || refs > 0;
}
void lock() {
- isLocked = true;
+ if (holder != null)
+ return;
- if (isReady || newData)
+ locked++;
+
+ if (locked > 1 || isReady || newData)
return;
MapTile p = rel.parent.tile;
@@ -113,9 +122,12 @@ class MapTile extends JobTile {
}
void unlock() {
- isLocked = false;
+ if (holder != null)
+ return;
- if (proxies == 0)
+ locked--;
+
+ if (locked > 0 || proxies == 0)
return;
if ((proxies & (1 << 4)) != 0) {
diff --git a/src/org/oscim/view/renderer/PolygonRenderer.java b/src/org/oscim/view/renderer/PolygonRenderer.java
index a423e25e..f2bd343d 100644
--- a/src/org/oscim/view/renderer/PolygonRenderer.java
+++ b/src/org/oscim/view/renderer/PolygonRenderer.java
@@ -41,15 +41,18 @@ import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import org.oscim.utils.GlUtils;
+import org.oscim.view.MapPosition;
import android.opengl.GLES20;
class PolygonRenderer {
- private static final String TAG = "PolygonRenderer";
+ // private static final String TAG = "PolygonRenderer";
private static final int NUM_VERTEX_SHORTS = 2;
private static final int POLYGON_VERTICES_DATA_POS_OFFSET = 0;
- private static int STENCIL_BITS = 8;
+ private static final int STENCIL_BITS = 8;
+
+ private static final float FADE_START = 1.3f;
private static PolygonLayer[] mFillPolys;
@@ -76,7 +79,7 @@ class PolygonRenderer {
return true;
}
- private static void fillPolygons(double zoom, float scale) {
+ private static void fillPolygons(int zoom, float scale) {
boolean blend = false;
/* draw to framebuffer */
@@ -96,7 +99,7 @@ class PolygonRenderer {
if (l.area.fade >= zoom || l.area.color[3] != 1.0) {
/* fade in/out || draw alpha color */
if (l.area.fade >= zoom) {
- f = (scale > 1.3f ? scale : 1.3f) - f;
+ f = (scale > FADE_START ? scale : FADE_START) - f;
if (f > 1.0f)
f = 1.0f;
}
@@ -159,8 +162,11 @@ class PolygonRenderer {
// stencil buffer index to start fill
private static int mStart;
- static PolygonLayer drawPolygons(final PolygonLayer layer, final int next,
- final float[] matrix, final double zoom, final float scale, boolean first) {
+ static PolygonLayer drawPolygons(MapPosition pos, PolygonLayer layer, int next,
+ float[] matrix, boolean first) {
+
+ int zoom = pos.zoomLevel;
+ float scale = pos.scale;
glUseProgram(polygonProgram);
GLES20.glEnableVertexAttribArray(hPolygonVertexPosition);
diff --git a/src/org/oscim/view/renderer/ScanBox.java b/src/org/oscim/view/renderer/ScanBox.java
index ba8c22da..75778091 100644
--- a/src/org/oscim/view/renderer/ScanBox.java
+++ b/src/org/oscim/view/renderer/ScanBox.java
@@ -17,23 +17,10 @@
package org.oscim.view.renderer;
-import org.oscim.view.renderer.MapRenderer.TilesData;
-
import android.util.FloatMath;
+import android.util.Log;
-public class ScanBox {
-
- interface Callback {
- void call(MapTile tile);
- }
-
- class SetVisible implements Callback {
-
- @Override
- public void call(MapTile tile) {
- tile.isVisible = true;
- }
- }
+public abstract class ScanBox {
static class Edge {
float x0, y0, x1, y1, dx, dy;
@@ -44,84 +31,50 @@ public class ScanBox {
this.y0 = y0;
this.x1 = x1;
this.y1 = y1;
- this.dx = x1 - x0;
- this.dy = y1 - y0;
+ dx = x1 - x0;
+ dy = y1 - y0;
} else {
this.x0 = x1;
this.y0 = y1;
this.x1 = x0;
this.y1 = y0;
- this.dx = x0 - x1;
- this.dy = y0 - y1;
+ dx = x0 - x1;
+ dy = y0 - y1;
}
}
}
- static Edge ab = new Edge();
- static Edge bc = new Edge();
- static Edge ca = new Edge();
+ private Edge ab = new Edge();
+ private Edge bc = new Edge();
+ private Edge ca = new Edge();
+ protected byte mZoom;
- static void scanSpans(Edge e0, Edge e1) {
+ void scan(float[] coords, byte zoom) {
+ mZoom = zoom;
- // sort edge by x-coordinate
- if (e0.x0 == e1.x0 && e0.y0 == e1.y0) {
- if (e0.x0 + e1.dy / e0.dy * e0.dx < e1.x1) {
- Edge t = e0;
- e0 = e1;
- e1 = t;
- }
- } else {
- if (e0.x1 - e1.dy / e0.dy * e0.dx < e1.x0) {
- Edge t = e0;
- e0 = e1;
- e1 = t;
- }
- }
+ ab.set(coords[0], coords[1], coords[2], coords[3]);
+ bc.set(coords[2], coords[3], coords[4], coords[5]);
+ ca.set(coords[4], coords[5], coords[0], coords[1]);
+ scanTriangle();
- float m0 = e0.dx / e0.dy;
- float m1 = e1.dx / e1.dy;
-
- int d0 = e0.dx > 0 ? 1 : 0;// use y + 1 to compute x0
- int d1 = e1.dx < 0 ? 1 : 0; // use y + 1 to compute x1
-
- float x0, x1;
-
- int y = (int) Math.max(0, FloatMath.floor(e1.y0));
- int bottom = (int) Math.min(mMax, FloatMath.ceil(e1.y1));
-
- for (; y < bottom; y++) {
- // float x0 = (m0 * Math.min(e0.dy, y + d0 - e0.y0) + e0.x0);
- // float x1 = (m1 * Math.min(e1.dy, y + d1 - e1.y0) + e1.x0);
-
- x0 = y + d0 - e0.y0;
- if (e0.dy < x0)
- x0 = e0.dy;
-
- x0 = e0.x0 + m0 * x0;
-
- if (x0 < 0)
- x0 = 0;
- else
- x0 = FloatMath.ceil(x0);
-
- x1 = y + d1 - e1.y0;
- if (e1.dy < x1)
- x1 = e1.dy;
-
- x1 = e1.x0 + m1 * x1;
-
- if (x1 < 0)
- x1 = 0;
- else
- x1 = FloatMath.floor(x1);
-
- setVisible(y, (int) x1, (int) x0);
-
- // setVisible(y, (int) (x1 - 0.5f), (int) (x0 + 0.5f));
- }
+ ab.set(coords[4], coords[5], coords[6], coords[7]);
+ bc.set(coords[6], coords[7], coords[0], coords[1]);
+ ca.set(coords[0], coords[1], coords[4], coords[5]);
+ scanTriangle();
}
- static void scanTriangle() {
+ /**
+ * @param y
+ * ...
+ * @param x1
+ * ...
+ * @param x2
+ * ...
+ */
+ void setVisible(int y, int x1, int x2) {
+ }
+
+ private void scanTriangle() {
if (ab.dy > bc.dy) {
Edge t = ab;
@@ -138,6 +91,10 @@ public class ScanBox {
bc = ca;
ca = t;
}
+ // ca.dy > bc.dy > ab.dy
+
+ if (ca.dy == 0)
+ return;
if (ab.dy != 0)
scanSpans(ca, ab);
@@ -146,42 +103,68 @@ public class ScanBox {
scanSpans(ca, bc);
}
- private static int mMax;
+ private static final int MAX_SLOPE = 4;
- public static void scan(float[] coords, TilesData tiles, int max) {
- sTiles = tiles;
- cntDoubles = 0;
- mMax = max;
+ private void scanSpans(Edge e0, Edge e1) {
- ab.set(coords[0], coords[1], coords[2], coords[3]);
- bc.set(coords[2], coords[3], coords[4], coords[5]);
- ca.set(coords[4], coords[5], coords[0], coords[1]);
- scanTriangle();
+ int y0 = (int) Math.max(0, FloatMath.floor(e1.y0));
+ int y1 = (int) Math.min((1 << mZoom), FloatMath.ceil(e1.y1));
- ab.set(coords[4], coords[5], coords[6], coords[7]);
- bc.set(coords[6], coords[7], coords[0], coords[1]);
- ca.set(coords[0], coords[1], coords[4], coords[5]);
- scanTriangle();
-
- // Log.d("..", "= x1 && tiles[i].tileX < x2) {
- // if (tiles[i].isVisible) {
- // Log.d("..", ">>>" + y + " " + tiles[i].tileX);
- // cntDoubles++;
- // }
- tiles[i].isVisible = true;
- }
+ // sort edge by x-coordinate
+ if (e0.x0 == e1.x0 && e0.y0 == e1.y0) {
+ // bottom-flat
+ if (e0.x0 + e1.dy / e0.dy * e0.dx < e1.x1) {
+ Edge t = e0;
+ e0 = e1;
+ e1 = t;
}
+ } else {
+ // top-flat
+ if (e0.x1 - e1.dy / e0.dy * e0.dx < e1.x0) {
+ Edge t = e0;
+ e0 = e1;
+ e1 = t;
+ }
+ }
+
+ float m0 = e0.dx / e0.dy;
+ float m1 = e1.dx / e1.dy;
+
+ // still needed?
+ if (m0 > MAX_SLOPE)
+ m0 = MAX_SLOPE;
+ else if (m0 < -MAX_SLOPE)
+ m0 = -MAX_SLOPE;
+
+ if (m1 > MAX_SLOPE)
+ m1 = MAX_SLOPE;
+ else if (m1 < -MAX_SLOPE)
+ m1 = -MAX_SLOPE;
+
+ int d0 = e0.dx > 0 ? 1 : 0; // use y + 1 to compute x0
+ int d1 = e1.dx < 0 ? 1 : 0; // use y + 1 to compute x1
+
+ float x0, x1, dy;
+
+ for (int y = y0; y < y1; y++) {
+ dy = y + d0 - e0.y0;
+ if (e0.dy < dy)
+ dy = e0.dy;
+
+ x0 = e0.x0 + m0 * dy;
+ x0 = FloatMath.ceil(x0);
+
+ dy = y + d1 - e1.y0;
+ if (e1.dy < dy)
+ dy = e1.dy;
+
+ x1 = e1.x0 + m1 * dy;
+ x1 = FloatMath.floor(x1);
+
+ if (x1 > x0)
+ Log.d("...", "X set visible" + y + " " + x1 + "/" + x0);
+
+ setVisible(y, (int) x1, (int) x0);
}
}
}
diff --git a/src/org/oscim/view/renderer/Shaders.java b/src/org/oscim/view/renderer/Shaders.java
index 398dd787..d0204044 100644
--- a/src/org/oscim/view/renderer/Shaders.java
+++ b/src/org/oscim/view/renderer/Shaders.java
@@ -19,7 +19,6 @@ class Shaders {
final static String lineVertexShader = ""
+ "precision mediump float;"
- // + "invariant gl_Position;"
+ "uniform mat4 u_mvp;"
+ "uniform float u_width;"
+ "attribute vec2 a_position;"
@@ -111,20 +110,20 @@ class Shaders {
+ "precision highp float; "
+ "attribute vec4 vertex;"
+ "attribute vec2 tex_coord;"
- + "uniform mat4 mvp;"
- + "uniform mat4 rotation;"
- + "uniform float scale;"
+ + "uniform mat4 u_mv;"
+ + "uniform mat4 u_proj;"
+ + "uniform float u_scale;"
+ "varying vec2 tex_c;"
+ "const vec2 div = vec2(1.0/4096.0,1.0/2048.0);"
+ "const float coord_scale = 0.125;"
+ "void main() {"
+ " vec4 pos;"
+ " if (mod(vertex.x, 2.0) == 0.0){"
- + " pos = rotation * (mvp * vec4(vertex.xy + vertex.zw * (1.0 / scale), 0.0, 1.0));"
+ + " pos = u_proj * (u_mv * vec4(vertex.xy + vertex.zw * u_scale, 0.0, 1.0));"
+ " } else {"
// place as billboard
- + " vec4 dir = mvp * vec4(vertex.xy, 0.0, 1.0);"
- + " pos = rotation * (dir + vec4(vertex.zw * coord_scale, 0.0, 0.0));"
+ + " vec4 dir = u_mv * vec4(vertex.xy, 0.0, 1.0);"
+ + " pos = u_proj * (dir + vec4(vertex.zw * coord_scale, 0.0, 0.0));"
+ " }"
+ " gl_Position = pos;"
+ " tex_c = tex_coord * div;"
@@ -175,7 +174,6 @@ class Shaders {
final static String textFragmentShader = ""
+ "precision highp float;"
+ "uniform sampler2D tex;"
- + "uniform vec4 col;"
+ "varying vec2 tex_c;"
+ "void main() {"
+ " gl_FragColor = texture2D(tex, tex_c.xy);"
diff --git a/src/org/oscim/view/renderer/TextRenderer.java b/src/org/oscim/view/renderer/TextRenderer.java
index eba3e990..4b25eb39 100644
--- a/src/org/oscim/view/renderer/TextRenderer.java
+++ b/src/org/oscim/view/renderer/TextRenderer.java
@@ -54,8 +54,8 @@ public class TextRenderer {
private static int mVerticesVBO;
private static int mTextProgram;
- private static int hTextUVPMatrix;
- private static int hTextRotationMatrix;
+ private static int hTextMVMatrix;
+ private static int hTextProjectionMatrix;
private static int hTextVertex;
private static int hTextScale;
private static int hTextTextureCoord;
@@ -83,11 +83,10 @@ public class TextRenderer {
mTextProgram = GlUtils.createProgram(Shaders.textVertexShader,
Shaders.textFragmentShader);
- hTextUVPMatrix = GLES20.glGetUniformLocation(mTextProgram, "mvp");
- hTextRotationMatrix = GLES20.glGetUniformLocation(mTextProgram, "rotation");
-
+ hTextMVMatrix = GLES20.glGetUniformLocation(mTextProgram, "u_mv");
+ hTextProjectionMatrix = GLES20.glGetUniformLocation(mTextProgram, "u_proj");
+ hTextScale = GLES20.glGetUniformLocation(mTextProgram, "u_scale");
hTextVertex = GLES20.glGetAttribLocation(mTextProgram, "vertex");
- hTextScale = GLES20.glGetUniformLocation(mTextProgram, "scale");
hTextTextureCoord = GLES20.glGetAttribLocation(mTextProgram, "tex_coord");
}
@@ -150,12 +149,6 @@ public class TextRenderer {
indices[i + 3] = (short) (j + 2);
indices[i + 4] = (short) (j + 3);
indices[i + 5] = (short) (j + 0);
- // indices[i + 0] = (short) (j + 0);
- // indices[i + 1] = (short) (j + 0);
- // indices[i + 2] = (short) (j + 1);
- // indices[i + 3] = (short) (j + 3);
- // indices[i + 4] = (short) (j + 2);
- // indices[i + 5] = (short) (j + 2);
}
mShortBuffer.clear();
@@ -192,7 +185,7 @@ public class TextRenderer {
if (tex.tile == null)
break;
- if (!tex.tile.isLocked)
+ if (!tex.tile.isLocked())
break;
tex = null;
@@ -293,11 +286,10 @@ public class TextRenderer {
if (t.caption != null) {
x1 = x3 = (short) (SCALE * (-hw));
- y1 = y3 = (short) (SCALE * (-hh));
+ y1 = y3 = (short) (SCALE * (hh));
x2 = x4 = (short) (SCALE * (hw));
- y2 = y4 = (short) (SCALE * (hh));
- }
- else {
+ y2 = y4 = (short) (SCALE * (-hh));
+ } else {
float vx = t.x1 - t.x2;
float vy = t.y1 - t.y2;
float a = FloatMath.sqrt(vx * vx + vy * vy);
@@ -322,14 +314,14 @@ public class TextRenderer {
// x3 = (short) (dx | 2);
// y2 = (short) (dy | 2);
- x1 = (short) (SCALE * (vx * hw + ux * hh));
- y1 = (short) (SCALE * (vy * hw + uy * hh));
- x2 = (short) (SCALE * (-vx * hw + ux * hh));
- y3 = (short) (SCALE * (-vy * hw + uy * hh));
- x4 = (short) (SCALE * (-vx * hw - ux * hh));
- y4 = (short) (SCALE * (-vy * hw - uy * hh));
- x3 = (short) (SCALE * (vx * hw - ux * hh));
- y2 = (short) (SCALE * (vy * hw - uy * hh));
+ x1 = (short) (SCALE * (vx * hw - ux * hh));
+ y1 = (short) (SCALE * (vy * hw - uy * hh));
+ x2 = (short) (SCALE * (-vx * hw - ux * hh));
+ y3 = (short) (SCALE * (-vy * hw - uy * hh));
+ x4 = (short) (SCALE * (-vx * hw + ux * hh));
+ y4 = (short) (SCALE * (-vy * hw + uy * hh));
+ x3 = (short) (SCALE * (vx * hw + ux * hh));
+ y2 = (short) (SCALE * (vy * hw + uy * hh));
}
short u1 = (short) (SCALE * x);
@@ -394,7 +386,8 @@ public class TextRenderer {
GLUtils.texSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, mBitmap,
mBitmapFormat, mBitmapType);
- // FIXME shouldnt be needed here, still looking for sometimes corrupted labels..
+ // FIXME shouldnt be needed here, still looking for sometimes corrupted
+ // labels..
GLES20.glFlush();
return true;
@@ -412,7 +405,7 @@ public class TextRenderer {
for (int i = 0; i < mTextures.length; i++) {
tex = mTextures[i];
- if (tex.tile == null || !tex.tile.isLocked)
+ if (tex.tile == null) // || !tex.tile.isLocked)
continue;
mShortBuffer.put(tex.vertices, 0, tex.length);
@@ -426,14 +419,14 @@ public class TextRenderer {
mShortBuffer);
}
- static void beginDraw(float scale, float[] rotation) {
+ static void beginDraw(float scale, float[] projection) {
GLES20.glUseProgram(mTextProgram);
GLES20.glEnableVertexAttribArray(hTextTextureCoord);
GLES20.glEnableVertexAttribArray(hTextVertex);
GLES20.glUniform1f(hTextScale, scale);
- GLES20.glUniformMatrix4fv(hTextRotationMatrix, 1, false, rotation, 0);
+ GLES20.glUniformMatrix4fv(hTextProjectionMatrix, 1, false, projection, 0);
if (debug) {
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
@@ -461,7 +454,7 @@ public class TextRenderer {
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, tile.texture.id);
- GLES20.glUniformMatrix4fv(hTextUVPMatrix, 1, false, matrix, 0);
+ GLES20.glUniformMatrix4fv(hTextMVMatrix, 1, false, matrix, 0);
if (debug) {
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
diff --git a/src/org/oscim/view/renderer/WayDecorator.java b/src/org/oscim/view/renderer/WayDecorator.java
index 9d26f813..746471b7 100644
--- a/src/org/oscim/view/renderer/WayDecorator.java
+++ b/src/org/oscim/view/renderer/WayDecorator.java
@@ -136,8 +136,8 @@ final class WayDecorator {
} else if ((currentY - nextY) == 0)
break;
- float diff = ((diffX) / (diffY) - (float) (currentX - nextX)
- / (currentY - nextY));
+ float diff = diffX / diffY -
+ (float) (currentX - nextX) / (currentY - nextY);
// skip segments with corners
if (diff >= 0.1f || diff <= -0.1f)
@@ -221,8 +221,8 @@ final class WayDecorator {
// check overlapping labels of road with more than one
// way
- short top2 = (t2.y1 < t2.y2 ? t2.y1 : t2.y2);
- short bot2 = (t2.y1 < t2.y2 ? t2.y2 : t2.y1);
+ short top2 = t2.y1 < t2.y2 ? t2.y1 : t2.y2;
+ short bot2 = t2.y1 < t2.y2 ? t2.y2 : t2.y1;
if (x1 - 10 < t2.x2 && t2.x1 - 10 < x2 && top - 10 < bot2
&& top2 - 10 < bot) {
@@ -240,7 +240,8 @@ final class WayDecorator {
continue;
}
- // Log.d("mapsforge", "add " + text + " " + first + " " + last);
+ // Log.d("mapsforge", "add " + text + " " + first + " " +
+ // last);
if (previousX < currentX) {
x1 = previousX;