New rendering for streets. Uses now redrawing instead of additional Bitmaps. No additional memory use. CPU usage with option shadow = 3 the same or even less than the classical one.

Changed missleading "shadowLayer" to "shadowRadius".
This commit is contained in:
seeebek 2011-10-09 13:28:02 +03:00 committed by Victor Shcherb
parent 4f3f4cc322
commit ed485a2702

View file

@ -63,31 +63,18 @@ public class OsmandRenderer {
private Map<Integer, Bitmap> cachedIcons = new LinkedHashMap<Integer, Bitmap>();
private final Context context;
//for street shadows
private Canvas streetcv;
private DisplayMetrics dm;
private int[] shadowarray;
private int shadownum;
private static class TextDrawInfo {
public TextDrawInfo(String text){
this.text = text;
}
String text = null;
Path drawOnPath = null;
float vOffset = 0;
float centerX = 0;
float pathRotate = 0;
float centerY = 0;
float textSize = 0;
float minDistance = 0;
int textColor = Color.BLACK;
int textShadow = 0;
int textWrap = 0;
boolean bold = false;
int shieldRes = 0;
int textOrder = 20;
public void fillProperties(RenderingContext rc, float centerX, float centerY){
this.centerX = centerX + rc.textDx;
@ -103,6 +90,21 @@ public class OsmandRenderer {
textOrder = rc.textOrder;
}
}
String text = null;
Path drawOnPath = null;
float vOffset = 0;
float centerX = 0;
float pathRotate = 0;
float centerY = 0;
float textSize = 0;
float minDistance = 0;
int textColor = Color.BLACK;
int textShadow = 0;
int textWrap = 0;
boolean bold = false;
int shieldRes = 0;
int textOrder = 20;
}
private static class IconDrawInfo {
@ -184,7 +186,7 @@ public class OsmandRenderer {
/* package*/ static class RenderingPaintProperties {
int color;
float strokeWidth;
int shadowLayer;
int shadowRadius;
int shadowColor;
boolean fillArea;
PathEffect pathEffect;
@ -199,7 +201,7 @@ public class OsmandRenderer {
fillArea = false;
shader = null;
shadowColor = 0;
shadowLayer = 0;
shadowRadius = 0;
}
public void updatePaint(Paint p){
@ -207,9 +209,9 @@ public class OsmandRenderer {
p.setColor(color);
p.setShader(shader);
if(shadowColor == 0){
shadowLayer = 0;
shadowRadius = 0;
}
p.setShadowLayer(shadowLayer, 0, 0, shadowColor);
p.setShadowLayer(shadowRadius, 0, 0, shadowColor);
p.setStrokeWidth(strokeWidth);
p.setStrokeCap(cap);
if (!fillArea) {
@ -225,7 +227,7 @@ public class OsmandRenderer {
shader = null;
pathEffect = null;
shadowColor = 0;
shadowLayer = 0;
shadowRadius = 0;
}
}
@ -286,16 +288,9 @@ public class OsmandRenderer {
public Bitmap generateNewBitmap(RenderingContext rc, List<BinaryMapDataObject> objects, Bitmap bmp, boolean useEnglishNames,
BaseOsmandRender renderer, List<IMapDownloaderCallback> notifyList) {
long now = System.currentTimeMillis();
//Flag for drawing the streets
boolean streetsdrawn = false;
// fill area
Canvas cv = new Canvas(bmp);
//needed for better street shadows
Bitmap streetbmp = Bitmap.createBitmap(cv.getWidth(), cv.getHeight(), Bitmap.Config.ARGB_8888);
streetcv = new Canvas(streetbmp);
if(renderer != null){
int dc = renderer.getDefaultColor(rc.nightMode);
if(dc != 0){
@ -349,29 +344,38 @@ public class OsmandRenderer {
rc.cosRotateTileSize = FloatMath.cos((float) Math.toRadians(rc.rotate)) * TILE_SIZE;
rc.sinRotateTileSize = FloatMath.sin((float) Math.toRadians(rc.rotate)) * TILE_SIZE;
//int shadow = 0; // no shadow (minumum CPU)
//int shadow = 1; // classic shadow (the implementaton in master)
//int shadow = 2; // blur shadow (most CPU, but still reasonable)
int shadow = 3; // solid border (CPU use like classic version or even smaller)
boolean repeat = false;
float[] keys = orderMap.keys();
Arrays.sort(keys);
int objCount = 0;
shadowarray = new int[keys.length];
shadownum = 0;
for (int k = 0; k < keys.length; k++) {
if(repeat == true && shadowarray[shadownum] == k){
shadownum++;
continue;
}
TIntArrayList list = orderMap.get(keys[k]);
for (int j = 0; j < list.size(); j++) {
int i = list.get(j);
int ind = i >> 8;
int l = i & 0xff;
BinaryMapDataObject obj = objects.get(ind);
int l = i & 0xff;
BinaryMapDataObject obj = objects.get(ind);
//draw streets with shadow when all have been drawn
if(keys[k] > 57 && !streetsdrawn){
drawStreetsShadow(cv, streetbmp);
streetsdrawn = true;
cv.drawBitmap(streetbmp, 0, 0, null);
}
// show text only for main type
drawObj(obj, renderer, cv, rc, l, l == 0, shadow, k);
// show text only for main type
drawObj(obj, renderer, cv, rc, l, l == 0, keys[k]);
objCount++;
objCount++;
}
if(objCount > 25){
notifyListeners(notifyList);
@ -380,6 +384,14 @@ public class OsmandRenderer {
if(rc.interrupted){
return null;
}
// order = 57 should be set as limit for shadows
if(keys[k] > 57 && repeat == false && shadow > 1){
shadow = 0;
shadownum = 0;
k = shadowarray[0];
repeat = true;
}
}
notifyListeners(notifyList);
long beforeIconTextTime = System.currentTimeMillis() - now;
@ -418,9 +430,6 @@ public class OsmandRenderer {
}
notifyListeners(notifyList);
//Draw streets here
drawStreetsWithShadow(cv, streetbmp);
drawTextOverCanvas(rc, cv, useEnglishNames);
long time = System.currentTimeMillis() - now;
rc.renderingDebugInfo = String.format("Rendering done in %s (%s text) ms\n" +
@ -445,15 +454,6 @@ public class OsmandRenderer {
cv.drawBitmap(streetbmp, 0, 0, null);
}
// Draw nice shadow for all streets
private void drawStreetsShadow(Canvas cv, Bitmap streetbmp){
Paint shadowpaint = new Paint();
shadowpaint.setColor(Color.BLACK);
shadowpaint.setMaskFilter(new BlurMaskFilter(1, BlurMaskFilter.Blur.SOLID));
Bitmap shadowImage = streetbmp.extractAlpha();
cv.drawBitmap(shadowImage, 0, 0, shadowpaint);
}
private void notifyListeners(List<IMapDownloaderCallback> notifyList) {
if (notifyList != null) {
for (IMapDownloaderCallback c : notifyList) {
@ -612,7 +612,7 @@ public class OsmandRenderer {
boolean horizontalWayDisplay = (text.pathRotate > 45 && text.pathRotate < 135) || (text.pathRotate > 225 && text.pathRotate < 315);
// text.minDistance = 0;
float textWidth = paintText.measureText(text.text) + (!horizontalWayDisplay ? 0 : text.minDistance);
// Paint.ascent is negative, so negate it.
// Paint.ascent is negative, so negate it.
int ascent = (int) Math.ceil(-paintText.ascent());
int descent = (int) Math.ceil(paintText.descent());
float textHeight = ascent + descent + (horizontalWayDisplay ? 0 : text.minDistance) + getDensityValue(rc, 5);
@ -661,8 +661,8 @@ public class OsmandRenderer {
st = 0;
}
// test functionality
// cv.drawRect(bounds, paint);
// cv.drawText(text.text.substring(0, Math.min(5, text.text.length())), bounds.centerX(), bounds.centerY(), paint);
// cv.drawRect(bounds, paint);
// cv.drawText(text.text.substring(0, Math.min(5, text.text.length())), bounds.centerX(), bounds.centerY(), paint);
for (int j = st; j < e; j++) {
RectF b = boundsIntersect.get(j);
@ -673,22 +673,23 @@ public class OsmandRenderer {
}
}
// store in list sorted by left boundary
// if(text.minDistance > 0){
// if (verticalText) {
// bounds.set(bounds.left + text.minDistance / 2, bounds.top,
// bounds.right - text.minDistance / 2, bounds.bottom);
// } else {
// bounds.set(bounds.left, bounds.top + text.minDistance / 2, bounds.right,
// bounds.bottom - text.minDistance / 2);
// }
// }
boundsIntersect.add(index, bounds);
// if(text.minDistance > 0){
// if (verticalText) {
// bounds.set(bounds.left + text.minDistance / 2, bounds.top,
// bounds.right - text.minDistance / 2, bounds.bottom);
// } else {
// bounds.set(bounds.left, bounds.top + text.minDistance / 2, bounds.right,
// bounds.bottom - text.minDistance / 2);
// }
// }
boundsIntersect.add(index, bounds);
}
return false;
}
protected void drawObj(BinaryMapDataObject obj, BaseOsmandRender render, Canvas canvas, RenderingContext rc, int l, boolean renderText, float order) {
protected void drawObj(BinaryMapDataObject obj, BaseOsmandRender render, Canvas canvas, RenderingContext rc, int l, boolean renderText
, int shadow, int index) {
rc.allObjects++;
if (obj instanceof MultyPolygon) {
drawMultiPolygon(obj, render,canvas, rc);
@ -702,7 +703,7 @@ public class OsmandRenderer {
drawPoint(obj, render, canvas, rc, pair, renderText);
} else if (t == MapRenderingTypes.POLYLINE_TYPE) {
int layer = MapRenderingTypes.getNegativeWayLayer(mainType);
drawPolyline(obj, render, canvas, rc, pair, layer, order);
drawPolyline(obj, render, canvas, rc, pair, layer, shadow, index);
} else if (t == MapRenderingTypes.POLYGON_TYPE) {
drawPolygon(obj, render, canvas, rc, pair);
} else {
@ -751,6 +752,8 @@ public class OsmandRenderer {
public void clearCachedResources(){
cachedIcons.clear();
shaders.clear();
@ -796,8 +799,8 @@ public class OsmandRenderer {
rc.main.updatePaint(paint);
canvas.drawPath(path, paint);
// for test purpose
// rc.second.strokeWidth = 1.5f;
// rc.second.color = Color.BLACK;
// rc.second.strokeWidth = 1.5f;
// rc.second.color = Color.BLACK;
if (rc.second.strokeWidth != 0) {
rc.second.updatePaint(paint);
@ -927,10 +930,33 @@ public class OsmandRenderer {
}
private void drawPolylineWithShadow(Canvas canvas, Path path, int shadow, int shadowRadius, int index){
// option shadow = 1 ,2 don't need any changes in first draw
// option shadow = 0 without any shadows
if(shadow == 0) paint.setShadowLayer(0, 0, 0, 0);
// option shadow = 3 with solid border
if(shadow == 3){
paint.setShadowLayer(0, 0, 0, 0);
paint.setStrokeWidth(paint.getStrokeWidth() + 2);
paint.setColor(0xffbababa);
}
canvas.drawPath(path, paint);
//check for shadow and save index in array
if(shadowRadius > 0 && shadow > 1){
if(shadownum == 0){
shadowarray[shadownum] = index;
shadownum++;
}
if (shadowarray[shadownum-1] != index){
shadowarray[shadownum] = index;
shadownum++;
}
}
}
private void drawPolyline(BinaryMapDataObject obj, BaseOsmandRender render, Canvas canvas, RenderingContext rc, TagValuePair pair, int layer) {
private void drawPolyline(BinaryMapDataObject obj, BaseOsmandRender render, Canvas canvas, RenderingContext rc, TagValuePair pair, int layer,
int shadow, int index) {
if(render == null || pair == null){
return;
}
@ -994,20 +1020,19 @@ public class OsmandRenderer {
}
if (path != null) {
rc.main.updatePaint(paint);
//changed canvas to the global one for streets
streetcv.drawPath(path, paint);
drawPolylineWithShadow(canvas, path, shadow, rc.main.shadowRadius, index);
if (rc.second.strokeWidth != 0) {
rc.second.updatePaint(paint);
streetcv.drawPath(path, paint);
drawPolylineWithShadow(canvas, path, shadow, rc.second.shadowRadius, index);
if (rc.third.strokeWidth != 0) {
rc.third.updatePaint(paint);
streetcv.drawPath(path, paint);
drawPolylineWithShadow(canvas, path, shadow, rc.third.shadowRadius, index);
}
}
if (rc.adds != null) {
for (int i = 0; i < rc.adds.length; i++) {
rc.adds[i].updatePaint(paint);
streetcv.drawPath(path, paint);
drawPolylineWithShadow(canvas, path, shadow, rc.adds[i].shadowRadius, index);
}
}
if (obj.getName() != null && obj.getName().length() > 0) {