/* * Copyright 2012 Hannes Janetzek * * This file is part of the OpenScienceMap project (http://www.opensciencemap.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.renderer.bucket; import static org.oscim.renderer.MapRenderer.COORD_SCALE; import org.oscim.backend.CanvasAdapter; import org.oscim.backend.canvas.Canvas; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class TextBucket extends TextureBucket { static final Logger log = LoggerFactory.getLogger(TextBucket.class); protected final static int LBIT_MASK = 0xfffffffe; protected static int mFontPadX = 1; //private static int mFontPadY = 1; public TextItem labels; protected final Canvas mCanvas; public TextItem getLabels() { return labels; } public void setLabels(TextItem labels) { this.labels = labels; } public TextBucket() { super(RenderBucket.SYMBOL); mCanvas = CanvasAdapter.newCanvas(); fixed = true; level = -1; } public void addText(TextItem item) { TextItem it = labels; for (; it != null; it = it.next) { 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; it.next = item; return; } } item.next = labels; labels = item; } @Override public void prepare() { int numIndices = 0; int offsetIndices = 0; int advanceY = 0; float x = 0; float y = 0; float yy; TextureItem t = pool.get(); textures = t; mCanvas.setBitmap(t.bitmap); for (TextItem it = labels; it != null;) { float width = it.width + 2 * mFontPadX; float height = (int) (it.text.fontHeight) + 0.5f; if (height > TEXTURE_HEIGHT) height = TEXTURE_HEIGHT; if (height > advanceY) advanceY = (int) height; if (x + width > TEXTURE_WIDTH) { x = 0; y += advanceY; advanceY = (int) (height + 0.5f); if (y + height > TEXTURE_HEIGHT) { t.offset = offsetIndices; t.indices = (numIndices - offsetIndices); offsetIndices = numIndices; t.next = pool.get(); t = t.next; mCanvas.setBitmap(t.bitmap); x = 0; y = 0; advanceY = (int) height; } } yy = y + height - it.text.fontDescent; mCanvas.drawText(it.string, x, yy, it.text.paint, it.text.stroke); // FIXME !!! if (width > TEXTURE_WIDTH) width = TEXTURE_WIDTH; while (it != null) { addItem(it, width, height, x, y); /* six indices to draw the four vertices */ numIndices += TextureBucket.INDICES_PER_SPRITE; numVertices += 4; if (it.next == null || (it.next.text != it.text) || (it.next.string != it.string)) { it = it.next; break; } it = it.next; } x += width; } t.offset = offsetIndices; t.indices = (numIndices - offsetIndices); } protected void addItem(TextItem it, float width, float height, float x, float y) { /* texture coordinates */ short u1 = (short) (COORD_SCALE * x); short v1 = (short) (COORD_SCALE * y); short u2 = (short) (COORD_SCALE * (x + width)); short v2 = (short) (COORD_SCALE * (y + height)); short x1, x2, x3, x4, y1, y3, y2, y4; float hw = width / 2.0f; float hh = height / 2.0f; if (it.text.caption) { x1 = x3 = (short) (COORD_SCALE * -hw); x2 = x4 = (short) (COORD_SCALE * hw); y1 = y2 = (short) (COORD_SCALE * (it.text.dy + hh)); y3 = y4 = (short) (COORD_SCALE * (it.text.dy - hh)); } else { float vx = it.x1 - it.x2; float vy = it.y1 - it.y2; float a = (float) Math.sqrt(vx * vx + vy * vy); vx = vx / a; vy = vy / a; float ux = -vy * hh; float uy = vx * hh; float ux2 = -vy * hh; float uy2 = vx * hh; vx *= hw; vy *= hw; /* top-left */ x1 = (short) (COORD_SCALE * (vx - ux)); y1 = (short) (COORD_SCALE * (vy - uy)); /* top-right */ x2 = (short) (COORD_SCALE * (-vx - ux)); y2 = (short) (COORD_SCALE * (-vy - uy)); /* bot-right */ x4 = (short) (COORD_SCALE * (-vx + ux2)); y4 = (short) (COORD_SCALE * (-vy + uy2)); /* bot-left */ x3 = (short) (COORD_SCALE * (vx + ux2)); y3 = (short) (COORD_SCALE * (vy + uy2)); } /* add vertices */ int tmp = (int) (COORD_SCALE * it.x) & LBIT_MASK; short tx = (short) (tmp | (it.text.caption ? 1 : 0)); short ty = (short) (COORD_SCALE * it.y); vertexItems.add(tx, ty, x1, y1, u1, v2); vertexItems.add(tx, ty, x3, y3, u1, v1); vertexItems.add(tx, ty, x2, y2, u2, v2); vertexItems.add(tx, ty, x4, y4, u2, v1); } @Override public void clear() { super.clear(); clearLabels(); } public void clearLabels() { labels = TextItem.pool.releaseAll(labels); } }