/*
Реализация спецификаций 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 malik.emulator.media.graphics;
import malik.emulator.util.*;
public final class RasterBuffer extends Object
{
public static final int MAX_SIZE = 0x7fff;
public static RasterBuffer create(int width, int height, int colorARGB, boolean opaque) {
int len;
int[] pixels;
if(width < 1 || width > MAX_SIZE)
{
throw new IllegalArgumentException("RasterBuffer.create: аргумент width выходит из диапазона.");
}
if(height < 1 || height > MAX_SIZE)
{
throw new IllegalArgumentException("RasterBuffer.create: аргумент height выходит из диапазона.");
}
Array.fill(pixels = new int[len = width * height], 0, len, colorARGB);
return new RasterBuffer(pixels, 0, width, width, height, opaque);
}
public static RasterBuffer create(int[] pixels, int offset, int scanlength, int width, int height, boolean opaque) {
int pixelsOffset;
int pixelsLength;
if(pixels == null)
{
throw new NullPointerException("RasterBuffer.create: аргумент pixels равен нулевой ссылке.");
}
if(scanlength < -MAX_SIZE || scanlength > MAX_SIZE)
{
throw new IllegalArgumentException("RasterBuffer.create: аргумент scanlength выходит из диапазона.");
}
if(width < 1 || width > MAX_SIZE)
{
throw new IllegalArgumentException("RasterBuffer.create: аргумент width выходит из диапазона.");
}
if(height < 1 || height > MAX_SIZE)
{
throw new IllegalArgumentException("RasterBuffer.create: аргумент height выходит из диапазона.");
}
if(scanlength >= 0)
{
pixelsOffset = offset;
pixelsLength = width + (height - 1) * scanlength;
} else
{
pixelsOffset = offset + (height - 1) * scanlength;
pixelsLength = width + offset - pixelsOffset;
}
Array.checkBound("RasterBuffer.create", pixels.length, pixelsOffset, pixelsLength);
return new RasterBuffer(pixels, offset, scanlength, width, height, opaque);
}
public static RasterBuffer create(RasterBuffer source, int left, int top, int width, int height) {
int s;
int lim;
int srcWidth;
int srcHeight;
if(source == null)
{
throw new NullPointerException("RasterBuffer.create: аргумент source равен нулевой ссылке.");
}
if(width < 1 || width > MAX_SIZE)
{
throw new IllegalArgumentException("RasterBuffer.create: аргумент width выходит из диапазона.");
}
if(height < 1 || height > MAX_SIZE)
{
throw new IllegalArgumentException("RasterBuffer.create: аргумент height выходит из диапазона.");
}
if((lim = left + width) > (srcWidth = source.width) || lim < left || left > srcWidth || left < 0)
{
throw new IllegalArgumentException("RasterBuffer.create: заданный регион выходит за пределы растрового буфера.");
}
if((lim = top + height) > (srcHeight = source.height) || lim < top || top > srcHeight || top < 0)
{
throw new IllegalArgumentException("RasterBuffer.create: заданный регион выходит за пределы растрового буфера.");
}
if(left == 0 && top == 0 && width == srcWidth && height == srcHeight)
{
return source;
}
return new RasterBuffer(source.pixels, source.offset + left + top * (s = source.scan), s, width, height, source.opaque);
}
public static RasterBuffer create(RasterBuffer source, Rectangle region) {
if(region == null)
{
throw new NullPointerException("RasterBuffer.create: аргумент region равен нулевой ссылке.");
}
return create(source, region.getLeft(), region.getTop(), region.getWidth(), region.getHeight());
}
private final boolean opaque;
private final int base;
private final int hash;
private final int scan;
private final int size;
private final int width;
private final int height;
private final int offset;
private final int[] pixels;
private RasterBuffer(int[] pixels, int offset, int scanlength, int width, int height, boolean opaque) {
int base;
this.opaque = opaque;
this.base = base = Array.getFirstElementAddress(pixels) + (offset << 2);
this.hash = base ^ (scanlength << 8) ^ width ^ (height << 16);
this.scan = scanlength;
this.size = width | height << 16;
this.width = width;
this.height = height;
this.offset = offset;
this.pixels = pixels;
}
public boolean equals(Object anot) {
RasterBuffer b;
return anot == this || anot instanceof RasterBuffer && opaque == (b = (RasterBuffer) anot).opaque && base == b.base && scan == b.scan && size == b.size;
}
public int hashCode() {
return hash;
}
public String toString() {
return (new StringBuilder()).
append(opaque ? "Растровый буфер[непрозрачный, база=" : "Растровый буфер[полупрозрачный, база=").append(base, 16, false).
append(", скан=").append(scan).append(", размер=").append(width).append("×").append(height).append("]").
toString();
}
public void putPixel(int x, int y, int colorARGB) {
if(x >= 0 && x < width && y >= 0 && y < height) pixels[offset + x + y * scan] = opaque ? colorARGB & 0x00ffffff : colorARGB;
}
public boolean isOpaque() {
return opaque;
}
public int getPixel(int x, int y) {
if(x < 0 || x >= width)
{
throw new IllegalArgumentException("RasterBuffer.getPixel: аргумент x выходит из диапазона.");
}
if(y < 0 || y >= height)
{
throw new IllegalArgumentException("RasterBuffer.getPixel: аргумент y выходит из диапазона.");
}
return pixels[offset + x + y * scan];
}
public int getBase() {
return base;
}
public int getOffset() {
return offset;
}
public int getScanlength() {
return scan;
}
public int getSize() {
return size;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public int[] getPixels() {
return pixels;
}
}