javauis/lcdui_qt/src/javax/microedition/lcdui/game/TiledLayer.java
changeset 21 2a9601315dfc
child 23 98ccebc37403
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javauis/lcdui_qt/src/javax/microedition/lcdui/game/TiledLayer.java	Mon May 03 12:27:20 2010 +0300
@@ -0,0 +1,289 @@
+/*
+* 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;
+    }
+}