import java.awt.*;
import java.awt.image.BufferedImage;
-import java.awt.image.DataBufferByte;
+import java.awt.image.DataBufferInt;
import java.awt.image.WritableRaster;
/**
public class RenderingContext {
/**
- * The {@link BufferedImage} pixel format used for the rendering buffer (4-byte ABGR).
+ * The {@link BufferedImage} pixel format used for the rendering buffer.
+ * TYPE_INT_RGB provides optimal performance for Java2D blitting.
*/
- public static final int bufferedImageType = BufferedImage.TYPE_4BYTE_ABGR;
+ public static final int bufferedImageType = BufferedImage.TYPE_INT_RGB;
/**
* Java2D graphics context for drawing text, anti-aliased shapes, and other
/**
* Pixels of the rendering area.
- * Each pixel is represented by 4 bytes: alpha, blue, green, red.
+ * Each pixel is a single int in RGB format: {@code (r << 16) | (g << 8) | b}.
*/
- public final byte[] pixels;
+ public final int[] pixels;
/**
* Width of the rendering area in pixels.
bufferedImage = new BufferedImage(width, height, bufferedImageType);
final WritableRaster raster = bufferedImage.getRaster();
- final DataBufferByte dbi = (DataBufferByte) raster.getDataBuffer();
+ final DataBufferInt dbi = (DataBufferInt) raster.getDataBuffer();
pixels = dbi.getData();
graphics = (Graphics2D) bufferedImage.getGraphics();
if (onScreenCappedXEnd > targetRenderingArea.width)
onScreenCappedXEnd = targetRenderingArea.width;
- final byte[] targetRenderingAreaBytes = targetRenderingArea.pixels;
+ final int[] targetRenderingAreaPixels = targetRenderingArea.pixels;
final int textureWidth = textureBitmap.width;
final int sourceBitmapScanlinePixel = ((textureBitmap.height * (y - onScreenUncappedYStart)) / onScreenUncappedHeight)
* textureWidth;
- int targetRenderingAreaOffset = ((y * targetRenderingArea.width) + onScreenCappedXStart) * 4;
+ int targetRenderingAreaOffset = (y * targetRenderingArea.width) + onScreenCappedXStart;
for (int x = onScreenCappedXStart; x < onScreenCappedXEnd; x++) {
- final int sourceBitmapPixelAddress = (sourceBitmapScanlinePixel + ((textureWidth * (x - onScreenUncappedXStart)) / onScreenUncappedWidth)) * 4;
+ final int sourceBitmapPixelAddress = sourceBitmapScanlinePixel + ((textureWidth * (x - onScreenUncappedXStart)) / onScreenUncappedWidth);
- textureBitmap.drawPixel(sourceBitmapPixelAddress, targetRenderingAreaBytes, targetRenderingAreaOffset);
+ textureBitmap.drawPixel(sourceBitmapPixelAddress, targetRenderingAreaPixels, targetRenderingAreaOffset);
- targetRenderingAreaOffset += 4;
+ targetRenderingAreaOffset++;
}
}
}
for (int x = 0; x < TEXTURE_RESOLUTION_PIXELS; x++)
for (int y = 0; y < TEXTURE_RESOLUTION_PIXELS; y++) {
- int address = texture.primaryBitmap.getAddress(x, y);
-
final int distanceFromCenter = (int) sqrt(pow(halfResolution - x, 2) + pow(halfResolution - y, 2));
int alpha = 255 - ((270 * distanceFromCenter) / halfResolution);
if (alpha < 0)
alpha = 0;
- texture.primaryBitmap.bytes[address] = (byte) alpha;
- address++;
- texture.primaryBitmap.bytes[address] = (byte) color.b;
- address++;
- texture.primaryBitmap.bytes[address] = (byte) color.g;
- address++;
- texture.primaryBitmap.bytes[address] = (byte) color.r;
+ texture.primaryBitmap.pixels[texture.primaryBitmap.getAddress(x, y)] =
+ (alpha << 24) | (color.r << 16) | (color.g << 8) | color.b;
}
return texture;
final int drawnWidth = x2 - x1;
- int offset = ((y * renderBuffer.width) + x1) * 4;
- final byte[] offSreenBufferBytes = renderBuffer.pixels;
+ int offset = (y * renderBuffer.width) + x1;
+ final int[] pixels = renderBuffer.pixels;
final int lineAlpha = color.a;
- final int colorB = color.b;
- final int colorG = color.g;
final int colorR = color.r;
+ final int colorG = color.g;
+ final int colorB = color.b;
for (int i = 0; i < drawnWidth; i++) {
final int realLineAlpha = (int) (lineAlpha * alphaMultiplier);
final int backgroundAlpha = 255 - realLineAlpha;
- offSreenBufferBytes[offset] = (byte) 255;
- offset++;
- offSreenBufferBytes[offset] = (byte) ((((offSreenBufferBytes[offset] & 0xff) * backgroundAlpha) + (colorB * realLineAlpha)) / 256);
- offset++;
- offSreenBufferBytes[offset] = (byte) ((((offSreenBufferBytes[offset] & 0xff) * backgroundAlpha) + (colorG * realLineAlpha)) / 256);
- offset++;
- offSreenBufferBytes[offset] = (byte) ((((offSreenBufferBytes[offset] & 0xff) * backgroundAlpha) + (colorR * realLineAlpha)) / 256);
- offset++;
+ final int dest = pixels[offset];
+ final int destR = (dest >> 16) & 0xff;
+ final int destG = (dest >> 8) & 0xff;
+ final int destB = dest & 0xff;
+
+ final int newR = ((destR * backgroundAlpha) + (colorR * realLineAlpha)) / 256;
+ final int newG = ((destG * backgroundAlpha) + (colorG * realLineAlpha)) / 256;
+ final int newB = ((destB * backgroundAlpha) + (colorB * realLineAlpha)) / 256;
+
+ pixels[offset++] = (newR << 16) | (newG << 8) | newB;
d1 += dinc;
}
if (lineWidth == 0)
return;
- final byte[] offSreenBufferBytes = buffer.pixels;
+ final int[] pixels = buffer.pixels;
final int backgroundAlpha = 255 - alpha;
- final int blueWithAlpha = color.b * alpha;
- final int greenWithAplha = color.g * alpha;
final int redWithAlpha = color.r * alpha;
+ final int greenWithAplha = color.g * alpha;
+ final int blueWithAlpha = color.b * alpha;
for (int relativeX = 0; relativeX <= lineWidth; relativeX++) {
final int x = xStart + relativeX;
final int y = yBase + ((relativeX * lineHeight) / lineWidth);
if ((y >= 0) && (y < buffer.height)) {
- int ramOffset = ((y * buffer.width) + x) * 4;
-
- offSreenBufferBytes[ramOffset] = (byte) 255;
- ramOffset++;
- offSreenBufferBytes[ramOffset] = (byte) ((((offSreenBufferBytes[ramOffset] & 0xff) * backgroundAlpha) + blueWithAlpha) / 256);
- ramOffset++;
- offSreenBufferBytes[ramOffset] = (byte) ((((offSreenBufferBytes[ramOffset] & 0xff) * backgroundAlpha) + greenWithAplha) / 256);
- ramOffset++;
- offSreenBufferBytes[ramOffset] = (byte) ((((offSreenBufferBytes[ramOffset] & 0xff) * backgroundAlpha) + redWithAlpha) / 256);
+ int offset = (y * buffer.width) + x;
+
+ final int dest = pixels[offset];
+ final int destR = (dest >> 16) & 0xff;
+ final int destG = (dest >> 8) & 0xff;
+ final int destB = dest & 0xff;
+
+ final int newR = ((destR * backgroundAlpha) + redWithAlpha) / 256;
+ final int newG = ((destG * backgroundAlpha) + greenWithAplha) / 256;
+ final int newB = ((destB * backgroundAlpha) + blueWithAlpha) / 256;
+
+ pixels[offset] = (newR << 16) | (newG << 8) | newB;
}
}
}
if (lineHeight == 0)
return;
- final byte[] offScreenBufferBytes = buffer.pixels;
+ final int[] pixels = buffer.pixels;
final int backgroundAlpha = 255 - alpha;
- final int blueWithAlpha = color.b * alpha;
- final int greenWithAlpha = color.g * alpha;
final int redWithAlpha = color.r * alpha;
+ final int greenWithAlpha = color.g * alpha;
+ final int blueWithAlpha = color.b * alpha;
for (int relativeY = 0; relativeY <= lineHeight; relativeY++) {
final int y = yStart + relativeY;
final int x = xBase + ((relativeY * lineWidth) / lineHeight);
if ((x >= 0) && (x < buffer.width)) {
- int ramOffset = ((y * buffer.width) + x) * 4;
-
- offScreenBufferBytes[ramOffset] = (byte) 255;
- ramOffset++;
- offScreenBufferBytes[ramOffset] = (byte) ((((offScreenBufferBytes[ramOffset] & 0xff) * backgroundAlpha) + blueWithAlpha) / 256);
- ramOffset++;
- offScreenBufferBytes[ramOffset] = (byte) ((((offScreenBufferBytes[ramOffset] & 0xff) * backgroundAlpha) + greenWithAlpha) / 256);
- ramOffset++;
- offScreenBufferBytes[ramOffset] = (byte) ((((offScreenBufferBytes[ramOffset] & 0xff) * backgroundAlpha) + redWithAlpha) / 256);
+ int offset = (y * buffer.width) + x;
+
+ final int dest = pixels[offset];
+ final int destR = (dest >> 16) & 0xff;
+ final int destG = (dest >> 8) & 0xff;
+ final int destB = dest & 0xff;
+
+ final int newR = ((destR * backgroundAlpha) + redWithAlpha) / 256;
+ final int newG = ((destG * backgroundAlpha) + greenWithAlpha) / 256;
+ final int newB = ((destB * backgroundAlpha) + blueWithAlpha) / 256;
+
+ pixels[offset] = (newR << 16) | (newG << 8) | newB;
}
}
}
final int width = x2 - x1;
- int offset = ((y * renderBuffer.width) + x1) * 4;
- final byte[] offScreenBufferBytes = renderBuffer.pixels;
+ int offset = (y * renderBuffer.width) + x1;
+ final int[] pixels = renderBuffer.pixels;
final int polygonAlpha = color.a;
- final int b = color.b;
- final int g = color.g;
final int r = color.r;
+ final int g = color.g;
+ final int b = color.b;
- if (polygonAlpha == 255)
- for (int i = 0; i < width; i++) {
- offScreenBufferBytes[offset] = (byte) 255;
- offset++;
- offScreenBufferBytes[offset] = (byte) b;
- offset++;
- offScreenBufferBytes[offset] = (byte) g;
- offset++;
- offScreenBufferBytes[offset] = (byte) r;
- offset++;
- }
- else {
+ if (polygonAlpha == 255) {
+ final int pixel = (r << 16) | (g << 8) | b;
+ for (int i = 0; i < width; i++)
+ pixels[offset++] = pixel;
+ } else {
final int backgroundAlpha = 255 - polygonAlpha;
- final int blueWithAlpha = b * polygonAlpha;
- final int greenWithAlpha = g * polygonAlpha;
final int redWithAlpha = r * polygonAlpha;
+ final int greenWithAlpha = g * polygonAlpha;
+ final int blueWithAlpha = b * polygonAlpha;
for (int i = 0; i < width; i++) {
- offScreenBufferBytes[offset] = (byte) 255;
- offset++;
- offScreenBufferBytes[offset] = (byte) ((((offScreenBufferBytes[offset] & 0xff) * backgroundAlpha) + blueWithAlpha) / 256);
- offset++;
- offScreenBufferBytes[offset] = (byte) ((((offScreenBufferBytes[offset] & 0xff) * backgroundAlpha) + greenWithAlpha) / 256);
- offset++;
- offScreenBufferBytes[offset] = (byte) ((((offScreenBufferBytes[offset] & 0xff) * backgroundAlpha) + redWithAlpha) / 256);
- offset++;
- }
+ final int dest = pixels[offset];
+ final int destR = (dest >> 16) & 0xff;
+ final int destG = (dest >> 8) & 0xff;
+ final int destB = dest & 0xff;
+
+ final int newR = ((destR * backgroundAlpha) + redWithAlpha) / 256;
+ final int newG = ((destG * backgroundAlpha) + greenWithAlpha) / 256;
+ final int newB = ((destB * backgroundAlpha) + blueWithAlpha) / 256;
+ pixels[offset++] = (newR << 16) | (newG << 8) | newB;
+ }
}
}
if (x2 >= renderBuffer.width)
x2 = renderBuffer.width - 1;
- int renderBufferOffset = ((y * renderBuffer.width) + x1) * 4;
- final byte[] renderBufferBytes = renderBuffer.pixels;
+ int renderBufferOffset = (y * renderBuffer.width) + x1;
+ final int[] renderBufferPixels = renderBuffer.pixels;
final double twidth = tx2 - tx1;
final double theight = ty2 - ty1;
final int textureOffset = textureBitmap.getAddress((int) tx,
(int) ty);
- textureBitmap.drawPixel(textureOffset, renderBufferBytes,
+ textureBitmap.drawPixel(textureOffset, renderBufferPixels,
renderBufferOffset);
- renderBufferOffset += 4;
+ renderBufferOffset++;
}
}
*/
package eu.svjatoslav.sixth.e3d.renderer.raster.texture;
-import eu.svjatoslav.sixth.e3d.gui.RenderingContext;
-
import java.awt.*;
import java.awt.image.BufferedImage;
-import java.awt.image.DataBufferByte;
+import java.awt.image.DataBufferInt;
import java.awt.image.WritableRaster;
import static java.util.Arrays.fill;
upSampled = new TextureBitmap[maxUpscale];
final BufferedImage bufferedImage = new BufferedImage(width, height,
- RenderingContext.bufferedImageType);
+ BufferedImage.TYPE_INT_ARGB);
final WritableRaster raster = bufferedImage.getRaster();
- final DataBufferByte dbi = (DataBufferByte) raster.getDataBuffer();
+ final DataBufferInt dbi = (DataBufferInt) raster.getDataBuffer();
graphics = (Graphics2D) bufferedImage.getGraphics();
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
* A helper class that accumulates color values for a given area of a bitmap
*/
public static class ColorAccumulator {
- // Accumulated color values
public int r, g, b, a;
- // Number of pixels that have been accumulated
public int pixelCount = 0;
/**
*/
public void accumulate(final TextureBitmap bitmap, final int x,
final int y) {
- int address = bitmap.getAddress(x, y);
-
- a += bitmap.bytes[address] & 0xff;
- address++;
-
- b += bitmap.bytes[address] & 0xff;
- address++;
-
- g += bitmap.bytes[address] & 0xff;
- address++;
-
- r += bitmap.bytes[address] & 0xff;
-
+ final int pixel = bitmap.pixels[bitmap.getAddress(x, y)];
+ a += (pixel >> 24) & 0xff;
+ r += (pixel >> 16) & 0xff;
+ g += (pixel >> 8) & 0xff;
+ b += pixel & 0xff;
pixelCount++;
}
*/
public void storeResult(final TextureBitmap bitmap, final int x,
final int y) {
- int address = bitmap.getAddress(x, y);
-
- bitmap.bytes[address] = (byte) (a / pixelCount);
- address++;
-
- bitmap.bytes[address] = (byte) (b / pixelCount);
- address++;
-
- bitmap.bytes[address] = (byte) (g / pixelCount);
- address++;
-
- bitmap.bytes[address] = (byte) (r / pixelCount);
+ final int avgA = a / pixelCount;
+ final int avgR = r / pixelCount;
+ final int avgG = g / pixelCount;
+ final int avgB = b / pixelCount;
+ bitmap.pixels[bitmap.getAddress(x, y)] = (avgA << 24) | (avgR << 16) | (avgG << 8) | avgB;
}
}
import eu.svjatoslav.sixth.e3d.renderer.raster.Color;
/**
- * Represents a single resolution level of a texture as a raw byte array.
+ * Represents a single resolution level of a texture as a raw int array.
*
- * <p>Each pixel is stored as 4 consecutive bytes in ABGR order:
- * Alpha, Blue, Green, Red. This byte ordering matches the
- * {@link java.awt.image.BufferedImage#TYPE_4BYTE_ABGR} format used by
- * the rendering pipeline.</p>
+ * <p>Each pixel is stored as a single int in ARGB format:
+ * {@code (alpha << 24) | (red << 16) | (green << 8) | blue}.
+ * This matches the {@link java.awt.image.BufferedImage#TYPE_INT_ARGB} format.</p>
*
* <p>{@code TextureBitmap} is used internally by {@link Texture} to represent
* individual mipmap levels. The {@link #multiplicationFactor} records the
*
* <p>This class provides low-level pixel operations including:</p>
* <ul>
- * <li>Alpha-blended pixel transfer to a target raster ({@link #drawPixel(int, byte[], int)})</li>
+ * <li>Alpha-blended pixel transfer to a target raster ({@link #drawPixel(int, int[], int)})</li>
* <li>Direct pixel writes using engine {@link Color} ({@link #drawPixel(int, int, Color)})</li>
* <li>Filled rectangle drawing ({@link #drawRectangle(int, int, int, int, Color)})</li>
* <li>Full-surface color fill ({@link #fillColor(Color)})</li>
public class TextureBitmap {
/**
- * Raw pixel data in ABGR byte order (Alpha, Blue, Green, Red).
- * The array length is {@code width * height * 4}.
+ * Raw pixel data in ARGB int format.
+ * Each int encodes: {@code (alpha << 24) | (red << 16) | (green << 8) | blue}.
+ * The array length is {@code width * height}.
*/
- public final byte[] bytes;
+ public final int[] pixels;
/**
* The width of this bitmap in pixels.
*/
public double multiplicationFactor;
- /**
- * Creates a texture bitmap backed by an existing byte array.
+/**
+ * Creates a texture bitmap backed by an existing int array.
*
* <p>This constructor is typically used when the bitmap data is obtained from
* a {@link java.awt.image.BufferedImage}'s raster, allowing direct access to
*
* @param width the bitmap width in pixels
* @param height the bitmap height in pixels
- * @param bytes the raw pixel data array (must be at least {@code width * height * 4} bytes)
+ * @param pixels the raw pixel data array (must be at least {@code width * height} ints)
* @param multiplicationFactor the scale factor relative to the native texture resolution
*/
- public TextureBitmap(final int width, final int height, final byte[] bytes,
- final double multiplicationFactor) {
+ public TextureBitmap(final int width, final int height, final int[] pixels,
+ final double multiplicationFactor) {
this.width = width;
this.height = height;
- this.bytes = bytes;
+ this.pixels = pixels;
this.multiplicationFactor = multiplicationFactor;
}
/**
- * Creates a texture bitmap with a newly allocated byte array.
+ * Creates a texture bitmap with a newly allocated int array.
*
* <p>The pixel data array is initialized to all zeros (fully transparent black).</p>
*
* @param multiplicationFactor the scale factor relative to the native texture resolution
*/
public TextureBitmap(final int width, final int height,
- final double multiplicationFactor) {
+ final double multiplicationFactor) {
- this(width, height, new byte[width * height * 4], multiplicationFactor);
+ this(width, height, new int[width * height], multiplicationFactor);
}
/**
- * Transfer (render) one pixel from current {@link TextureBitmap} to target raster bitmap.
+ * Transfer (render) one pixel from current {@link TextureBitmap} to target RGB raster.
*
- * @param sourceBitmapPixelAddress Pixel address within current {@link TextureBitmap} as indicated by its offset.
- * @param targetBitmap Bitmap of the target image where pixel should be rendered to.
- * @param targetBitmapPixelAddress Pixel location within target image where pixel should be rendered to.
+ * <p>This texture stores pixels in ARGB format. The target is RGB format (no alpha).
+ * Alpha blending is performed based on the source pixel's alpha value.</p>
+ *
+ * @param sourcePixelAddress Pixel index within current texture.
+ * @param targetBitmap Target RGB pixel array.
+ * @param targetPixelAddress Pixel index within target image.
*/
- public void drawPixel(int sourceBitmapPixelAddress,
- final byte[] targetBitmap, int targetBitmapPixelAddress) {
+ public void drawPixel(final int sourcePixelAddress,
+ final int[] targetBitmap, final int targetPixelAddress) {
- final int textureAlpha = bytes[sourceBitmapPixelAddress] & 0xff;
+ final int sourcePixel = pixels[sourcePixelAddress];
+ final int textureAlpha = (sourcePixel >> 24) & 0xff;
if (textureAlpha == 0)
return;
if (textureAlpha == 255) {
- // skip reading of background for fully opaque pixels
- targetBitmap[targetBitmapPixelAddress] = (byte) 255;
-
- targetBitmapPixelAddress++;
- sourceBitmapPixelAddress++;
- targetBitmap[targetBitmapPixelAddress] = bytes[sourceBitmapPixelAddress];
-
- targetBitmapPixelAddress++;
- sourceBitmapPixelAddress++;
- targetBitmap[targetBitmapPixelAddress] = bytes[sourceBitmapPixelAddress];
-
- targetBitmapPixelAddress++;
- sourceBitmapPixelAddress++;
- targetBitmap[targetBitmapPixelAddress] = bytes[sourceBitmapPixelAddress];
+ targetBitmap[targetPixelAddress] = sourcePixel;
return;
}
final int backgroundAlpha = 255 - textureAlpha;
- sourceBitmapPixelAddress++;
- targetBitmap[targetBitmapPixelAddress] = (byte) 255;
- targetBitmapPixelAddress++;
+ final int srcR = (sourcePixel >> 16) & 0xff;
+ final int srcG = (sourcePixel >> 8) & 0xff;
+ final int srcB = sourcePixel & 0xff;
- targetBitmap[targetBitmapPixelAddress] = (byte) ((((targetBitmap[targetBitmapPixelAddress] & 0xff) * backgroundAlpha) + ((bytes[sourceBitmapPixelAddress] & 0xff) * textureAlpha)) / 256);
- sourceBitmapPixelAddress++;
- targetBitmapPixelAddress++;
+ final int destPixel = targetBitmap[targetPixelAddress];
+ final int destR = (destPixel >> 16) & 0xff;
+ final int destG = (destPixel >> 8) & 0xff;
+ final int destB = destPixel & 0xff;
- targetBitmap[targetBitmapPixelAddress] = (byte) ((((targetBitmap[targetBitmapPixelAddress] & 0xff) * backgroundAlpha) + ((bytes[sourceBitmapPixelAddress] & 0xff) * textureAlpha)) / 256);
- sourceBitmapPixelAddress++;
- targetBitmapPixelAddress++;
+ final int r = ((destR * backgroundAlpha) + (srcR * textureAlpha)) / 256;
+ final int g = ((destG * backgroundAlpha) + (srcG * textureAlpha)) / 256;
+ final int b = ((destB * backgroundAlpha) + (srcB * textureAlpha)) / 256;
- targetBitmap[targetBitmapPixelAddress] = (byte) ((((targetBitmap[targetBitmapPixelAddress] & 0xff) * backgroundAlpha) + ((bytes[sourceBitmapPixelAddress] & 0xff) * textureAlpha)) / 256);
+ targetBitmap[targetPixelAddress] = (r << 16) | (g << 8) | b;
}
/**
* @param color the color to write
*/
public void drawPixel(final int x, final int y, final Color color) {
- int address = getAddress(x, y);
-
- bytes[address] = (byte) color.a;
-
- address++;
- bytes[address] = (byte) color.b;
-
- address++;
- bytes[address] = (byte) color.g;
-
- address++;
- bytes[address] = (byte) color.r;
+ pixels[getAddress(x, y)] = (color.a << 24) | (color.r << 16) | (color.g << 8) | color.b;
}
/**
* @param color the color to fill the entire bitmap with
*/
public void fillColor(final Color color) {
- int address = 0;
- while (address < bytes.length) {
- bytes[address] = (byte) color.a;
- address++;
-
- bytes[address] = (byte) color.b;
- address++;
-
- bytes[address] = (byte) color.g;
- address++;
-
- bytes[address] = (byte) color.r;
- address++;
- }
+ final int pixel = (color.a << 24) | (color.r << 16) | (color.g << 8) | color.b;
+ for (int i = 0; i < pixels.length; i++)
+ pixels[i] = pixel;
}
/**
- * Computes the byte offset into the {@link #bytes} array for the pixel at ({@code x}, {@code y}).
+ * Computes the index into the {@link #pixels} array for the pixel at ({@code x}, {@code y}).
*
* <p>Coordinates are clamped to the valid range {@code [0, width-1]} and
* {@code [0, height-1]} so that out-of-bounds accesses are safely handled
*
* @param x the x coordinate of the pixel
* @param y the y coordinate of the pixel
- * @return the byte offset of the first component (alpha) for the specified pixel
+ * @return the index into the pixels array for the specified pixel
*/
public int getAddress(int x, int y) {
if (x < 0)
if (y >= height)
y = height - 1;
- return ((y * width) + x) * 4;
+ return (y * width) + x;
}
}