start of TextureAtlas

This commit is contained in:
Hannes Janetzek 2013-04-12 04:32:01 +02:00
parent a1e9efbe5a
commit 47ad1d3617
2 changed files with 298 additions and 0 deletions

View File

@ -0,0 +1,212 @@
/*
* Copyright 2013 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 <http://www.gnu.org/licenses/>.
*/
// ported from:
/* ============================================================================
* Freetype GL - A C OpenGL Freetype engine
* Platform: Any
* WWW: http://code.google.com/p/freetype-gl/
* ----------------------------------------------------------------------------
* Copyright 2011,2012 Nicolas P. Rougier. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY NICOLAS P. ROUGIER ''AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL NICOLAS P. ROUGIER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of Nicolas P. Rougier.
* ============================================================================
*
* This source is based on the article by Jukka Jylanki :
* "A Thousand Ways to Pack the Bin - A Practical Approach to
* Two-Dimensional Rectangle Bin Packing", February 27, 2010.
*
* More precisely, this is an implementation of the Skyline Bottom-Left
* algorithm based on C++ sources provided by Jukka Jylanki at:
* http://clb.demon.fi/files/RectangleBinPack/
*
* ============================================================================
*/
package org.oscim.renderer;
import org.oscim.utils.pool.Inlist;
import android.graphics.Bitmap;
public class TextureAtlas {
/** Allocated slots */
Slot mSlots;
Rect mRects;
/** Width (in pixels) of the underlying texture */
final int mWidth;
/** Height (in pixels) of the underlying texture */
final int mHeight;
/** Depth (in bytes) of the underlying texture */
final int mDepth;
/** Allocated surface size */
int mUsed;
/** Texture identity (OpenGL) */
int mId;
/** Atlas data */
Bitmap mData;
class Slot extends Inlist<Slot> {
int x, y, w;
public Slot(int x, int y, int w) {
this.x = x;
this.y = y;
this.w = w;
}
}
public static class Rect extends Inlist<Rect> {
public int x, y, w, h;
}
private TextureAtlas(int width, int height, int depth) {
mWidth = width;
mHeight = height;
mDepth = depth;
mSlots = new Slot(1, 1, width - 2);
}
public Rect getRegion(int width, int height) {
int y, bestHeight, bestWidth;
Slot slot, prev;
Rect r = new Rect();
r.w = width;
r.h = height;
bestHeight = Integer.MAX_VALUE;
bestWidth = Integer.MAX_VALUE;
Slot bestSlot = null;
for (slot = mSlots; slot != null; slot = slot.next) {
// fit width
if ((slot.x + width) > (mWidth - 1))
continue;
// fit height
y = slot.y;
int widthLeft = width;
Slot fit = slot;
while (widthLeft > 0) {
if (fit.y > y)
y = fit.y;
if ((y + height) > (mHeight - 1)) {
y = -1;
break;
}
widthLeft -= fit.w;
fit = fit.next;
}
if (y < 0)
continue;
int h = y + height;
if ((h < bestHeight) || ((h == bestHeight) && (slot.w < bestWidth))) {
bestHeight = h;
bestSlot = slot;
bestWidth = slot.w;
r.x = slot.x;
r.y = y;
}
}
if (bestSlot == null)
return null;
Slot curSlot = new Slot(r.x, r.y + height, width);
mSlots = Inlist.prependRelative(mSlots, curSlot, bestSlot);
for (prev = curSlot; prev.next != null;) {
slot = prev.next;
int shrink = (prev.x + prev.w) - slot.x;
if (shrink <= 0)
break;
slot.x += shrink;
slot.w -= shrink;
if (slot.w > 0)
break;
// erease slot
prev.next = slot.next;
}
// merge
for (slot = mSlots; slot.next != null;) {
Slot next = slot.next;
if (slot.y == next.y) {
slot.w += next.w;
// erease 'next' slot
slot.next = next.next;
} else {
slot = next;
}
}
mUsed += width * height;
mRects = Inlist.push(mRects, r);
return r;
}
public void clear() {
mRects = null;
mSlots = new Slot(1, 1, mWidth - 2);
}
public static TextureAtlas create(int width, int height, int depth) {
if (!(depth == 1 || depth == 3 || depth == 4))
throw new IllegalArgumentException("invalid depth");
return new TextureAtlas(width, height, depth);
}
}

View File

@ -0,0 +1,86 @@
package org.oscim.renderer.overlays;
import java.util.Arrays;
import org.oscim.core.MapPosition;
import org.oscim.graphics.Color;
import org.oscim.graphics.Paint.Cap;
import org.oscim.renderer.GLRenderer.Matrices;
import org.oscim.renderer.TextureAtlas;
import org.oscim.renderer.TextureAtlas.Rect;
import org.oscim.renderer.layer.LineLayer;
import org.oscim.theme.renderinstruction.Line;
import org.oscim.view.MapView;
import android.util.Log;
public class AtlasTest extends BasicOverlay {
public AtlasTest(MapView mapView) {
super(mapView);
TextureAtlas mAtlas = TextureAtlas.create(2048, 2048, 1);
LineLayer ll = layers.getLineLayer(0);
ll.line = new Line(Color.BLUE, 3, Cap.BUTT);
ll.width = 1.5f;
LineLayer ll2 = layers.getLineLayer(1);
ll2.line = new Line(Color.RED, 3, Cap.BUTT);
ll2.width = 1.5f;
float[] points = new float[10];
for (int i = 0; i < 400; i++) {
int w = (int) (20 + Math.random() * 256);
int h = (int) (20 + Math.random() * 56);
Rect r = mAtlas.getRegion(w, h);
if (r == null) {
Log.d("...", "no space left");
continue;
}
points[0] = r.x;
points[1] = r.y;
points[2] = r.x + r.w;
points[3] = r.y;
points[4] = r.x + r.w;
points[5] = r.y + r.h;
points[6] = r.x;
points[7] = r.y + r.h;
points[8] = r.x;
points[9] = r.y;
ll.addLine(points, 10, false);
r.x += 2;
r.y += 2;
points[0] = r.x;
points[1] = r.y;
points[2] = r.x + w;
points[3] = r.y;
points[4] = r.x + w;
points[5] = r.y + h;
points[6] = r.x;
points[7] = r.y + h;
points[8] = r.x;
points[9] = r.y;
Log.d("...", "add region: " + Arrays.toString(points));
ll2.addLine(points, 10, false);
}
this.newData = true;
}
boolean initial = true;
@Override
public void update(MapPosition pos, boolean positionChanged,
boolean tilesChanged, Matrices m) {
if (initial) {
mMapPosition.copy(pos);
initial = false;
}
}
}