draw text textures only once per string

- unify duplicate strings from different tiles (as side-effect save some bytes)
- fix 'advance by width' in texture drawing
This commit is contained in:
Hannes Janetzek 2013-01-17 14:31:20 +01:00
parent 928c7e7328
commit e1fb97ae30
5 changed files with 175 additions and 119 deletions

View File

@ -22,7 +22,6 @@ import android.util.Log;
* @author Hannes Janetzek * @author Hannes Janetzek
*/ */
public class Layers { public class Layers {
// mixed Polygon and Line layers // mixed Polygon and Line layers
public Layer layers; public Layer layers;
public Layer textureLayers; public Layer textureLayers;
@ -34,6 +33,10 @@ public class Layers {
// 3. other layers keep their byte offset in Layer.offset // 3. other layers keep their byte offset in Layer.offset
public int lineOffset; public int lineOffset;
// time when layers became first rendered (in uptime)
// used for animations
public long time;
private Layer mCurLayer; private Layer mCurLayer;
// get or add the line- or polygon-layer for a level. // get or add the line- or polygon-layer for a level.
@ -198,7 +201,6 @@ public class Layers {
} }
for (l = textureLayers; l != null; l = l.next) { for (l = textureLayers; l != null; l = l.next) {
VertexPool.release(l.pool);
l.clear(); l.clear();
} }

View File

@ -207,6 +207,13 @@ public final class SymbolLayer extends TextureLayer {
short tx = (short) ((int) (SCALE * it2.x) & LBIT_MASK | (it2.billboard ? 1 : 0)); short tx = (short) ((int) (SCALE * it2.x) & LBIT_MASK | (it2.billboard ? 1 : 0));
short ty = (short) (SCALE * it2.y); short ty = (short) (SCALE * it2.y);
if (pos == VertexPoolItem.SIZE) {
si.used = VertexPoolItem.SIZE;
si = si.next = VertexPool.get();
buf = si.vertices;
pos = 0;
}
// top-left // top-left
buf[pos++] = tx; buf[pos++] = tx;
buf[pos++] = ty; buf[pos++] = ty;
@ -238,17 +245,9 @@ public final class SymbolLayer extends TextureLayer {
// six elements used to draw the four vertices // six elements used to draw the four vertices
curIndices += TextureRenderer.INDICES_PER_SPRITE; curIndices += TextureRenderer.INDICES_PER_SPRITE;
if (pos == VertexPoolItem.SIZE) {
si.used = VertexPoolItem.SIZE;
si = si.next = VertexPool.get();
buf = si.vertices;
pos = 0;
} }
x += width; x += width;
} }
}
to.offset = offsetIndices; to.offset = offsetIndices;
to.vertices = curIndices; to.vertices = curIndices;
@ -263,8 +262,10 @@ public final class SymbolLayer extends TextureLayer {
protected void clear() { protected void clear() {
TextureObject.release(textures); TextureObject.release(textures);
SymbolItem.release(symbols); SymbolItem.release(symbols);
VertexPool.release(pool);
textures = null; textures = null;
symbols = null; symbols = null;
pool = null;
verticesCnt = 0; verticesCnt = 0;
} }
} }

View File

