package loon.action.scripting.pack;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import loon.LSystem;
import loon.LTouch;
import loon.action.map.AStarFindHeuristic;
import loon.action.map.AStarFinder;
import loon.action.map.Field2D;
import loon.action.scripting.ScriptScreen;
import loon.core.LRelease;
import loon.core.geom.Vector2f;
import loon.core.graphics.Screen;
import loon.core.graphics.device.LColor;
import loon.core.graphics.device.LLight;
import loon.core.graphics.opengl.GL;
import loon.core.graphics.opengl.GLEx;
import loon.core.graphics.opengl.GLUtils;
import loon.core.graphics.opengl.LTexturePack;
import loon.utils.MathUtils;
import loon.utils.StringUtils;
import loon.utils.xml.XMLElement;
import loon.utils.xml.XMLParser;
/**
* Copyright 2008 - 2011
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
* @project loonframework
* @author chenpeng
* @email:ceponline@yahoo.com.cn
* @version 0.1
*/
public class PackTileMap extends LLight implements LRelease {
class SimplePackTileFactory extends PackTileFactory {
HashMap<Integer, PackTile> tiles = new HashMap<Integer, PackTile>(10);
public void add(int id, PackTile tile) {
tiles.put(id, tile);
}
@Override
public PackTile getTile(int id) {
return tiles.get(id);
}
public boolean contains(int id) {
return tiles.containsKey(id);
}
@Override
public String getName() {
return "simple";
}
}
private String bindPackName;
private int lazyHashCode = 1;
private int posX, posY;
private int sx, sy;
private PackView view;
private PackTileFactory tileFactory;
private int[] limit;
private boolean init, dirty;
private int tileWidth = 32;
private int tileHeight = 32;
private int width, height;
private String name;
private PackTile[][] tiles;
private Field2D field;
private XMLElement element;
private Screen screen;
private int limitWidth, limitHeight;
private int minX, minY, maxX, maxY;
public PackTileMap(String res) {
this(res, null);
}
public PackTileMap(InputStream in) {
this(in, null);
}
public PackTileMap(XMLElement element) {
this(element, null);
}
public PackTileMap(PackTileFactory factory, XMLElement element) {
this(factory, element, null);
}
public PackTileMap(String res, Screen screen) {
this(XMLParser.parse(res).getRoot(), screen);
}
public PackTileMap(InputStream in, Screen screen) {
this(XMLParser.parse(in).getRoot(), screen);
}
public PackTileMap(XMLElement element, Screen screen) {
this(null, element, screen);
}
public PackTileMap(PackTileFactory factory, XMLElement element,
Screen screen) {
this.screen = screen;
this.tileFactory = factory;
this.element = element;
this.dirty = true;
}
public void init(PackTileFactory tileFactory) {
if (init) {
return;
}
this.name = element.getAttribute("name", null);
this.bindPackName = element.getAttribute("bind", null);
this.tileWidth = element.getIntAttribute("tw", tileWidth);
if (tileWidth < 32) {
tileWidth = 32;
}
this.tileHeight = element.getIntAttribute("th", tileHeight);
if (tileHeight < 32) {
tileHeight = 32;
}
String limits = element.getAttribute("limit", "");
String[] list = StringUtils.split(limits, ",");
if (list != null && list.length > 0) {
int size = list.length;
limit = new int[size];
for (int i = 0; i < size; i++) {
try {
limit[i] = Integer.parseInt(list[i]);
} catch (Exception e) {
limit[i] = -1;
}
}
}
if (tileFactory == null) {
SimplePackTileFactory packTile = new SimplePackTileFactory();
for (Iterator<?> it = element.elements("tile"); it.hasNext();) {
XMLElement child = (XMLElement) it.next();
final int id = child.getIntAttribute("id", -1);
final int imgId = child.getIntAttribute("blockid", -1);
final float sx = child.getIntAttribute("x", 0);
final float sy = child.getIntAttribute("y", 0);
final float sw = child.getIntAttribute("w", 0);
final float sh = child.getIntAttribute("h", 0);
final boolean sub = (sx != 0 || sy != 0 || sw != 0 || sh != 0);
final String imgName = child.getAttribute("blockname", "");
if (!packTile.contains(id)) {
PackTile tile = new PackTile() {
boolean solid;
@Override
public void draw(LTexturePack pack, float x, float y,
LColor[] c) {
if (c == null) {
if (imgId != -1) {
if (sub) {
pack.draw(imgId, x, y, tileWidth,
tileHeight, sx, sy, sw, sh);
} else {
pack.draw(imgId, x, y);
}
} else {
if (sub) {
pack.draw(imgName, x, y, tileWidth,
tileHeight, sx, sy, sw, sh);
} else {
pack.draw(imgName, x, y);
}
}
} else {
if (imgId != -1) {
if (sub) {
pack.drawOnlyBatch(imgId, x, y,
tileWidth, tileHeight, sx, sy,
sw, sh, c);
} else {
pack.drawOnlyBatch(imgId, x, y, c);
}
} else {
if (sub) {
pack.drawOnlyBatch(imgName, x, y,
tileWidth, tileHeight, sx, sy,
sw, sh, c);
} else {
pack.drawOnlyBatch(imgName, x, y, c);
}
}
}
}
@Override
public boolean isSolid() {
return solid;
}
@Override
public void setSolid(boolean s) {
this.solid = s;
}
@Override
public int width() {
return tileWidth;
}
@Override
public int height() {
return tileHeight;
}
@Override
public void update(long t) {
}
};
packTile.add(id, tile);
}
}
this.tileFactory = packTile;
}
ArrayList<int[]> records = new ArrayList<int[]>(10);
for (Iterator<?> e = element.elements("b"); e.hasNext();) {
String result = ((XMLElement) e.next()).getAttribute("d", "");
if (!"".equals(result)) {
String[] stringArray = result.split(",");
int size = stringArray.length;
int[] intArray = new int[size];
for (int i = 0; i < size; i++) {
intArray[i] = Integer.parseInt(stringArray[i]);
}
records.add(intArray);
}
}
if (records.size() > 0) {
int col = records.size();
int[][] result = new int[col][];
for (int i = 0; i < col; i++) {
result[i] = records.get(i);
}
this.width = result[0].length;
this.height = result.length;
this.field = new Field2D(result, tileWidth, tileHeight);
}
if (screen != null) {
limitWidth = screen.getWidth() / tileWidth;
limitHeight = screen.getHeight() / tileHeight;
} else {
limitWidth = width;
limitHeight = height;
}
this.maxLightSize(width, height);
this.maxX = limitWidth;
this.maxY = limitHeight;
this.init = true;
}
public void sub(int x, int y, int w, int h) {
this.minX = x;
this.minY = y;
this.maxX = w;
this.maxY = h;
}
public void sub(int x, int y) {
sub(x, y, limitWidth, limitHeight);
}
public boolean isDirty() {
return dirty;
}
public void update() {
if (!dirty) {
return;
}
if (field != null) {
int[][] maps = field.getMap();
if (tiles == null) {
this.tiles = new PackTile[this.width][this.height];
}
if (limit == null) {
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
tiles[x][y] = tileFactory.getTile(maps[y][x]);
if (tiles[x][y] != null && maps[y][x] == -1) {
tiles[x][y].setSolid(true);
}
}
}
} else {
field.setLimit(limit);
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
int id = maps[y][x];
if (tiles[x][y] == null) {
tiles[x][y] = tileFactory.getTile(id);
}
if (tiles[x][y] != null) {
if (limit != null) {
for (int i = 0; i < limit.length; i++) {
if (id == limit[i]) {
tiles[x][y].setSolid(true);
}
}
}
}
}
}
}
}
dirty = false;
}
public LinkedList<Vector2f> findAStar(AStarFindHeuristic heuristic, int x1,
int y1, LTouch touch) {
if (field != null) {
return findAStar(heuristic, x1, y1, touch.x(), touch.y());
}
return null;
}
public LinkedList<Vector2f> findAStar(AStarFindHeuristic heuristic, int x1,
int y1, int x2, int y2) {
if (field != null) {
return findAStar(heuristic, x1, y1, x2, y2, true);
}
return null;
}
public LinkedList<Vector2f> findAStar(AStarFindHeuristic heuristic, int x1,
int y1, boolean flag, LTouch touch) {
if (field != null) {
return findAStar(heuristic, x1, y1, touch.x(), touch.y(), flag);
}
return null;
}
public LinkedList<Vector2f> findAStar(AStarFindHeuristic heuristic, int x1,
int y1, int x2, int y2, boolean flag) {
if (field != null) {
return AStarFinder.find(heuristic, field,
field.pixelsToTilesWidth(x1),
field.pixelsToTilesHeight(y1),
field.pixelsToTilesWidth(x2),
field.pixelsToTilesHeight(y2), flag);
}
return null;
}
public void limit(int[] list) {
if (field != null) {
this.limit = list;
this.dirty = true;
}
}
public void setBlockSize(int tileWidth, int tileHeight) {
this.tileWidth = tileWidth;
this.tileHeight = tileHeight;
}
public int getWidth() {
return width * tileWidth;
}
public int getHeight() {
return height * tileHeight;
}
public PackTile getTile(int x, int y) {
return tiles[x][y];
}
public void setTile(int x, int y, PackTile type) {
tiles[x][y] = type;
}
public boolean collidesWith(PackSprite sprite) {
return !canMove(sprite, sprite.getX(), sprite.getY());
}
public int count(PackTile element) {
int result = 0;
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
if (element == tiles[x][y]) {
result++;
}
}
}
return result;
}
public boolean canMove(PackSprite sprite, float x1, float y1) {
float w = sprite.getWidth();
float h = sprite.getHeight();
float sx = x1 - w;
float sy = y1 - h;
for (int x = MathUtils.max(MathUtils.floor(sx / tileWidth), 0); x <= MathUtils
.min(MathUtils.floor((sx + w - 1) / tileWidth), width - 1); x++) {
for (int y = MathUtils.max(MathUtils.floor(sy / tileHeight), 0); y <= MathUtils
.min(MathUtils.floor((sy + h - 1) / tileHeight), height - 1); y++) {
if (tiles[x][y].isSolid()) {
return false;
}
}
}
return true;
}
public void touch(PackSprite sprite) {
float w = sprite.getWidth();
float h = sprite.getHeight();
float sx = sprite.getX() - w;
float sy = sprite.getY() - h;
for (int x = MathUtils.max(MathUtils.floor(sx / tileWidth), 0); x <= MathUtils
.min(MathUtils.floor((sx + w - 1) / tileWidth), width - 1); x++) {
for (int y = MathUtils.max(MathUtils.floor(sy / tileHeight), 0); y <= MathUtils
.min(MathUtils.floor((sy + h - 1) / tileHeight), height - 1); y++) {
tiles[x][y] = tiles[x][y].touch(sprite, x * tileWidth, y
* tileHeight);
}
}
}
public boolean drawSub(LTexturePack pack) {
return draw(pack, minX, minY, maxX, maxY);
}
public boolean draw(LTexturePack pack) {
return draw(pack, 0, 0);
}
public boolean draw(LTexturePack pack, int minX, int minY) {
return draw(pack, minX, minY, limitWidth - minX, limitHeight - minY);
}
public boolean draw(final LTexturePack pack, int minX, int minY, int maxX,
int maxY) {
int lazy = 1;
lazy = LSystem.unite(lazy, minX);
lazy = LSystem.unite(lazy, minY);
lazy = LSystem.unite(lazy, maxX);
lazy = LSystem.unite(lazy, maxY);
lazy = LSystem.unite(lazy, dirty);
lazy = LSystem.unite(lazy, isLightDirty);
if (dirty) {
update();
}
LTexturePack currentPack = null;
long elapsedTime = 0;
int size = 0;
if (screen != null) {
if (bindPackName == null
|| pack.getName().equalsIgnoreCase(bindPackName)) {
currentPack = pack;
} else {
if (screen instanceof Screen) {
ScriptScreen script = (ScriptScreen) screen;
currentPack = script.getPack(bindPackName);
if (currentPack == null) {
currentPack = pack;
}
size = script.getPackSprites().size();
}
}
elapsedTime = screen.elapsedTime;
} else {
currentPack = pack;
}
if (lightingOn) {
GLUtils.setShadeModelSmooth(GLEx.gl10);
}
boolean update = (size != 0 && currentPack == pack);
GLEx gl = GLEx.self;
int old = gl.getBlendMode();
gl.setBlendMode(GL.MODE_SPEED);
if (update || lazy != lazyHashCode) {
currentPack.glBegin();
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
PackTile tile = tiles[x][y];
if (tile != null) {
sx = minX + x;
sy = minY + y;
if (sx + tile.width() < minX || sx > maxX
|| sy + tile.height() < minY || sy > maxY) {
continue;
}
if (lightingOn) {
setLightColor(sx, sy);
}
tile.update(elapsedTime);
tile.draw(currentPack,
posX + view.worldToRealX(sx * tileWidth), posY
+ view.worldToRealY(sy * tileHeight),
colors);
}
}
}
currentPack.glEnd();
lazyHashCode = lazy;
} else {
currentPack.glCache();
}
gl.setBlendMode(old);
if (lightingOn) {
GLUtils.setShadeModelFlat(GLEx.gl10);
}
return update;
}
public String getName() {
return name;
}
public PackTileFactory getTileFactory() {
return tileFactory;
}
public void setTileFactory(PackTileFactory tileFactory) {
this.tileFactory = tileFactory;
this.dirty = true;
}
public int getTileWidth() {
return tileWidth;
}
public int getTileHeight() {
return tileHeight;
}
public Field2D getField2D() {
return field;
}
public int[] getLimit() {
return limit;
}
public PackView getView() {
return view;
}
public void setView(PackView view) {
this.view = view;
}
public int getPosX() {
return posX;
}
public void setPosX(int posX) {
this.posX = posX;
}
public int getPosY() {
return posY;
}
public void setPosY(int posY) {
this.posY = posY;
}
public void setPos(int x, int y) {
this.posX = x;
this.posY = y;
}
public Screen getScreen() {
return screen;
}
@Override
public void dispose() {
if (tiles != null) {
tiles = null;
}
if (field != null) {
field = null;
}
if (tileFactory != null) {
if (tileFactory instanceof SimplePackTileFactory) {
tileFactory = null;
}
}
dirty = false;
init = false;
}
}