javauis/lcdui_qt/src/javax/microedition/lcdui/game/TiledLayer.java
changeset 21 2a9601315dfc
child 23 98ccebc37403
equal deleted inserted replaced
18:e8e63152f320 21:2a9601315dfc
       
     1 /*
       
     2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description: 
       
    15 *
       
    16 */
       
    17 package javax.microedition.lcdui.game;
       
    18 
       
    19 import javax.microedition.lcdui.Graphics;
       
    20 import javax.microedition.lcdui.Image;
       
    21 
       
    22 public class TiledLayer extends Layer {
       
    23 
       
    24     // Animated tile array increment
       
    25     private static final int ANIM_ARRAY_INCREMENT = 4;
       
    26 
       
    27     private int rows;
       
    28     private int cols;
       
    29 
       
    30     private int[][] cells;
       
    31     private int[] animArray;
       
    32     private int animCount;
       
    33 
       
    34     public TiledLayer(int cols, int rows, Image tileImage, int tileWidth, int tileHeight) {
       
    35         super(tileImage, tileWidth, tileHeight);
       
    36 
       
    37         if (cols < 1 || rows < 1) {
       
    38             throw new IllegalArgumentException(
       
    39                     MsgRepository.TILEDLAYER_EXCEPTION_INVALID_DIMENSIONS);
       
    40         }
       
    41 
       
    42         this.cols = cols;
       
    43         this.rows = rows;
       
    44         cells = new int[rows][cols];
       
    45         animArray = new int[ANIM_ARRAY_INCREMENT];
       
    46         animCount = 0;
       
    47     }
       
    48 
       
    49     public void setStaticTileSet(Image tileImage, int tileWidth, int tileHeight) {
       
    50         final int oldTileCount = tileCount;
       
    51 
       
    52         setTileImage(tileImage, tileWidth, tileHeight);
       
    53 
       
    54         // If the new static tile set has as many or more tiles, then the
       
    55         // animated tiles and cell contents will be preserved.
       
    56         // If not, the contents of the grid will be cleared (all cells will
       
    57         // contain index 0) and all animated tiles will be deleted.
       
    58         //
       
    59         if (tileCount < oldTileCount) {
       
    60             fillCells(0, 0, cols, rows, 0);
       
    61             animCount = 0;
       
    62         }
       
    63     }
       
    64 
       
    65     public void setCell(int col, int row, int aTileIndex) {
       
    66         validateTileIndex(aTileIndex);
       
    67         cells[row][col] = aTileIndex;
       
    68     }
       
    69 
       
    70     public int getCell(int col, int row) {
       
    71         return cells[row][col];
       
    72     }
       
    73 
       
    74     public void fillCells(int col, int row, int numCols, int numRows, int tileIndex) {
       
    75         if (numCols < 0) {
       
    76             throw new IllegalArgumentException(
       
    77                     MsgRepository.TILEDLAYER_EXCEPTION_INVALID_NUMBER_OF_COLUMNS);
       
    78         }
       
    79         if (numRows < 0) {
       
    80             throw new IllegalArgumentException(
       
    81                     MsgRepository.TILEDLAYER_EXCEPTION_INVALID_NUMBER_OF_ROWS);
       
    82         }
       
    83         validateTileIndex(tileIndex);
       
    84 
       
    85         for (int i = col + numCols; --i >= col;) {
       
    86             cells[row][i] = tileIndex;
       
    87         }
       
    88         for (int i = row + numRows; --i > row;) {
       
    89             System.arraycopy(cells[row], col, cells[i], col, numCols);
       
    90         }
       
    91     }
       
    92 
       
    93     public int createAnimatedTile(int tileIndex) {
       
    94         if (tileIndex < 0 || tileIndex > tileCount) {
       
    95             throw new IndexOutOfBoundsException(
       
    96                     MsgRepository.TILEDLAYER_EXCEPTION_INVALID_TILE_INDEX);
       
    97         }
       
    98 
       
    99         final int index = animCount;
       
   100         checkCapacity(index + 1);
       
   101         animArray[index] = tileIndex;
       
   102         animCount++;
       
   103         return ~index;
       
   104     }
       
   105 
       
   106     /**
       
   107      * Grows the animated tile array if required.
       
   108      */
       
   109     private void checkCapacity(int requiredLength) {
       
   110         int length = animArray.length;
       
   111         if (requiredLength > length) {
       
   112             int[] array = new int[length + ANIM_ARRAY_INCREMENT];
       
   113             System.arraycopy(animArray, 0, array, 0, length);
       
   114             animArray = array;
       
   115         }
       
   116     }
       
   117 
       
   118     public void setAnimatedTile(int animIndex, int tileIndex) {
       
   119         final int index = ~animIndex;
       
   120         if (index >= animCount) {
       
   121             throw new IndexOutOfBoundsException(
       
   122                     MsgRepository.TILEDLAYER_EXCEPTION_INVALID_ANIMTILE_INDEX);
       
   123         }
       
   124         if (tileIndex < 0 || tileIndex > tileCount) {
       
   125             throw new IndexOutOfBoundsException(
       
   126                     MsgRepository.TILEDLAYER_EXCEPTION_INVALID_TILE_INDEX);
       
   127         }
       
   128         animArray[index] = tileIndex;
       
   129     }
       
   130 
       
   131     public int getAnimatedTile(int animIndex) {
       
   132         final int index = ~animIndex;
       
   133         if (index >= animCount) {
       
   134             throw new IndexOutOfBoundsException(
       
   135                     MsgRepository.TILEDLAYER_EXCEPTION_INVALID_ANIMTILE_INDEX);
       
   136         }
       
   137         return animArray[index];
       
   138     }
       
   139 
       
   140     public final int getCellWidth() {
       
   141         return tileWidth;
       
   142     }
       
   143 
       
   144     public final int getCellHeight() {
       
   145         return tileHeight;
       
   146     }
       
   147 
       
   148     public final int getColumns() {
       
   149         return cols;
       
   150     }
       
   151 
       
   152     public final int getRows() {
       
   153         return rows;
       
   154     }
       
   155 
       
   156     public final void paint(Graphics aGraphics) {
       
   157         if (visible) {
       
   158             aGraphics.translate(x, y);
       
   159 
       
   160             int clipX1 = aGraphics.getClipX();
       
   161             int clipY1 = aGraphics.getClipY();
       
   162             int clipX2 = clipX1 + aGraphics.getClipWidth();
       
   163             int clipY2 = clipY1 + aGraphics.getClipHeight();
       
   164 
       
   165             final int tw = tileWidth;
       
   166             final int th = tileHeight;
       
   167             final int lw = getWidth(); // layer width
       
   168             final int lh = getHeight(); // layer height
       
   169 
       
   170             clipX1 = (clipX1 < 0 ? 0 : clipX1);
       
   171             clipY1 = (clipY1 < 0 ? 0 : clipY1);
       
   172             clipX2 = (clipX2 > lw ? lw : clipX2);
       
   173             clipY2 = (clipY2 > lh ? lh : clipY2);
       
   174 
       
   175             final int begRow = clipY1 / tileHeight;
       
   176             final int begCol = clipX1 / tileWidth;
       
   177             final int endRow = (clipY2 - 1) / tileHeight;
       
   178             final int endCol = (clipX2 - 1) / tileWidth;
       
   179 
       
   180             int sx = begRow * th;
       
   181             int sy = begCol * tw;
       
   182             int dx;
       
   183             int dy;
       
   184 
       
   185             for (int row = begRow; row <= endRow; row++) {
       
   186                 for (int col = begCol; col <= endCol; col++) {
       
   187                     final int index = validateTileIndex(cells[row][col]);
       
   188                     if (index >= 0) {
       
   189                         // Future performace improvement suggestion: accumulate
       
   190                         // region
       
   191                         //
       
   192                         // We have a visible tile in the clip rect, if its
       
   193                         // bounding rect is disjoint from our accumulated rect,
       
   194                         // we draw what we have accumulated so far and reset our
       
   195                         // accumulation rect, else we just add this tile to the
       
   196                         // accumulation rect.
       
   197                         //
       
   198                         // This helps with the not totally uncommon case of
       
   199                         // cells in the tiled layer containing adjacent tiles
       
   200                         // from the tile image. Accumulating the tiles turns
       
   201                         // multiple bitblt's into a single bitblt, saving a bit
       
   202                         // on setup/teardown/data transfer.
       
   203 
       
   204                         dx = col * tw;
       
   205                         dy = row * th;
       
   206 
       
   207                         int tr = index / tileColumns;
       
   208                         int tc = index % tileColumns;
       
   209 
       
   210                         sx = tc * tw;
       
   211                         sy = tr * th;
       
   212 
       
   213                         aGraphics.drawRegion(tileImage,
       
   214                                 sx, sy,
       
   215                                 tw, th,
       
   216                                 Sprite.TRANS_NONE,
       
   217                                 dx, dy, 0);
       
   218                     }
       
   219                 }
       
   220             }
       
   221 
       
   222             aGraphics.translate(-x, -y);
       
   223         }
       
   224     }
       
   225 
       
   226     private int validateTileIndex(int tileIndex) {
       
   227         if (tileIndex > tileCount) {
       
   228             throw new IndexOutOfBoundsException(
       
   229                     MsgRepository.TILEDLAYER_EXCEPTION_INVALID_TILE_INDEX);
       
   230         }
       
   231         // check createAnimatedTile has been called, getAnimatedTile will throw
       
   232         // exception if hasn't.
       
   233         if (tileIndex < 0) {
       
   234             tileIndex = getAnimatedTile(tileIndex);
       
   235         }
       
   236         return tileIndex - 1;
       
   237     }
       
   238 
       
   239     boolean collidesCell(int aX1, int aY1, int aX2, int aY2) {
       
   240         // tiled layer rect in painter's coordinates
       
   241         int tlX1 = x;
       
   242         int tlY1 = y;
       
   243         int tlX2 = x + getWidth();
       
   244         int tlY2 = y + getHeight();
       
   245 
       
   246         // compute intersection of TiledLayer bounds and sprite collision
       
   247         // rectangle.
       
   248         tlX1 = Math.max(tlX1, aX1);
       
   249         tlY1 = Math.max(tlY1, aY1);
       
   250         tlX2 = Math.min(tlX2, aX2);
       
   251         tlY2 = Math.min(tlY2, aY2);
       
   252 
       
   253         // return false if empty intersection.
       
   254         if (!((tlX1 < tlX2) && (tlY1 < tlY2))) {
       
   255             return false;
       
   256         }
       
   257 
       
   258         // transform to tiled layer coordinates
       
   259         tlX1 -= x;
       
   260         tlY1 -= y;
       
   261         tlX2 -= x;
       
   262         tlY2 -= y;
       
   263 
       
   264         int startRow = (tlY1 / tileHeight);
       
   265         int startCol = (tlX1 / tileWidth);
       
   266         int endRow = (tlY2 - 1) / tileHeight;
       
   267         int endCol = (tlX2 - 1) / tileWidth;
       
   268 
       
   269         for (int row = startRow; row <= endRow; row++) {
       
   270             for (int col = startCol; col <= endCol; col++) {
       
   271                 if (cells[row][col] != 0) {
       
   272                     // at least one cell is not empty
       
   273                     return true;
       
   274                 }
       
   275             }
       
   276         }
       
   277 
       
   278         // all cells in overlap are empty
       
   279         return false;
       
   280     }
       
   281 
       
   282     int getLayerWidth() {
       
   283         return cols * tileWidth;
       
   284     }
       
   285 
       
   286     int getLayerHeight() {
       
   287         return rows * tileHeight;
       
   288     }
       
   289 }