TileMangler/src/tm/tilecodecs/LinearTileCodec.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;
}
}
}