/*
Реализация спецификаций CLDC версии 1.1 (JSR-139), MIDP версии 2.1 (JSR-118)
и других спецификаций для функционирования компактных приложений на языке
Java (мидлетов) в среде программного обеспечения Малик Эмулятор.
Copyright © 2016–2017, 2019–2023 Малик Разработчик
Это свободная программа: вы можете перераспространять ее и/или изменять
ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она будет полезной,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
общественной лицензии GNU.
Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<https://www.gnu.org/licenses/>.
*/
package javax.microedition.lcdui.game;
import javax.microedition.lcdui.*;
public class TiledLayer extends Layer
{
private static final int MAX_SIZE = 0x7fff;
private final int cols;
private final int rows;
int tileSetCellWidth;
int tileSetCellHeight;
int tileSetCellsCount;
int tileSetCellsPerRow;
private int animatedTilesCount;
private int[] animatedTiles;
private final int[] staticTiles;
Image tileSet;
public TiledLayer(int cols, int rows, Image tileSet, int cellWidth, int cellHeight) {
int tilesPerRow;
int tileSetWidth;
int tileSetHeight;
if(cols < 1 || cols > MAX_SIZE)
{
throw new IllegalArgumentException("TiledLayer: аргумент cols не может быть меньше 1 или больше " + MAX_SIZE + ".");
}
if(rows < 1 || rows > MAX_SIZE)
{
throw new IllegalArgumentException("TiledLayer: аргумент rows не может быть меньше 1 или больше " + MAX_SIZE + ".");
}
if(tileSet == null)
{
throw new NullPointerException("TiledLayer: аргумент tileSet равен нулевой ссылке.");
}
if(cellWidth < 1 || cellWidth > MAX_SIZE)
{
throw new IllegalArgumentException("TiledLayer: аргумент cellWidth не может быть меньше 1 или больше " + MAX_SIZE + ".");
}
if(cellHeight < 1 || cellHeight > MAX_SIZE)
{
throw new IllegalArgumentException("TiledLayer: аргумент cellHeight не может быть меньше 1 или больше " + MAX_SIZE + ".");
}
if((tileSetWidth = tileSet.getWidth()) % cellWidth != 0 || (tileSetHeight = tileSet.getHeight()) % cellHeight != 0)
{
throw new IllegalArgumentException("TiledLayer: размеры ячеек оба должны быть делителями размеров набора плиток.");
}
this.width = cols * cellWidth;
this.height = rows * cellHeight;
this.cols = cols;
this.rows = rows;
this.tileSetCellWidth = cellWidth;
this.tileSetCellHeight = cellHeight;
this.tileSetCellsCount = (tilesPerRow = tileSetWidth / cellWidth) * (tileSetHeight / cellHeight);
this.tileSetCellsPerRow = tilesPerRow;
this.staticTiles = new int[cols * rows];
this.tileSet = tileSet;
}
public void fillCells(int startCol, int startRow, int numCols, int numRows, int tileIndex) {
int error = 0;
synchronized(monitor)
{
label0:
{
int width;
int[] tiles;
if(numCols < 0)
{
error = 1;
break label0;
}
if(numRows < 0)
{
error = 2;
break label0;
}
if(!Array.isBoundValid(width = cols, startCol, numCols) || !Array.isBoundValid(rows, startRow, numRows))
{
error = 3;
break label0;
}
if(tileIndex < -animatedTilesCount || tileIndex > tileSetCellsCount)
{
error = 4;
break label0;
}
tiles = staticTiles;
for(int offset = startCol + startRow * width, i = numRows; i-- > 0; offset += width) Array.fill(tiles, offset, numCols, tileIndex);
}
}
switch(error)
{
case 1:
throw new IllegalArgumentException("TiledLayer.fillCells: аргумент numCols не может быть отрицательным.");
case 2:
throw new IllegalArgumentException("TiledLayer.fillCells: аргумент numRows не может быть отрицательным.");
case 3:
throw new IndexOutOfBoundsException("TiledLayer.fillCells: индекс выходит из диапазона.");
case 4:
throw new IndexOutOfBoundsException("TiledLayer.fillCells: аргумент tileIndex выходит из диапазона.");
}
}
public void setCell(int col, int row, int tileIndex) {
int error = 0;
synchronized(monitor)
{
label0:
{
int width;
if(col < 0 || col >= (width = cols) || row < 0 || row >= rows)
{
error = 1;
break label0;
}
if(tileIndex < -animatedTilesCount || tileIndex > tileSetCellsCount)
{
error = 2;
break label0;
}
staticTiles[col + row * width] = tileIndex;
}
}
switch(error)
{
case 1:
throw new IndexOutOfBoundsException("TiledLayer.setCell: индекс выходит из диапазона.");
case 2:
throw new IndexOutOfBoundsException("TiledLayer.setCell: аргумент tileIndex выходит из диапазона.");
}
}
public void setAnimatedTile(int animatedTileIndex, int staticTileIndex) {
int error = 0;
synchronized(monitor)
{
label0:
{
if(animatedTileIndex < -animatedTilesCount || animatedTileIndex >= 0)
{
error = 1;
break label0;
}
if(staticTileIndex < 0 || staticTileIndex > tileSetCellsCount)
{
error = 2;
break label0;
}
animatedTiles[~animatedTileIndex] = staticTileIndex;
}
}
switch(error)
{
case 1:
throw new IndexOutOfBoundsException("TiledLayer.setAnimatedTile: аргумент animatedTileIndex выходит из диапазона.");
case 2:
throw new IndexOutOfBoundsException("TiledLayer.setAnimatedTile: аргумент staticTileIndex выходит из диапазона.");
}
}
public void setStaticTileSet(Image tileSet, int cellWidth, int cellHeight) {
int tileSetWidth;
int tileSetHeight;
if(tileSet == null)
{
throw new NullPointerException("TiledLayer.setStaticTileSet: аргумент tileSet равен нулевой ссылке.");
}
if(cellWidth < 1 || cellWidth > MAX_SIZE)
{
throw new IllegalArgumentException("TiledLayer.setStaticTileSet: аргумент cellWidth не может быть меньше 1 или больше " + MAX_SIZE + ".");
}
if(cellHeight < 1 || cellHeight > MAX_SIZE)
{
throw new IllegalArgumentException("TiledLayer.setStaticTileSet: аргумент cellHeight не может быть меньше 1 или больше " + MAX_SIZE + ".");
}
if((tileSetWidth = tileSet.getWidth()) % cellWidth != 0 || (tileSetHeight = tileSet.getHeight()) % cellHeight != 0)
{
throw new IllegalArgumentException("TiledLayer.setStaticTileSet: размеры ячеек оба должны быть делителями размеров набора плиток.");
}
synchronized(monitor)
{
int tilesPerRow;
int newCellsCount;
int oldCellsCount = tileSetCellsCount;
this.width = cols * cellWidth;
this.height = rows * cellHeight;
this.tileSetCellWidth = cellWidth;
this.tileSetCellHeight = cellHeight;
this.tileSetCellsCount = newCellsCount = (tilesPerRow = tileSetWidth / cellWidth) * (tileSetHeight / cellHeight);
this.tileSetCellsPerRow = tilesPerRow;
this.tileSet = tileSet;
if(newCellsCount < oldCellsCount)
{
int[] tiles;
animatedTilesCount = 0;
animatedTiles = null;
Array.fill(tiles = staticTiles, 0, tiles.length, 0);
}
}
}
public int createAnimatedTile(int staticTileIndex) {
int result;
int error = 0;
synchronized(monitor)
{
label0:
{
int len;
int[] tiles;
if(staticTileIndex < 0 || staticTileIndex > tileSetCellsCount)
{
error = 1;
result = 0;
break label0;
}
result = ~(len = animatedTilesCount);
if((tiles = animatedTiles) == null)
{
tiles = animatedTiles = new int[7];
}
else if(len == tiles.length)
{
Array.copy(tiles, 0, tiles = animatedTiles = new int[(len << 1) + 1], 0, len);
}
tiles[len++] = staticTileIndex;
animatedTilesCount = len;
}
}
if(error == 1)
{
throw new IndexOutOfBoundsException("TiledLayer.createAnimatedTile: аргумент staticTileIndex выходит из диапазона.");
}
return result;
}
public int getCell(int col, int row) {
int result;
int error = 0;
synchronized(monitor)
{
label0:
{
int width;
if(col < 0 || col >= (width = cols) || row < 0 || row >= rows)
{
error = 1;
result = 0;
break label0;
}
result = staticTiles[col + row * width];
}
}
if(error == 1)
{
throw new IndexOutOfBoundsException("TiledLayer.getCell: индекс выходит из диапазона.");
}
return result;
}
public int getAnimatedTile(int animatedTileIndex) {
int result;
int error = 0;
synchronized(monitor)
{
label0:
{
if(animatedTileIndex < -animatedTilesCount || animatedTileIndex >= 0)
{
error = 1;
result = 0;
break label0;
}
result = animatedTiles[~animatedTileIndex];
}
}
if(error == 1)
{
throw new IndexOutOfBoundsException("TiledLayer.getAnimatedTile: аргумент animatedTileIndex выходит из диапазона.");
}
return result;
}
public final void paint(Graphics render) {
if(render == null)
{
throw new NullPointerException("TiledLayer.paint: аргумент render равен нулевой ссылке.");
}
if(!visibility) return;
synchronized(monitor)
{
int clip;
int left = this.left;
int top = this.top;
int cols = this.cols;
int rows = this.rows;
int cellWidth = tileSetCellWidth;
int cellHeight = tileSetCellHeight;
int cellsPerRow = tileSetCellsPerRow;
int scol = left > (clip = render.getClipX()) ? 0 : (clip - left) / cellWidth;
int fcol = left > (clip += render.getClipWidth() - 1) ? -1 : (clip - left) / cellWidth;
int srow = top > (clip = render.getClipY()) ? 0 : (clip - top) / cellHeight;
int frow = top > (clip += render.getClipHeight() - 1) ? -1 : (clip - top) / cellHeight;
int[] animatedTiles = this.animatedTiles;
int[] staticTiles = this.staticTiles;
Image tileSet = this.tileSet;
for(int offset = srow * cols, y = top + srow * cellHeight, row = srow; row <= frow && row < rows; offset += cols, y += cellHeight, row++)
{
for(int x = left + scol * cellWidth, col = scol; col <= fcol && col < cols; x += cellWidth, col++)
{
int tileIndex;
if((tileIndex = staticTiles[offset + col]) < 0) tileIndex = animatedTiles[~tileIndex];
if(tileIndex-- > 0)
{
int tileSetLeft = (tileIndex % cellsPerRow) * cellWidth;
int tileSetTop = (tileIndex / cellsPerRow) * cellHeight;
render.drawRegion(tileSet, tileSetLeft, tileSetTop, cellWidth, cellHeight, Sprite.TRANS_NONE, x, y, 0);
}
}
}
}
}
public final int getColumns() {
return cols;
}
public final int getRows() {
return rows;
}
public final int getCellWidth() {
return tileSetCellWidth;
}
public final int getCellHeight() {
return tileSetCellHeight;
}
final int getTileIndex(int col, int row) {
int result;
if((result = staticTiles[col + row * cols]) < 0) result = animatedTiles[~result];
return result;
}
}