@ -34,6 +34,21 @@ public class TextItem {
} }
} }
public static void append(TextItem ti, TextItem in) {
if (ti == null)
return;
if (ti.next == null) {
in.next = ti.next;
ti.next = in;
}
TextItem t = ti;
while (t.next != null)
t = t.next;
in.next = t.next;
t.next = in;
}
public static void release(TextItem ti) { public static void release(TextItem ti) {
if (ti == null) if (ti == null)
return; return;

View File

@ -22,7 +22,7 @@ import android.util.Log;
public final class TextLayer extends TextureLayer { public final class TextLayer extends TextureLayer {
// private static String TAG = TextureLayer.class.getSimpleName(); //private static String TAG = TextureLayer.class.getName();
private final static int TEXTURE_WIDTH = TextureObject.TEXTURE_WIDTH; private final static int TEXTURE_WIDTH = TextureObject.TEXTURE_WIDTH;
private final static int TEXTURE_HEIGHT = TextureObject.TEXTURE_HEIGHT; private final static int TEXTURE_HEIGHT = TextureObject.TEXTURE_HEIGHT;
@ -61,10 +61,8 @@ public final class TextLayer extends TextureLayer {
else else
prev.next = it.next; prev.next = it.next;
verticesCnt -= 4;
return true; return true;
} }
prev = it; prev = it;
} }
@ -72,21 +70,42 @@ public final class TextLayer extends TextureLayer {
} }
public void addText(TextItem item) { public void addText(TextItem item) {
verticesCnt += 4;
TextItem it = labels; TextItem it = labels;
for (; it != null; it = it.next) { for (; it != null; it = it.next) {
if (it.text == item.text) { // todo add captions at the end
// insert after text of same type //if (item.text.caption && !it.text.caption)
//continue;
//if (!item.text.caption && it.text.caption)
//continue;
if (item.text == it.text) {
while (it.next != null
// break if next item uses different text style
&& item.text == it.next.text
// check same string instance
&& item.string != it.string
// check same string
&& !item.string.equals(it.string))
it = it.next;
// unify duplicate string :)
// Note: this is required for 'packing test' in prepare to work!
if (item.string != it.string && item.string.equals(it.string))
item.string = it.string;
// insert after text of same type and/or before same string
item.next = it.next; item.next = it.next;
it.next = item; it.next = item;
return; return;
} }
} }
item.next = labels; item.next = labels;
labels = item; labels = item;
// for (it = labels; it != null; it = it.next)
// Log.d(TAG, "> " + it.text + " " + it.string);
// Log.d(TAG, "< ");
} }
@Override @Override
@ -94,19 +113,14 @@ public final class TextLayer extends TextureLayer {
if (TextureRenderer.debug) if (TextureRenderer.debug)
Log.d("...", "prepare"); Log.d("...", "prepare");
// int numLabel = 0;
// int numTextures = 0;
short numIndices = 0; short numIndices = 0;
short offsetIndices = 0; short offsetIndices = 0;
curItem = VertexPool.get(); VertexPoolItem vi = pool = VertexPool.get();
pool = curItem; int pos = vi.used; // 0
short buf[] = vi.vertices;
VertexPoolItem si = curItem; verticesCnt = 0;
int pos = si.used;
short buf[] = si.vertices;
int advanceY = 0; int advanceY = 0;
float x = 0; float x = 0;
@ -117,8 +131,7 @@ public final class TextLayer extends TextureLayer {
textures = to; textures = to;
mCanvas.setBitmap(to.bitmap); mCanvas.setBitmap(to.bitmap);
for (TextItem it = labels; it != null; it = it.next) { for (TextItem it = labels; it != null;) {
// numLabel++;
float width = it.width + 2 * mFontPadX; float width = it.width + 2 * mFontPadX;
float height = (int) (it.text.fontHeight) + 2 * mFontPadY + 0.5f; float height = (int) (it.text.fontHeight) + 2 * mFontPadY + 0.5f;
@ -165,6 +178,34 @@ public final class TextLayer extends TextureLayer {
float hw = width / 2.0f; float hw = width / 2.0f;
float hh = height / 2.0f; float hh = height / 2.0f;
float hh2 = 0;
if (!it.text.caption) {
hw /= mScale;
hh2 = hh + it.text.fontDescent / 2;
hh -= it.text.fontDescent / 2;
hh /= mScale;
hh2 /= mScale;
}
// texture coordinates
short u1 = (short) (SCALE * x);
short v1 = (short) (SCALE * y);
short u2 = (short) (SCALE * (x + width));
short v2 = (short) (SCALE * (y + height));
// add symbol items referencing the same bitmap / drawable
for (TextItem it2 = it;; it2 = it2.next) {
if (it != it2) {
if (it2 == null
|| (it2.text != it.text)
|| (it2.string != it.string)) {
it = it2;
break;
}
//Log.d(TAG, "pack strings: " + it.string);
}
short x1, x2, x3, x4, y1, y3, y2, y4; short x1, x2, x3, x4, y1, y3, y2, y4;
if (it.text.caption) { if (it.text.caption) {
@ -175,8 +216,8 @@ public final class TextLayer extends TextureLayer {
// x1 = x3 = (short) (0); // x1 = x3 = (short) (0);
// x2 = x4 = (short) (SCALE * width); // x2 = x4 = (short) (SCALE * width);
} else { } else {
float vx = it.x1 - it.x2; float vx = it2.x1 - it2.x2;
float vy = it.y1 - it.y2; float vy = it2.y1 - it2.y2;
float a = (float) Math.sqrt(vx * vx + vy * vy); float a = (float) Math.sqrt(vx * vx + vy * vy);
vx = vx / a; vx = vx / a;
vy = vy / a; vy = vy / a;
@ -184,13 +225,6 @@ public final class TextLayer extends TextureLayer {
float ux = -vy; float ux = -vy;
float uy = vx; float uy = vx;
hw /= mScale;
float hh2 = hh + it.text.fontDescent / 2;
hh -= it.text.fontDescent / 2;
hh /= mScale;
hh2 /= mScale;
x1 = (short) (SCALE * (vx * hw - ux * hh)); x1 = (short) (SCALE * (vx * hw - ux * hh));
y1 = (short) (SCALE * (vy * hw - uy * hh)); y1 = (short) (SCALE * (vy * hw - uy * hh));
x2 = (short) (SCALE * (-vx * hw - ux * hh)); x2 = (short) (SCALE * (-vx * hw - ux * hh));
@ -201,16 +235,17 @@ public final class TextLayer extends TextureLayer {
y3 = (short) (SCALE * (vy * hw + uy * hh2)); y3 = (short) (SCALE * (vy * hw + uy * hh2));
} }
short u1 = (short) (SCALE * x);
short v1 = (short) (SCALE * y);
short u2 = (short) (SCALE * (x + width));
short v2 = (short) (SCALE * (y + height));
// add vertices // add vertices
int tmp = (int) (SCALE * it.x) & LBIT_MASK; int tmp = (int) (SCALE * it2.x) & LBIT_MASK;
short tx = (short) (tmp | (it.text.caption ? 1 : 0)); short tx = (short) (tmp | (it2.text.caption ? 1 : 0));
short ty = (short) (SCALE * it2.y);
short ty = (short) (SCALE * it.y); if (pos == VertexPoolItem.SIZE) {
vi.used = VertexPoolItem.SIZE;
vi = vi.next = VertexPool.get();
buf = vi.vertices;
pos = 0;
}
// top-left // top-left
buf[pos++] = tx; buf[pos++] = tx;
@ -242,14 +277,8 @@ public final class TextLayer extends TextureLayer {
buf[pos++] = v1; buf[pos++] = v1;
// six indices to draw the four vertices // six indices to draw the four vertices
numIndices += 6; numIndices += TextureRenderer.INDICES_PER_SPRITE;
verticesCnt += 4;
if (pos == VertexPoolItem.SIZE) {
si.used = VertexPoolItem.SIZE;
si = si.next = VertexPool.get();
buf = si.vertices;
pos = 0;
}
// FIXME this does not work, need to draw bitmap on next // FIXME this does not work, need to draw bitmap on next
// texture... // texture...
@ -259,15 +288,15 @@ public final class TextLayer extends TextureLayer {
// pos = 0; // pos = 0;
// } // }
}
x += width; x += width;
} }
vi.used = pos;
to.offset = offsetIndices; to.offset = offsetIndices;
to.vertices = (short) (numIndices - offsetIndices); to.vertices = (short) (numIndices - offsetIndices);
si.used = pos;
curItem = si;
// Log.d(TAG, "added labels " + numTextures + " " + numLabel); // Log.d(TAG, "added labels " + numTextures + " " + numLabel);
return true; return true;
@ -277,8 +306,10 @@ public final class TextLayer extends TextureLayer {
protected void clear() { protected void clear() {
TextureObject.release(textures); TextureObject.release(textures);
TextItem.release(labels); TextItem.release(labels);
VertexPool.release(pool);
textures = null; textures = null;
labels = null; labels = null;
pool = null;
verticesCnt = 0; verticesCnt = 0;
} }
} }

View File

@ -38,8 +38,11 @@ public class TextOverlay extends RenderOverlay {
private LabelThread mThread; private LabelThread mThread;
private MapPosition mWorkPos; private MapPosition mWorkPos;
// TextLayer that is updating
private TextLayer mWorkLayer; private TextLayer mWorkLayer;
private TextLayer mNewLayer; // TextLayer that is ready to be added to 'layers'
private TextLayer mCurLayer;
/* package */boolean mRun; /* package */boolean mRun;
/* package */boolean mRerun; /* package */boolean mRerun;
@ -97,8 +100,9 @@ public class TextOverlay extends RenderOverlay {
// only relabel when tiles belong to the current zoomlevel or its parent // only relabel when tiles belong to the current zoomlevel or its parent
if (diff > 1 || diff < -2) { if (diff > 1 || diff < -2) {
// pass back the current layer
synchronized (this) { synchronized (this) {
mNewLayer = tl; mCurLayer = tl;
} }
return; return;
} }
@ -257,7 +261,7 @@ public class TextOverlay extends RenderOverlay {
// everything synchronized? // everything synchronized?
synchronized (this) { synchronized (this) {
mNewLayer = tl; mCurLayer = tl;
} }
} }
@ -268,14 +272,17 @@ public class TextOverlay extends RenderOverlay {
if (mHolding) if (mHolding)
return; return;
if (mNewLayer != null) { if (mCurLayer != null) {
// keep text layer, not recrating its canvas each time
// keep text layer, not recrating its canvas each time...
mWorkLayer = (TextLayer) layers.textureLayers; mWorkLayer = (TextLayer) layers.textureLayers;
// clear textures and text items from previous layer
layers.clear(); layers.clear();
layers.textureLayers = mNewLayer; // set new TextLayer to be uploaded and used
mNewLayer = null; layers.textureLayers = mCurLayer;
mCurLayer = null;
// make the 'labeled' MapPosition current // make the 'labeled' MapPosition current
MapPosition tmp = mMapPosition; MapPosition tmp = mMapPosition;