166 lines
5.2 KiB
Java
166 lines
5.2 KiB
Java
/*
|
|
*
|
|
* Copyright (C) 2003 Kent Hansen.
|
|
*
|
|
* This file is part of Tile Mangler.
|
|
*
|
|
* Tile Mangler is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* Tile Mangler is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
*/
|
|
|
|
package tm.tilecodecs;
|
|
|
|
/**
|
|
*
|
|
* Linear palette-indexed 8x8 tile codec. Max. 8 bits per pixel.
|
|
* bitsPerPixel mod 2 = 0 (so only 1, 2, 4, 8bpp possible).
|
|
*
|
|
* Some notes on "pixel ordering":
|
|
*
|
|
* I define pixel order for a row like so: 0 1 2 3 4 5 6 7.
|
|
* In other words, pixels are numbered from leftmost to rightmost,
|
|
* as they appear on screen.
|
|
* I define bit order in a byte like so: 7 6 5 4 3 2 1 0.
|
|
* In other words, bits are numbered from rightmost (high) to leftmost (low).
|
|
*
|
|
* For formats with less than 8 bits per pixel, it is then an
|
|
* issue how bits are extracted from the bytes of encoded tile data
|
|
* to form the order of pixels stated above.
|
|
*
|
|
* Note that this applies at the PIXEL-level, not bit-, byte- or row-level;
|
|
* this is why ordering is not an issue for 8bpp tiles, since each byte
|
|
* contains only one pixel. It is assumed that the bytes themselves are
|
|
* always stored in-order (0, 1, 2, 3, ...). Similary, it is assumed that
|
|
* the individual bits of a pixel are always stored from high -> low.
|
|
*
|
|
* The familiar terms "little endian" and "big endian" are not appropriate to
|
|
* use here, as I consider them to apply at the byte-level. To avoid any
|
|
* confusion or ambiguity, I therefore use the expressions "in-order" and
|
|
* "reverse-order" to refer to the ordering of pixels within a byte.
|
|
* This is still a bit tricky since the order of pixels and bits above are
|
|
* reverses of eachother to begin with, but shouldn't be too confusing:
|
|
*
|
|
* I define "in-order" to mean that the order of pixel data as stored in a byte
|
|
* complies with the order of pixels to be rendered, from left to right. For
|
|
* 1bpp, this is simple: in-order means that bit 7 corresponds to pixel 0,
|
|
* bit 6 to pixel 1 and so on. Reverse-order means that bit 7 corresponds to
|
|
* pixel 7, bit 6 corresponds to pixel 6 and so on (in other words, the bits
|
|
* have to be reversed from left to right in order for the pixel order to be
|
|
* correct). Diagrammatically:
|
|
*
|
|
* Pixels: 01234567
|
|
* |||||||| (In-order)
|
|
* Bits: 76543210
|
|
*
|
|
* Pixels: 01234567
|
|
* |||||||| (Reverse-order)
|
|
* Bits: 01234567
|
|
*
|
|
* This extends quite intuitively to the cases of 2 and 4 bits per pixel.
|
|
* I will give one example of each.
|
|
*
|
|
* 2bpp, in-order:
|
|
*
|
|
* Pixels: 0 1 2 3
|
|
* | | | |
|
|
* Bits: 76 54 32 10
|
|
*
|
|
* 4bpp, reverse-order:
|
|
*
|
|
* Pixels: 0 1
|
|
* | |
|
|
* Bits: 3210 7654
|
|
*
|
|
**/
|
|
|
|
public class LinearTileCodec extends TileCodec {
|
|
|
|
public static final int IN_ORDER=1;
|
|
public static final int REVERSE_ORDER=2;
|
|
|
|
protected int ordering;
|
|
protected int pixelsPerByte;
|
|
protected int pixelMask;
|
|
protected int startPixel;
|
|
protected int boundary;
|
|
protected int step;
|
|
|
|
/**
|
|
* Constructor.
|
|
**/
|
|
|
|
public LinearTileCodec(String id, int bitsPerPixel, int ordering, String description) {
|
|
super(id, bitsPerPixel, description); // <= 8
|
|
this.ordering = ordering; // IN_ORDER or REVERSE_ORDER
|
|
pixelsPerByte = 8 / bitsPerPixel;
|
|
pixelMask = (int)(colorCount - 1);
|
|
|
|
if (IN_ORDER == ordering) {
|
|
startPixel = pixelsPerByte-1;
|
|
boundary = -1;
|
|
step = -1;
|
|
}
|
|
else { // REVERSE_ORDER
|
|
startPixel = 0;
|
|
boundary = pixelsPerByte;
|
|
step = 1;
|
|
}
|
|
}
|
|
|
|
/**
|
|
*
|
|
* Decodes a tile.
|
|
*
|
|
**/
|
|
|
|
public int[] decode(byte[] bits, int ofs, int stride) {
|
|
int pos=0;
|
|
stride *= bytesPerRow;
|
|
for (int i=0; i<8; i++) {
|
|
// do one row
|
|
for (int k=0; k<bytesPerRow; k++) {
|
|
// do one byte
|
|
int b = bits[ofs++] & 0xFF; // TODO: rowbyteoffset[k]
|
|
for (int m = startPixel; m != boundary; m += step) {
|
|
// decode one pixel
|
|
pixels[pos++] = (b >> bitsPerPixel*m) & pixelMask;
|
|
}
|
|
}
|
|
ofs += stride;
|
|
}
|
|
return pixels;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* Encodes a tile.
|
|
*
|
|
**/
|
|
|
|
public void encode(int[] pixels, byte[] bits, int ofs, int stride) {
|
|
int pos = 0;
|
|
stride *= bytesPerRow;
|
|
for (int i=0; i<8; i++) {
|
|
// do one row
|
|
for (int k=0; k<bytesPerRow; k++) {
|
|
// do one byte
|
|
byte b = 0;
|
|
for (int m = startPixel; m != boundary; m += step) {
|
|
// encode one pixel
|
|
b |= (pixels[pos++] & pixelMask) << (m*bitsPerPixel);
|
|
}
|
|
bits[ofs++] = b; // TODO: rowbyteoffset[k]
|
|
}
|
|
ofs += stride;
|
|
}
|
|
}
|
|
|
|
} |