/*
Реализация спецификаций CLDC версии 1.1 (JSR-139), MIDP версии 2.1 (JSR-118)
и других спецификаций для функционирования компактных приложений на языке
Java (мидлетов) в среде программного обеспечения Малик Эмулятор.
Copyright © 2016, 2019 Малик Разработчик
Это свободная программа: вы можете перераспространять ее и/или изменять
ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она будет полезной,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
общественной лицензии GNU.
Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<https://www.gnu.org/licenses/>.
*/
package javax.microedition.lcdui.game;
import javax.microedition.lcdui.*;
public class TiledLayer extends Layer
{
private int cols;
private int rows;
private int tileWidth;
private int tileHeight;
private int tilesCount;
private int tilesPerRow;
private int animatedTilesCount;
private int[] animatedTiles;
private int[] cells;
private Image tileSet;
public TiledLayer(int columns, int rows, Image tileSet, int tileWidth, int tileHeight)
{
super(columns * tileWidth, rows * tileHeight);
int tmp;
int width;
int height;
if(tileSet == null)
{
throw new NullPointerException("TiledLayer: " +
"параметр tileSet равен нулевой ссылке.");
}
if(columns < 1 || rows < 1)
{
throw new IllegalArgumentException("TiledLayer: " +
"размеры замощённого слоя могут быть только положительными.");
}
if(tileWidth < 1 || tileHeight < 1)
{
throw new IllegalArgumentException("TiledLayer: " +
"размеры плиток замощённого слоя могут быть только положительными.");
}
if((width = tileSet.getWidth()) % tileWidth != 0 ||
(height = tileSet.getHeight()) % tileHeight != 0)
{
throw new IllegalArgumentException("TiledLayer: " +
"размеры набора плиток могут только нацело делиться на размеры самих плиток.");
}
this.cols = columns;
this.rows = rows;
this.tileWidth = tileWidth;
this.tileHeight = tileHeight;
this.tilesCount = (tmp = width / tileWidth) * (height / tileHeight);
this.tilesPerRow = tmp;
this.cells = new int[columns * rows];
this.tileSet = tileSet;
}
public void setStaticTileSet(Image tileSet, int tileWidth, int tileHeight)
{
int i;
int tmp;
int width;
int height;
int oldTilesCount;
int newTilesCount;
int[] cls;
if(tileSet == null)
{
throw new NullPointerException("TiledLayer.setStaticTileSet: " +
"параметр tileSet равен нулевой ссылке.");
}
if(tileWidth < 1 || tileHeight < 1)
{
throw new IllegalArgumentException("TiledLayer.setStaticTileSet: " +
"размеры плиток замощённого слоя могут быть только положительными.");
}
if((width = tileSet.getWidth()) % tileWidth != 0 ||
(height = tileSet.getHeight()) % tileHeight != 0)
{
throw new IllegalArgumentException("TiledLayer.setStaticTileSet: " +
"размеры набора плиток могут только нацело делиться на размеры самих плиток.");
}
synchronized(cls = cells)
{
oldTilesCount = this.tilesCount;
setSize(cols * tileWidth, rows* tileHeight);
this.tileWidth = tileWidth;
this.tileHeight = tileHeight;
this.tilesCount = newTilesCount = (tmp = width / tileWidth) * (height / tileHeight);
this.tilesPerRow = tmp;
this.tileSet = tileSet;
if(newTilesCount < oldTilesCount)
{
animatedTilesCount = 0;
animatedTiles = null;
for(i = cls.length; i-- > 0; cls[i] = 0);
}
}
}
public void setAnimatedTile(int animatedTileIndex, int staticTileIndex)
{
int error;
int[] animated;
if(staticTileIndex < 0 || staticTileIndex > tilesCount)
{
throw new IndexOutOfBoundsException("TiledLayer.setAnimatedTile: " +
"параметр staticTileIndex выходит из диапазона.");
}
error = 0;
synchronized(cells)
{
label0:
{
if((animated = animatedTiles) == null ||
(animatedTileIndex = ~animatedTileIndex) < 0 ||
animatedTileIndex >= animatedTilesCount)
{
error = 1;
break label0;
}
animated[animatedTileIndex] = staticTileIndex;
}
}
if(error == 1)
{
throw new IndexOutOfBoundsException("TiledLayer.setAnimatedTile: " +
"параметр animatedTileIndex выходит из диапазона.");
}
}
public void setCell(int col, int row, int tileIndex)
{
int c;
if(col < 0 || col >= (c = cols))
{
throw new IndexOutOfBoundsException("TiledLayer.setCell: " +
"параметр col выходит из диапазона.");
}
if(row < 0 || row >= rows)
{
throw new IndexOutOfBoundsException("TiledLayer.setCell: " +
"параметр row выходит из диапазона.");
}
if(tileIndex < -animatedTilesCount || tileIndex > tilesCount)
{
throw new IndexOutOfBoundsException("TiledLayer.setCell: " +
"параметр tileIndex выходит из диапазона.");
}
cells[col + row * c] = tileIndex;
}
public void fillCells(int col, int row, int numCols, int numRows, int tileIndex)
{
int i;
int j;
int r;
int b;
int c;
int d;
int lim;
int len;
int[] cls;
if((lim = r = col + numCols) > (len = c = cols) || lim < col || col > len || col < 0 ||
(lim = b = row + numRows) > (len = rows) || lim < row || row > len || row < 0)
{
throw new IndexOutOfBoundsException("TiledLayer.fillCells: " +
"индекс выходит из диапазона.");
}
if(tileIndex < -animatedTilesCount || tileIndex > tilesCount)
{
throw new IndexOutOfBoundsException("TiledLayer.fillCells: " +
"параметр tileIndex выходит из диапазона.");
}
for(cls = cells, d = row * c, j = row; j < b; d += c, j++)
{
for(i = col; i < r; i++)
{
cls[i + d] = tileIndex;
}
}
}
public int createAnimatedTile(int staticTileIndex)
{
int result;
int[] animated;
if(staticTileIndex < 0 || staticTileIndex > tilesCount)
{
throw new IndexOutOfBoundsException("TiledLayer.createAnimatedTile: " +
"параметр staticTileIndex выходит из диапазона.");
}
synchronized(cells)
{
result = animatedTilesCount;
if((animated = animatedTiles) == null)
{
animated = animatedTiles = new int[4];
}
else if(result == animated.length)
{
Array.copy(animated, 0,
animated = animatedTiles = new int[result << 1], 0, result);
}
animated[result++] = staticTileIndex;
animatedTilesCount = result;
}
return -result;
}
public int getAnimatedTile(int animatedTileIndex)
{
int error;
int result;
int[] animated;
error = 0;
synchronized(cells)
{
label0:
{
if((animated = animatedTiles) == null ||
(animatedTileIndex = ~animatedTileIndex) < 0 ||
animatedTileIndex >= animatedTilesCount)
{
error = 1;
result = 0;
break label0;
}
result = animated[animatedTileIndex];
}
}
if(error == 1)
{
throw new IndexOutOfBoundsException("TiledLayer.getAnimatedTile: " +
"параметр animatedTileIndex выходит из диапазона.");
}
return result;
}
public int getCell(int col, int row)
{
int c;
if(col < 0 || col >= (c = cols))
{
throw new IndexOutOfBoundsException("TiledLayer.getCell: " +
"параметр col выходит из диапазона.");
}
if(row < 0 || row >= rows)
{
throw new IndexOutOfBoundsException("TiledLayer.getCell: " +
"параметр row выходит из диапазона.");
}
return cells[col + row * c];
}
public final void paint(Graphics render)
{
int i;
int j;
int l;
int t;
int r;
int b;
int c;
int d;
int cell;
int clipLeft;
int clipTop;
int layerLeft;
int layerTop;
int tileWidth;
int tileHeight;
int tilesCount;
int tilesPerRow;
int[] animated;
int[] cls;
Image tileSet;
if(render == null)
{
throw new NullPointerException("TiledLayer.paint: " +
"параметр render равен нулевой ссылке.");
}
if(!isVisible())
{
return;
}
synchronized(cls = cells)
{
clipLeft = render.getClipX();
clipTop = render.getClipY();
layerLeft = getX();
layerTop = getY();
tileWidth = this.tileWidth;
tileHeight = this.tileHeight;
tilesCount = this.tilesCount;
tilesPerRow = this.tilesPerRow;
animated = this.animatedTiles;
tileSet = this.tileSet;
l = Math.max(0, (clipLeft - layerLeft) / tileWidth);
t = Math.max(0, (clipTop - layerTop) / tileHeight);
r = Math.min((c = cols) - 1,
(clipLeft + render.getClipWidth() - layerLeft - 1) / tileWidth);
b = Math.min(rows - 1,
(clipTop + render.getClipHeight() - layerTop - 1) / tileHeight);
for(d = t * c, j = t; j <= b; d += c, j++)
{
for(i = l; i <= r; i++)
{
if((cell = cls[i + d]) < 0)
{
cell = animated[~cell];
}
if(cell == 0 || cell > tilesCount)
{
continue;
}
cell--;
render.drawRegion(tileSet,
(cell % tilesPerRow) * tileWidth, (cell / tilesPerRow) * tileHeight,
tileWidth, tileHeight, 0,
layerLeft + i * tileWidth, layerTop + j * tileHeight,
Graphics.LEFT | Graphics.TOP);
}
}
}
}
public final int getColumns()
{
return cols;
}
public final int getRows()
{
return rows;
}
public final int getCellWidth()
{
return tileWidth;
}
public final int getCellHeight()
{
return tileHeight;
}
final int getTilesPerRow()
{
return tilesPerRow;
}
final int getTileIndex(int col, int row)
{
int result;
if((result = cells[col + row * cols]) < 0)
{
result = animatedTiles[~result];
}
return result;
}
final Image getTileSet()
{
return tileSet;
}
final Object getMonitor()
{
return cells;
}
}