diff -r 6c158198356e -r ae942d28ec0e javauis/lcdui_qt/src/javax/microedition/lcdui/game/TiledLayer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javauis/lcdui_qt/src/javax/microedition/lcdui/game/TiledLayer.java Tue Aug 31 15:09:22 2010 +0300 @@ -0,0 +1,329 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +*/ +package javax.microedition.lcdui.game; + +import javax.microedition.lcdui.Graphics; +import javax.microedition.lcdui.Image; + +public class TiledLayer extends Layer +{ + + // Animated tile array increment + private static final int ANIM_ARRAY_INCREMENT = 4; + + private int rows; + private int cols; + + private int[][] cells; + private int[] animArray; + private int animCount; + + public TiledLayer(int cols, int rows, Image tileImage, int tileWidth, int tileHeight) + { + super(tileImage, tileWidth, tileHeight); + + if(cols < 1 || rows < 1) + { + throw new IllegalArgumentException( + MsgRepository.TILEDLAYER_EXCEPTION_INVALID_DIMENSIONS); + } + + this.cols = cols; + this.rows = rows; + cells = new int[rows][cols]; + animArray = new int[ANIM_ARRAY_INCREMENT]; + animCount = 0; + } + + public void setStaticTileSet(Image tileImage, int tileWidth, int tileHeight) + { + final int oldTileCount = tileCount; + + setTileImage(tileImage, tileWidth, tileHeight); + + // If the new static tile set has as many or more tiles, then the + // animated tiles and cell contents will be preserved. + // If not, the contents of the grid will be cleared (all cells will + // contain index 0) and all animated tiles will be deleted. + // + if(tileCount < oldTileCount) + { + fillCells(0, 0, cols, rows, 0); + animCount = 0; + } + } + + public void setCell(int col, int row, int aTileIndex) + { + validateTileIndex(aTileIndex); + cells[row][col] = aTileIndex; + } + + public int getCell(int col, int row) + { + return cells[row][col]; + } + + public void fillCells(int col, int row, int numCols, int numRows, int tileIndex) + { + if(numCols < 0) + { + throw new IllegalArgumentException( + MsgRepository.TILEDLAYER_EXCEPTION_INVALID_NUMBER_OF_COLUMNS); + } + if(numRows < 0) + { + throw new IllegalArgumentException( + MsgRepository.TILEDLAYER_EXCEPTION_INVALID_NUMBER_OF_ROWS); + } + validateTileIndex(tileIndex); + + for(int i = col + numCols; --i >= col;) + { + cells[row][i] = tileIndex; + } + for(int i = row + numRows; --i > row;) + { + System.arraycopy(cells[row], col, cells[i], col, numCols); + } + } + + public int createAnimatedTile(int tileIndex) + { + if(tileIndex < 0 || tileIndex > tileCount) + { + throw new IndexOutOfBoundsException( + MsgRepository.TILEDLAYER_EXCEPTION_INVALID_TILE_INDEX); + } + + final int index = animCount; + checkCapacity(index + 1); + animArray[index] = tileIndex; + animCount++; + return ~index; + } + + /** + * Grows the animated tile array if required. + */ + private void checkCapacity(int requiredLength) + { + int length = animArray.length; + if(requiredLength > length) + { + int[] array = new int[length + ANIM_ARRAY_INCREMENT]; + System.arraycopy(animArray, 0, array, 0, length); + animArray = array; + } + } + + public void setAnimatedTile(int animIndex, int tileIndex) + { + final int index = ~animIndex; + if(index >= animCount) + { + throw new IndexOutOfBoundsException( + MsgRepository.TILEDLAYER_EXCEPTION_INVALID_ANIMTILE_INDEX); + } + if(tileIndex < 0 || tileIndex > tileCount) + { + throw new IndexOutOfBoundsException( + MsgRepository.TILEDLAYER_EXCEPTION_INVALID_TILE_INDEX); + } + animArray[index] = tileIndex; + } + + public int getAnimatedTile(int animIndex) + { + final int index = ~animIndex; + if(index >= animCount) + { + throw new IndexOutOfBoundsException( + MsgRepository.TILEDLAYER_EXCEPTION_INVALID_ANIMTILE_INDEX); + } + return animArray[index]; + } + + public final int getCellWidth() + { + return tileWidth; + } + + public final int getCellHeight() + { + return tileHeight; + } + + public final int getColumns() + { + return cols; + } + + public final int getRows() + { + return rows; + } + + public final void paint(Graphics aGraphics) + { + if(visible) + { + aGraphics.translate(x, y); + + int clipX1 = aGraphics.getClipX(); + int clipY1 = aGraphics.getClipY(); + int clipX2 = clipX1 + aGraphics.getClipWidth(); + int clipY2 = clipY1 + aGraphics.getClipHeight(); + + final int tw = tileWidth; + final int th = tileHeight; + final int lw = getWidth(); // layer width + final int lh = getHeight(); // layer height + + clipX1 = (clipX1 < 0 ? 0 : clipX1); + clipY1 = (clipY1 < 0 ? 0 : clipY1); + clipX2 = (clipX2 > lw ? lw : clipX2); + clipY2 = (clipY2 > lh ? lh : clipY2); + + final int begRow = clipY1 / tileHeight; + final int begCol = clipX1 / tileWidth; + final int endRow = (clipY2 - 1) / tileHeight; + final int endCol = (clipX2 - 1) / tileWidth; + + int sx = begRow * th; + int sy = begCol * tw; + int dx; + int dy; + + for(int row = begRow; row <= endRow; row++) + { + for(int col = begCol; col <= endCol; col++) + { + final int index = validateTileIndex(cells[row][col]); + if(index >= 0) + { + // Future performace improvement suggestion: accumulate + // region + // + // We have a visible tile in the clip rect, if its + // bounding rect is disjoint from our accumulated rect, + // we draw what we have accumulated so far and reset our + // accumulation rect, else we just add this tile to the + // accumulation rect. + // + // This helps with the not totally uncommon case of + // cells in the tiled layer containing adjacent tiles + // from the tile image. Accumulating the tiles turns + // multiple bitblt's into a single bitblt, saving a bit + // on setup/teardown/data transfer. + + dx = col * tw; + dy = row * th; + + int tr = index / tileColumns; + int tc = index % tileColumns; + + sx = tc * tw; + sy = tr * th; + + aGraphics.drawRegion(tileImage, + sx, sy, + tw, th, + Sprite.TRANS_NONE, + dx, dy, 0); + } + } + } + + aGraphics.translate(-x, -y); + } + } + + private int validateTileIndex(int tileIndex) + { + if(tileIndex > tileCount) + { + throw new IndexOutOfBoundsException( + MsgRepository.TILEDLAYER_EXCEPTION_INVALID_TILE_INDEX); + } + // check createAnimatedTile has been called, getAnimatedTile will throw + // exception if hasn't. + if(tileIndex < 0) + { + tileIndex = getAnimatedTile(tileIndex); + } + return tileIndex - 1; + } + + boolean collidesCell(int aX1, int aY1, int aX2, int aY2) + { + // tiled layer rect in painter's coordinates + int tlX1 = x; + int tlY1 = y; + int tlX2 = x + getWidth(); + int tlY2 = y + getHeight(); + + // compute intersection of TiledLayer bounds and sprite collision + // rectangle. + tlX1 = Math.max(tlX1, aX1); + tlY1 = Math.max(tlY1, aY1); + tlX2 = Math.min(tlX2, aX2); + tlY2 = Math.min(tlY2, aY2); + + // return false if empty intersection. + if(!((tlX1 < tlX2) && (tlY1 < tlY2))) + { + return false; + } + + // transform to tiled layer coordinates + tlX1 -= x; + tlY1 -= y; + tlX2 -= x; + tlY2 -= y; + + int startRow = (tlY1 / tileHeight); + int startCol = (tlX1 / tileWidth); + int endRow = (tlY2 - 1) / tileHeight; + int endCol = (tlX2 - 1) / tileWidth; + + for(int row = startRow; row <= endRow; row++) + { + for(int col = startCol; col <= endCol; col++) + { + if(cells[row][col] != 0) + { + // at least one cell is not empty + return true; + } + } + } + + // all cells in overlap are empty + return false; + } + + int getLayerWidth() + { + return cols * tileWidth; + } + + int getLayerHeight() + { + return rows * tileHeight; + } +}