- remove swrenderer
- rearchitect: now that MapView is a ViewGroup and MapRenderer is the GLSurfaceView. - lock/unlock proxy tiles properly to not be removed from cache while in use
This commit is contained in:
52
src/org/oscim/utils/AndroidUtils.java
Normal file
52
src/org/oscim/utils/AndroidUtils.java
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.oscim.utils;
|
||||
|
||||
import android.os.Build;
|
||||
import android.os.Looper;
|
||||
|
||||
/**
|
||||
* A utility class with Android-specific helper methods.
|
||||
*/
|
||||
public final class AndroidUtils {
|
||||
/**
|
||||
* Build names to detect the emulator from the Android SDK.
|
||||
*/
|
||||
private static final String[] EMULATOR_NAMES = { "google_sdk", "sdk" };
|
||||
|
||||
/**
|
||||
* @return true if the application is running on the Android emulator, false otherwise.
|
||||
*/
|
||||
public static boolean applicationRunsOnAndroidEmulator() {
|
||||
for (int i = 0, n = EMULATOR_NAMES.length; i < n; ++i) {
|
||||
if (Build.PRODUCT.equals(EMULATOR_NAMES[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the current thread is the UI thread, false otherwise.
|
||||
*/
|
||||
public static boolean currentThreadIsUiThread() {
|
||||
return Looper.getMainLooper().getThread() == Thread.currentThread();
|
||||
}
|
||||
|
||||
private AndroidUtils() {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
1808
src/org/oscim/utils/GLSurfaceView.java
Normal file
1808
src/org/oscim/utils/GLSurfaceView.java
Normal file
File diff suppressed because it is too large
Load Diff
278
src/org/oscim/utils/GeometryUtils.java
Normal file
278
src/org/oscim/utils/GeometryUtils.java
Normal file
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.oscim.utils;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
public final class GeometryUtils {
|
||||
/**
|
||||
* Calculates the center of the minimum bounding rectangle for the given coordinates.
|
||||
*
|
||||
* @param coordinates
|
||||
* the coordinates for which calculation should be done.
|
||||
* @return the center coordinates of the minimum bounding rectangle.
|
||||
*/
|
||||
static float[] calculateCenterOfBoundingBox(float[] coordinates) {
|
||||
float longitudeMin = coordinates[0];
|
||||
float longitudeMax = coordinates[0];
|
||||
float latitudeMax = coordinates[1];
|
||||
float latitudeMin = coordinates[1];
|
||||
|
||||
for (int i = 2; i < coordinates.length; i += 2) {
|
||||
if (coordinates[i] < longitudeMin) {
|
||||
longitudeMin = coordinates[i];
|
||||
} else if (coordinates[i] > longitudeMax) {
|
||||
longitudeMax = coordinates[i];
|
||||
}
|
||||
|
||||
if (coordinates[i + 1] < latitudeMin) {
|
||||
latitudeMin = coordinates[i + 1];
|
||||
} else if (coordinates[i + 1] > latitudeMax) {
|
||||
latitudeMax = coordinates[i + 1];
|
||||
}
|
||||
}
|
||||
|
||||
return new float[] { (longitudeMin + longitudeMax) / 2, (latitudeMax + latitudeMin) / 2 };
|
||||
}
|
||||
|
||||
/**
|
||||
* @param way
|
||||
* the coordinates of the way.
|
||||
* @return true if the given way is closed, false otherwise.
|
||||
*/
|
||||
static boolean isClosedWay(float[] way) {
|
||||
return Float.compare(way[0], way[way.length - 2]) == 0 && Float.compare(way[1], way[way.length - 1]) == 0;
|
||||
}
|
||||
|
||||
private GeometryUtils() {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
static boolean linesIntersect(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) {
|
||||
// Return false if either of the lines have zero length
|
||||
if (x1 == x2 && y1 == y2 || x3 == x4 && y3 == y4) {
|
||||
return false;
|
||||
}
|
||||
// Fastest method, based on Franklin Antonio's
|
||||
// "Faster Line Segment Intersection" topic "in Graphics Gems III" book
|
||||
// (http://www.graphicsgems.org/)
|
||||
double ax = x2 - x1;
|
||||
double ay = y2 - y1;
|
||||
double bx = x3 - x4;
|
||||
double by = y3 - y4;
|
||||
double cx = x1 - x3;
|
||||
double cy = y1 - y3;
|
||||
|
||||
double alphaNumerator = by * cx - bx * cy;
|
||||
double commonDenominator = ay * bx - ax * by;
|
||||
|
||||
if (commonDenominator > 0) {
|
||||
if (alphaNumerator < 0 || alphaNumerator > commonDenominator) {
|
||||
return false;
|
||||
}
|
||||
} else if (commonDenominator < 0) {
|
||||
if (alphaNumerator > 0 || alphaNumerator < commonDenominator) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
double betaNumerator = ax * cy - ay * cx;
|
||||
if (commonDenominator > 0) {
|
||||
if (betaNumerator < 0 || betaNumerator > commonDenominator) {
|
||||
return false;
|
||||
}
|
||||
} else if (commonDenominator < 0) {
|
||||
if (betaNumerator > 0 || betaNumerator < commonDenominator) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (commonDenominator == 0) {
|
||||
// This code wasn't in Franklin Antonio's method. It was added by Keith
|
||||
// Woodward.
|
||||
// The lines are parallel.
|
||||
// Check if they're collinear.
|
||||
double y3LessY1 = y3 - y1;
|
||||
double collinearityTestForP3 = x1 * (y2 - y3) + x2 * (y3LessY1) + x3 * (y1 - y2); // see
|
||||
// http://mathworld.wolfram.com/Collinear.html
|
||||
// If p3 is collinear with p1 and p2 then p4 will also be collinear,
|
||||
// since p1-p2 is parallel with p3-p4
|
||||
if (collinearityTestForP3 == 0) {
|
||||
// The lines are collinear. Now check if they overlap.
|
||||
if (x1 >= x3 && x1 <= x4 || x1 <= x3 && x1 >= x4 || x2 >= x3 && x2 <= x4 || x2 <= x3 && x2 >= x4
|
||||
|| x3 >= x1 && x3 <= x2 || x3 <= x1 && x3 >= x2) {
|
||||
if (y1 >= y3 && y1 <= y4 || y1 <= y3 && y1 >= y4 || y2 >= y3 && y2 <= y4 || y2 <= y3 && y2 >= y4
|
||||
|| y3 >= y1 && y3 <= y2 || y3 <= y1 && y3 >= y2) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static boolean doesIntersect(double l1x1, double l1y1, double l1x2, double l1y2, double l2x1, double l2y1,
|
||||
double l2x2, double l2y2) {
|
||||
double denom = ((l2y2 - l2y1) * (l1x2 - l1x1)) - ((l2x2 - l2x1) * (l1y2 - l1y1));
|
||||
|
||||
if (denom == 0.0f) {
|
||||
return false;
|
||||
}
|
||||
|
||||
double ua = (((l2x2 - l2x1) * (l1y1 - l2y1)) - ((l2y2 - l2y1) * (l1x1 - l2x1))) / denom;
|
||||
double ub = (((l1x2 - l1x1) * (l1y1 - l2y1)) - ((l1y2 - l1y1) * (l1x1 - l2x1))) / denom;
|
||||
|
||||
return ((ua >= 0.0d) && (ua <= 1.0d) && (ub >= 0.0d) && (ub <= 1.0d));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param x1
|
||||
* ...
|
||||
* @param y1
|
||||
* ...
|
||||
* @param x2
|
||||
* ...
|
||||
* @param y2
|
||||
* ...
|
||||
* @param x3
|
||||
* ...
|
||||
* @param y3
|
||||
* ...
|
||||
* @param x4
|
||||
* ...
|
||||
* @param y4
|
||||
* ...
|
||||
* @return ...
|
||||
*/
|
||||
public static boolean lineIntersect(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) {
|
||||
double denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);
|
||||
if (denom == 0.0) { // Lines are parallel.
|
||||
return false;
|
||||
}
|
||||
double ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / denom;
|
||||
double ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / denom;
|
||||
if (ua >= 0.0f && ua <= 1.0f && ub >= 0.0f && ub <= 1.0f) {
|
||||
// Get the intersection point.
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// private static final int OUT_LEFT = 1;
|
||||
// private static final int OUT_TOP = 2;
|
||||
// private static final int OUT_RIGHT = 4;
|
||||
// private static final int OUT_BOTTOM = 8;
|
||||
//
|
||||
//
|
||||
// private static int outcode(double x, double y) {
|
||||
// /*
|
||||
// * Note on casts to double below. If the arithmetic of
|
||||
// * x+w or y+h is done in float, then some bits may be
|
||||
// * lost if the binary exponents of x/y and w/h are not
|
||||
// * similar. By converting to double before the addition
|
||||
// * we force the addition to be carried out in double to
|
||||
// * avoid rounding error in the comparison.
|
||||
// *
|
||||
// * See bug 4320890 for problems that this inaccuracy causes.
|
||||
// */
|
||||
// int out = 0;
|
||||
// if (this.width <= 0) {
|
||||
// out |= OUT_LEFT | OUT_RIGHT;
|
||||
// } else if (x < this.x) {
|
||||
// out |= OUT_LEFT;
|
||||
// } else if (x > this.x + (double) this.width) {
|
||||
// out |= OUT_RIGHT;
|
||||
// }
|
||||
// if (this.height <= 0) {
|
||||
// out |= OUT_TOP | OUT_BOTTOM;
|
||||
// } else if (y < this.y) {
|
||||
// out |= OUT_TOP;
|
||||
// } else if (y > this.y + (double) this.height) {
|
||||
// out |= OUT_BOTTOM;
|
||||
// }
|
||||
// return out;
|
||||
// }
|
||||
|
||||
// from http://shamimkhaliq.50megs.com/Java/lineclipper.htm
|
||||
// private static int outCodes(Point P)
|
||||
// {
|
||||
// int Code = 0;
|
||||
//
|
||||
// if(P.y > yTop) Code += 1; /* code for above */
|
||||
// else if(P.y < yBottom) Code += 2; /* code for below */
|
||||
//
|
||||
// if(P.x > xRight) Code += 4; /* code for right */
|
||||
// else if(P.x < xLeft) Code += 8; /* code for left */
|
||||
//
|
||||
// return Code;
|
||||
// }
|
||||
//
|
||||
// private static boolean rejectCheck(int outCode1, int outCode2)
|
||||
// {
|
||||
// if ((outCode1 & outCode2) != 0 ) return true;
|
||||
// return(false);
|
||||
// }
|
||||
//
|
||||
//
|
||||
// private static boolean acceptCheck(int outCode1, int outCode2)
|
||||
// {
|
||||
// if ( (outCode1 == 0) && (outCode2 == 0) ) return(true);
|
||||
// return(false);
|
||||
// }
|
||||
//
|
||||
// static boolean CohenSutherland2DClipper(Point P0,Point P1)
|
||||
// {
|
||||
// int outCode0,outCode1;
|
||||
// while(true)
|
||||
// {
|
||||
// outCode0 = outCodes(P0);
|
||||
// outCode1 = outCodes(P1);
|
||||
// if( rejectCheck(outCode0,outCode1) ) return(false);
|
||||
// if( acceptCheck(outCode0,outCode1) ) return(true);
|
||||
// if(outCode0 == 0)
|
||||
// {
|
||||
// double tempCoord; int tempCode;
|
||||
// tempCoord = P0.x; P0.x= P1.x; P1.x = tempCoord;
|
||||
// tempCoord = P0.y; P0.y= P1.y; P1.y = tempCoord;
|
||||
// tempCode = outCode0; outCode0 = outCode1; outCode1 = tempCode;
|
||||
// }
|
||||
// if( (outCode0 & 1) != 0 )
|
||||
// {
|
||||
// P0.x += (P1.x - P0.x)*(yTop - P0.y)/(P1.y - P0.y);
|
||||
// P0.y = yTop;
|
||||
// }
|
||||
// else
|
||||
// if( (outCode0 & 2) != 0 )
|
||||
// {
|
||||
// P0.x += (P1.x - P0.x)*(yBottom - P0.y)/(P1.y - P0.y);
|
||||
// P0.y = yBottom;
|
||||
// }
|
||||
// else
|
||||
// if( (outCode0 & 4) != 0 )
|
||||
// {
|
||||
// P0.y += (P1.y - P0.y)*(xRight - P0.x)/(P1.x - P0.x);
|
||||
// P0.x = xRight;
|
||||
// }
|
||||
// else
|
||||
// if( (outCode0 & 8) != 0 )
|
||||
// {
|
||||
// P0.y += (P1.y - P0.y)*(xLeft - P0.x)/(P1.x - P0.x);
|
||||
// P0.x = xLeft;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
158
src/org/oscim/utils/GlConfigChooser.java
Normal file
158
src/org/oscim/utils/GlConfigChooser.java
Normal file
@@ -0,0 +1,158 @@
|
||||
package org.oscim.utils;
|
||||
|
||||
import javax.microedition.khronos.egl.EGL10;
|
||||
import javax.microedition.khronos.egl.EGLConfig;
|
||||
import javax.microedition.khronos.egl.EGLDisplay;
|
||||
|
||||
import android.opengl.GLSurfaceView;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class GlConfigChooser implements GLSurfaceView.EGLConfigChooser {
|
||||
static private final String TAG = "ConfigChooser";
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public static int stencilSize = 0;
|
||||
|
||||
@Override
|
||||
public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
|
||||
mValue = new int[1];
|
||||
|
||||
// Try to find a normal multisample configuration first.
|
||||
int[] configSpec = {
|
||||
EGL10.EGL_RED_SIZE, 5,
|
||||
EGL10.EGL_GREEN_SIZE, 6,
|
||||
EGL10.EGL_BLUE_SIZE, 5,
|
||||
EGL10.EGL_ALPHA_SIZE, 8,
|
||||
EGL10.EGL_DEPTH_SIZE, 16,
|
||||
// Requires that setEGLContextClientVersion(2) is called on the view.
|
||||
EGL10.EGL_RENDERABLE_TYPE, 4 /* EGL_OPENGL_ES2_BIT */,
|
||||
EGL10.EGL_STENCIL_SIZE, 8,
|
||||
EGL10.EGL_NONE };
|
||||
|
||||
if (!egl.eglChooseConfig(display, configSpec, null, 0, mValue)) {
|
||||
throw new IllegalArgumentException("eglChooseConfig failed");
|
||||
}
|
||||
int numConfigs = mValue[0];
|
||||
|
||||
if (numConfigs <= 0) {
|
||||
stencilSize = 4;
|
||||
|
||||
configSpec = new int[] {
|
||||
// EGL10.EGL_RENDERABLE_TYPE, 4, EGL10.EGL_NONE };
|
||||
EGL10.EGL_RED_SIZE, 8,
|
||||
EGL10.EGL_GREEN_SIZE, 8,
|
||||
EGL10.EGL_BLUE_SIZE, 8,
|
||||
EGL10.EGL_ALPHA_SIZE, 8,
|
||||
EGL10.EGL_DEPTH_SIZE, 16,
|
||||
EGL10.EGL_RENDERABLE_TYPE, 4 /* EGL_OPENGL_ES2_BIT */,
|
||||
EGL10.EGL_STENCIL_SIZE, 8,
|
||||
EGL10.EGL_NONE };
|
||||
|
||||
if (!egl.eglChooseConfig(display, configSpec, null, 0, mValue)) {
|
||||
throw new IllegalArgumentException("eglChooseConfig failed");
|
||||
}
|
||||
numConfigs = mValue[0];
|
||||
|
||||
if (numConfigs <= 0) {
|
||||
throw new IllegalArgumentException("No configs match configSpec");
|
||||
}
|
||||
} else {
|
||||
stencilSize = 8;
|
||||
}
|
||||
|
||||
// Get all matching configurations.
|
||||
EGLConfig[] configs = new EGLConfig[numConfigs];
|
||||
if (!egl.eglChooseConfig(display, configSpec, configs, numConfigs, mValue)) {
|
||||
throw new IllegalArgumentException("data eglChooseConfig failed");
|
||||
}
|
||||
|
||||
// CAUTION! eglChooseConfigs returns configs with higher bit depth
|
||||
// first: Even though we asked for rgb565 configurations, rgb888
|
||||
// configurations are considered to be "better" and returned first.
|
||||
// You need to explicitly filter the data returned by eglChooseConfig!
|
||||
|
||||
// for (int i = 0; i < configs.length; ++i) {
|
||||
// Log.i(TAG, printConfig(egl, display, configs[i]));
|
||||
// }
|
||||
|
||||
// int index = -1;
|
||||
// for (int i = 0; i < configs.length; ++i) {
|
||||
// // if (findConfigAttrib(egl, display, configs[i], EGL10.EGL_RED_SIZE, 0) == 8
|
||||
// // &&
|
||||
// // findConfigAttrib(egl, display, configs[i], EGL10.EGL_ALPHA_SIZE, 0) == 0) {
|
||||
// // index = i;
|
||||
// // break;
|
||||
// // }
|
||||
// // else
|
||||
// if (findConfigAttrib(egl, display, configs[i], EGL10.EGL_RED_SIZE, 0) == 8
|
||||
// &&
|
||||
// findConfigAttrib(egl, display, configs[i], EGL10.EGL_ALPHA_SIZE, 0) == 0
|
||||
// &&
|
||||
// findConfigAttrib(egl, display, configs[i], EGL10.EGL_DEPTH_SIZE, 0) == 24) {
|
||||
// index = i;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// if (index == -1) {
|
||||
// Log.w(TAG, "Did not find sane config, using first");
|
||||
// index = 0;
|
||||
// }
|
||||
int index = 0;
|
||||
|
||||
Log.i(TAG, "using: " + printConfig(egl, display, configs[index]));
|
||||
|
||||
EGLConfig config = configs.length > 0 ? configs[index] : null;
|
||||
if (config == null) {
|
||||
throw new IllegalArgumentException("No config chosen");
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
// from quake2android
|
||||
private String printConfig(EGL10 egl, EGLDisplay display,
|
||||
EGLConfig config) {
|
||||
|
||||
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);
|
||||
int d = findConfigAttrib(egl, display, config, EGL10.EGL_DEPTH_SIZE, 0);
|
||||
int s = findConfigAttrib(egl, display, config, EGL10.EGL_STENCIL_SIZE, 0);
|
||||
|
||||
/*
|
||||
* EGL_CONFIG_CAVEAT value #define EGL_NONE 0x3038 #define EGL_SLOW_CONFIG 0x3050 #define
|
||||
* EGL_NON_CONFORMANT_CONFIG 0x3051
|
||||
*/
|
||||
|
||||
return String.format("EGLConfig rgba=%d%d%d%d depth=%d stencil=%d",
|
||||
Integer.valueOf(r), Integer.valueOf(g),
|
||||
Integer.valueOf(b), Integer.valueOf(a), Integer.valueOf(d),
|
||||
Integer.valueOf(s))
|
||||
+ " native="
|
||||
+ findConfigAttrib(egl, display, config, EGL10.EGL_NATIVE_RENDERABLE, 0)
|
||||
+ " buffer="
|
||||
+ findConfigAttrib(egl, display, config, EGL10.EGL_BUFFER_SIZE, 0)
|
||||
+ String.format(
|
||||
" caveat=0x%04x",
|
||||
Integer.valueOf(findConfigAttrib(egl, display, config,
|
||||
EGL10.EGL_CONFIG_CAVEAT, 0)));
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
162
src/org/oscim/utils/GlUtils.java
Normal file
162
src/org/oscim/utils/GlUtils.java
Normal file
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.oscim.utils;
|
||||
|
||||
import static android.opengl.GLES20.glUniform4f;
|
||||
import android.graphics.Bitmap;
|
||||
import android.opengl.GLES20;
|
||||
import android.opengl.GLUtils;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* Utility functions
|
||||
*/
|
||||
public class GlUtils {
|
||||
private static String TAG = "GlUtils";
|
||||
|
||||
/**
|
||||
* @param bitmap
|
||||
* ...
|
||||
* @return gl identifier
|
||||
*/
|
||||
public static int loadTextures(Bitmap bitmap) {
|
||||
|
||||
int[] textures = new int[1];
|
||||
GLES20.glGenTextures(1, textures, 0);
|
||||
|
||||
int textureID = textures[0];
|
||||
// Log.i(TAG, "new texture " + textureID + " " + textureCnt++);
|
||||
|
||||
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureID);
|
||||
|
||||
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,
|
||||
GLES20.GL_LINEAR);
|
||||
|
||||
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER,
|
||||
GLES20.GL_LINEAR);
|
||||
|
||||
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,
|
||||
GLES20.GL_CLAMP_TO_EDGE);
|
||||
|
||||
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,
|
||||
GLES20.GL_CLAMP_TO_EDGE);
|
||||
|
||||
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
|
||||
|
||||
return textureID;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param shaderType
|
||||
* shader type
|
||||
* @param source
|
||||
* shader code
|
||||
* @return gl identifier
|
||||
*/
|
||||
public static int loadShader(int shaderType, String source) {
|
||||
int shader = GLES20.glCreateShader(shaderType);
|
||||
if (shader != 0) {
|
||||
GLES20.glShaderSource(shader, source);
|
||||
GLES20.glCompileShader(shader);
|
||||
int[] compiled = new int[1];
|
||||
GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
|
||||
if (compiled[0] == 0) {
|
||||
Log.e(TAG, "Could not compile shader " + shaderType + ":");
|
||||
Log.e(TAG, GLES20.glGetShaderInfoLog(shader));
|
||||
GLES20.glDeleteShader(shader);
|
||||
shader = 0;
|
||||
}
|
||||
}
|
||||
return shader;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param vertexSource
|
||||
* ...
|
||||
* @param fragmentSource
|
||||
* ...
|
||||
* @return gl identifier
|
||||
*/
|
||||
public static int createProgram(String vertexSource, String fragmentSource) {
|
||||
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
|
||||
if (vertexShader == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
|
||||
if (pixelShader == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int program = GLES20.glCreateProgram();
|
||||
if (program != 0) {
|
||||
checkGlError("glCreateProgram");
|
||||
GLES20.glAttachShader(program, vertexShader);
|
||||
checkGlError("glAttachShader");
|
||||
GLES20.glAttachShader(program, pixelShader);
|
||||
checkGlError("glAttachShader");
|
||||
GLES20.glLinkProgram(program);
|
||||
int[] linkStatus = new int[1];
|
||||
GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
|
||||
if (linkStatus[0] != GLES20.GL_TRUE) {
|
||||
Log.e(TAG, "Could not link program: ");
|
||||
Log.e(TAG, GLES20.glGetProgramInfoLog(program));
|
||||
GLES20.glDeleteProgram(program);
|
||||
program = 0;
|
||||
}
|
||||
}
|
||||
return program;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param op
|
||||
* ...
|
||||
*/
|
||||
public static void checkGlError(String op) {
|
||||
int error;
|
||||
while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
|
||||
Log.e(TAG, op + ": glError " + error);
|
||||
// throw new RuntimeException(op + ": glError " + error);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean checkGlOutOfMemory(String op) {
|
||||
int error;
|
||||
boolean oom = false;
|
||||
while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
|
||||
Log.e(TAG, op + ": glError " + error);
|
||||
// throw new RuntimeException(op + ": glError " + error);
|
||||
if (error == 1285)
|
||||
oom = true;
|
||||
}
|
||||
return oom;
|
||||
}
|
||||
|
||||
public static void setBlendColors(int handle, float[] c1, float[] c2, float alpha) {
|
||||
|
||||
glUniform4f(handle,
|
||||
c1[0] * (1 - alpha) + c2[0] * alpha,
|
||||
c1[1] * (1 - alpha) + c2[1] * alpha,
|
||||
c1[2] * (1 - alpha) + c2[2] * alpha, 1);
|
||||
}
|
||||
|
||||
public static void setColor(int handle, float[] c, float alpha) {
|
||||
if (alpha >= 1)
|
||||
GLES20.glUniform4fv(handle, 1, c, 0);
|
||||
else
|
||||
glUniform4f(handle, c[0] * alpha, c[1] * alpha, c[2] * alpha, alpha);
|
||||
|
||||
}
|
||||
}
|
||||
57
src/org/oscim/utils/LRUCache.java
Normal file
57
src/org/oscim/utils/LRUCache.java
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.oscim.utils;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* An LRUCache with a fixed size and an access-order policy. Old mappings are automatically removed from the cache when
|
||||
* new mappings are added. This implementation uses an {@link LinkedHashMap} internally.
|
||||
*
|
||||
* @param <K>
|
||||
* the type of the map key, see {@link Map}.
|
||||
* @param <V>
|
||||
* the type of the map value, see {@link Map}.
|
||||
*/
|
||||
public class LRUCache<K, V> extends LinkedHashMap<K, V> {
|
||||
private static final float LOAD_FACTOR = 0.6f;
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static int calculateInitialCapacity(int capacity) {
|
||||
if (capacity < 0) {
|
||||
throw new IllegalArgumentException("capacity must not be negative: " + capacity);
|
||||
}
|
||||
return (int) (capacity / LOAD_FACTOR) + 2;
|
||||
}
|
||||
|
||||
private final int capacity;
|
||||
|
||||
/**
|
||||
* @param capacity
|
||||
* the maximum capacity of this cache.
|
||||
* @throws IllegalArgumentException
|
||||
* if the capacity is negative.
|
||||
*/
|
||||
public LRUCache(int capacity) {
|
||||
super(calculateInitialCapacity(capacity), LOAD_FACTOR, true);
|
||||
this.capacity = capacity;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
|
||||
return size() > this.capacity;
|
||||
}
|
||||
}
|
||||
155
src/org/oscim/utils/PausableThread.java
Normal file
155
src/org/oscim/utils/PausableThread.java
Normal file
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.oscim.utils;
|
||||
|
||||
/**
|
||||
* An abstract base class for threads which support pausing and resuming.
|
||||
*/
|
||||
public abstract class PausableThread extends Thread {
|
||||
private boolean mPausing;
|
||||
private boolean mShouldPause;
|
||||
|
||||
/**
|
||||
* Causes the current thread to wait until this thread is pausing.
|
||||
*/
|
||||
public final void awaitPausing() {
|
||||
synchronized (this) {
|
||||
while (!isInterrupted() && !isPausing()) {
|
||||
try {
|
||||
wait(100);
|
||||
} catch (InterruptedException e) {
|
||||
// restore the interrupted status
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void interrupt() {
|
||||
// first acquire the monitor which is used to call wait()
|
||||
synchronized (this) {
|
||||
super.interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if this thread is currently pausing, false otherwise.
|
||||
*/
|
||||
public final synchronized boolean isPausing() {
|
||||
return mPausing;
|
||||
}
|
||||
|
||||
/**
|
||||
* The thread should stop its work temporarily.
|
||||
*/
|
||||
public final synchronized void pause() {
|
||||
if (!mShouldPause) {
|
||||
mShouldPause = true;
|
||||
takeabreak();
|
||||
notify();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The paused thread should continue with its work.
|
||||
*/
|
||||
public final synchronized void proceed() {
|
||||
if (mShouldPause) {
|
||||
mShouldPause = false;
|
||||
mPausing = false;
|
||||
afterPause();
|
||||
notify();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void run() {
|
||||
setName(getThreadName());
|
||||
setPriority(getThreadPriority());
|
||||
|
||||
while (!isInterrupted()) {
|
||||
synchronized (this) {
|
||||
while (!isInterrupted() && (mShouldPause || !hasWork())) {
|
||||
try {
|
||||
if (mShouldPause) {
|
||||
mPausing = true;
|
||||
}
|
||||
wait();
|
||||
} catch (InterruptedException e) {
|
||||
// restore the interrupted status
|
||||
interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isInterrupted()) {
|
||||
break;
|
||||
}
|
||||
|
||||
try {
|
||||
doWork();
|
||||
} catch (InterruptedException e) {
|
||||
// restore the interrupted status
|
||||
interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
afterRun();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called once when this thread continues to work after a pause. The default implementation is empty.
|
||||
*/
|
||||
protected void afterPause() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
protected void takeabreak() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Called once at the end of the {@link #run()} method. The default implementation is empty.
|
||||
*/
|
||||
protected void afterRun() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when this thread is not paused and should do its work.
|
||||
*
|
||||
* @throws InterruptedException
|
||||
* if the thread has been interrupted.
|
||||
*/
|
||||
protected abstract void doWork() throws InterruptedException;
|
||||
|
||||
/**
|
||||
* @return the name of this thread.
|
||||
*/
|
||||
protected abstract String getThreadName();
|
||||
|
||||
/**
|
||||
* @return the priority of this thread. The default value is {@link Thread#NORM_PRIORITY}.
|
||||
*/
|
||||
protected int getThreadPriority() {
|
||||
return Thread.NORM_PRIORITY;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if this thread has some work to do, false otherwise.
|
||||
*/
|
||||
protected abstract boolean hasWork();
|
||||
}
|
||||
Reference in New Issue
Block a user