PcxTexture
This commit is contained in:
113
src/main/java/dmx/lwjake2/render/PcxTexture.java
Normal file
113
src/main/java/dmx/lwjake2/render/PcxTexture.java
Normal file
@@ -0,0 +1,113 @@
|
||||
package dmx.lwjake2.render;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
@Getter
|
||||
@EqualsAndHashCode
|
||||
public class PcxTexture {
|
||||
|
||||
private static final int $PALETTE_SIZE = 48;
|
||||
private static final int $FILLER_SIZE = 58;
|
||||
|
||||
private byte manufacturer;
|
||||
private byte version;
|
||||
private byte encoding;
|
||||
private byte bitsPerPixel;
|
||||
|
||||
private int xMin;
|
||||
private int yMin;
|
||||
private int xMax;
|
||||
private int yMax;
|
||||
private int hRes;
|
||||
private int vRes;
|
||||
|
||||
private byte[] palette = new byte[$PALETTE_SIZE];
|
||||
|
||||
private byte reserved;
|
||||
private byte colorPlanes;
|
||||
private int bytesPerLine;
|
||||
private int paletteType;
|
||||
|
||||
private byte[] filler = new byte[$FILLER_SIZE];
|
||||
|
||||
private ByteBuffer data;
|
||||
|
||||
private int height;
|
||||
private int width;
|
||||
|
||||
public PcxTexture(ByteBuffer byteBuffer) {
|
||||
byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
header(byteBuffer);
|
||||
|
||||
data = byteBuffer.slice();
|
||||
|
||||
width = xMax - xMin + 1;
|
||||
height = yMax - yMin + 1;
|
||||
}
|
||||
|
||||
public PcxTexture(byte[] bytes) {
|
||||
this(ByteBuffer.wrap(bytes));
|
||||
}
|
||||
|
||||
public byte[] decode() {
|
||||
byte[] result = new byte[width * height];
|
||||
|
||||
int count = 0;
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; ) {
|
||||
byte dataByte = data.get();
|
||||
|
||||
if ((dataByte & 0xC0) == 0xC0) {
|
||||
int runLength = dataByte & 0x3F;
|
||||
dataByte = data.get();
|
||||
while (runLength-- > 0) {
|
||||
result[count++] = dataByte;
|
||||
x++;
|
||||
}
|
||||
} else {
|
||||
result[count++] = dataByte;
|
||||
x++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private int getUnsignedShort(ByteBuffer byteBuffer) {
|
||||
return byteBuffer.getShort() & 0xffff;
|
||||
}
|
||||
|
||||
private void header(ByteBuffer byteBuffer) {
|
||||
manufacturer = byteBuffer.get();
|
||||
version = byteBuffer.get();
|
||||
encoding = byteBuffer.get();
|
||||
bitsPerPixel = byteBuffer.get();
|
||||
xMin = getUnsignedShort(byteBuffer);
|
||||
yMin = getUnsignedShort(byteBuffer);
|
||||
xMax = getUnsignedShort(byteBuffer);
|
||||
yMax = getUnsignedShort(byteBuffer);
|
||||
hRes = getUnsignedShort(byteBuffer);
|
||||
vRes = getUnsignedShort(byteBuffer);
|
||||
byteBuffer.get(palette);
|
||||
reserved = byteBuffer.get();
|
||||
colorPlanes = byteBuffer.get();
|
||||
bytesPerLine = getUnsignedShort(byteBuffer);
|
||||
paletteType = getUnsignedShort(byteBuffer);
|
||||
byteBuffer.get(filler);
|
||||
}
|
||||
|
||||
public static boolean isValid(PcxTexture pcx) {
|
||||
return pcx.manufacturer != 0x0A
|
||||
|| pcx.version != 5
|
||||
|| pcx.encoding != 1
|
||||
|| pcx.bitsPerPixel != 8
|
||||
|| pcx.xMax >= 640
|
||||
|| pcx.yMax >= 480;
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
package lwjake2.client;
|
||||
|
||||
import dmx.lwjake2.render.PcxTexture;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import lwjake2.Defines;
|
||||
import lwjake2.Globals;
|
||||
@@ -1366,76 +1367,34 @@ public final class SCR {
|
||||
* LoadPCX
|
||||
*/
|
||||
static int LoadPCX(String filename, byte[] palette, cinematics_t cin) {
|
||||
qfiles.pcx_t pcx;
|
||||
|
||||
// load the file
|
||||
ByteBuffer raw = UnpackLoader.loadFileAsByteBuffer(filename);
|
||||
|
||||
if (raw == null) {
|
||||
VID.Printf(Defines.PRINT_DEVELOPER, "Bad pcx file " + filename
|
||||
+ '\n');
|
||||
VID.Printf(Defines.PRINT_DEVELOPER, "Bad pcx file " + filename + '\n');
|
||||
return 0;
|
||||
}
|
||||
|
||||
// parse the PCX file
|
||||
pcx = new qfiles.pcx_t(raw);
|
||||
|
||||
if (pcx.manufacturer != 0x0a || pcx.version != 5 || pcx.encoding != 1
|
||||
|| pcx.bits_per_pixel != 8 || pcx.xmax >= 640
|
||||
|| pcx.ymax >= 480) {
|
||||
PcxTexture pcx = new PcxTexture(raw);
|
||||
|
||||
if (PcxTexture.isValid(pcx)) {
|
||||
VID.Printf(Defines.PRINT_ALL, "Bad pcx file " + filename + '\n');
|
||||
return 0;
|
||||
}
|
||||
|
||||
int width = pcx.xmax - pcx.xmin + 1;
|
||||
int height = pcx.ymax - pcx.ymin + 1;
|
||||
|
||||
byte[] pix = new byte[width * height];
|
||||
|
||||
if (palette != null) {
|
||||
raw.position(raw.limit() - 768);
|
||||
raw.get(palette);
|
||||
}
|
||||
|
||||
if (cin != null) {
|
||||
cin.pic = pix;
|
||||
cin.width = width;
|
||||
cin.height = height;
|
||||
cin.pic = pcx.decode();
|
||||
cin.width = pcx.getWidth();
|
||||
cin.height = pcx.getHeight();
|
||||
}
|
||||
|
||||
//
|
||||
// decode pcx
|
||||
//
|
||||
int count = 0;
|
||||
byte dataByte = 0;
|
||||
int runLength = 0;
|
||||
int x, y;
|
||||
|
||||
// simple counter for buffer indexing
|
||||
int p = 0;
|
||||
|
||||
for (y = 0; y < height; y++) {
|
||||
for (x = 0; x < width;) {
|
||||
|
||||
dataByte = pcx.data.get(p++);
|
||||
|
||||
if ((dataByte & 0xC0) == 0xC0) {
|
||||
runLength = dataByte & 0x3F;
|
||||
dataByte = pcx.data.get(p++);
|
||||
// write runLength pixel
|
||||
while (runLength-- > 0) {
|
||||
pix[count++] = dataByte;
|
||||
x++;
|
||||
}
|
||||
} else {
|
||||
// write one pixel
|
||||
pix[count++] = dataByte;
|
||||
x++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return width * height;
|
||||
return pcx.getWidth() * pcx.getHeight();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -47,64 +47,6 @@ public class qfiles {
|
||||
/*
|
||||
========================================================================
|
||||
|
||||
PCX files are used for as many images as possible
|
||||
|
||||
========================================================================
|
||||
*/
|
||||
public static class pcx_t {
|
||||
|
||||
// size of byte arrays
|
||||
static final int PALETTE_SIZE = 48;
|
||||
static final int FILLER_SIZE = 58;
|
||||
|
||||
public byte manufacturer;
|
||||
public byte version;
|
||||
public byte encoding;
|
||||
public byte bits_per_pixel;
|
||||
public int xmin, ymin, xmax, ymax; // unsigned short
|
||||
public int hres, vres; // unsigned short
|
||||
public byte[] palette; //unsigned byte; size 48
|
||||
public byte reserved;
|
||||
public byte color_planes;
|
||||
public int bytes_per_line; // unsigned short
|
||||
public int palette_type; // unsigned short
|
||||
public byte[] filler; // size 58
|
||||
public ByteBuffer data; //unbounded data
|
||||
|
||||
public pcx_t(byte[] dataBytes) {
|
||||
this(ByteBuffer.wrap(dataBytes));
|
||||
}
|
||||
|
||||
public pcx_t(ByteBuffer b) {
|
||||
// is stored as little endian
|
||||
b.order(ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
// fill header
|
||||
manufacturer = b.get();
|
||||
version = b.get();
|
||||
encoding = b.get();
|
||||
bits_per_pixel = b.get();
|
||||
xmin = b.getShort() & 0xffff;
|
||||
ymin = b.getShort() & 0xffff;
|
||||
xmax = b.getShort() & 0xffff;
|
||||
ymax = b.getShort() & 0xffff;
|
||||
hres = b.getShort() & 0xffff;
|
||||
vres = b.getShort() & 0xffff;
|
||||
b.get(palette = new byte[PALETTE_SIZE]);
|
||||
reserved = b.get();
|
||||
color_planes = b.get();
|
||||
bytes_per_line = b.getShort() & 0xffff;
|
||||
palette_type = b.getShort() & 0xffff;
|
||||
b.get(filler = new byte[FILLER_SIZE]);
|
||||
|
||||
// fill data
|
||||
data = b.slice();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
========================================================================
|
||||
|
||||
TGA files are used for sky planes
|
||||
|
||||
========================================================================
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
package lwjake2.render.lwjgl;
|
||||
|
||||
import dmx.lwjake2.render.PcxTexture;
|
||||
import lwjake2.Defines;
|
||||
import lwjake2.ErrorCode;
|
||||
import dmx.lwjake2.UnpackLoader;
|
||||
@@ -444,8 +445,6 @@ public abstract class Image extends Main {
|
||||
==============
|
||||
*/
|
||||
byte[] LoadPCX(String filename, byte[][] palette, Dimension dim) {
|
||||
qfiles.pcx_t pcx;
|
||||
|
||||
//
|
||||
// load the file
|
||||
//
|
||||
@@ -459,64 +458,24 @@ public abstract class Image extends Main {
|
||||
//
|
||||
// parse the PCX file
|
||||
//
|
||||
pcx = new qfiles.pcx_t(raw);
|
||||
|
||||
if (pcx.manufacturer != 0x0a
|
||||
|| pcx.version != 5
|
||||
|| pcx.encoding != 1
|
||||
|| pcx.bits_per_pixel != 8
|
||||
|| pcx.xmax >= 640
|
||||
|| pcx.ymax >= 480) {
|
||||
PcxTexture pcx = new PcxTexture(raw);
|
||||
|
||||
if (PcxTexture.isValid(pcx)) {
|
||||
VID.Printf(Defines.PRINT_ALL, "Bad pcx file " + filename + '\n');
|
||||
return null;
|
||||
}
|
||||
|
||||
int width = pcx.xmax - pcx.xmin + 1;
|
||||
int height = pcx.ymax - pcx.ymin + 1;
|
||||
|
||||
byte[] pix = new byte[width * height];
|
||||
|
||||
if (palette != null) {
|
||||
palette[0] = new byte[768];
|
||||
System.arraycopy(raw, raw.length - 768, palette[0], 0, 768);
|
||||
}
|
||||
|
||||
if (dim != null) {
|
||||
dim.width = width;
|
||||
dim.height = height;
|
||||
dim.width = pcx.getWidth();
|
||||
dim.height = pcx.getHeight();
|
||||
}
|
||||
|
||||
//
|
||||
// decode pcx
|
||||
//
|
||||
int count = 0;
|
||||
byte dataByte;
|
||||
int runLength;
|
||||
int x, y;
|
||||
|
||||
for (y = 0; y < height; y++) {
|
||||
for (x = 0; x < width;) {
|
||||
|
||||
dataByte = pcx.data.get();
|
||||
|
||||
if ((dataByte & 0xC0) == 0xC0) {
|
||||
runLength = dataByte & 0x3F;
|
||||
dataByte = pcx.data.get();
|
||||
// write runLength pixel
|
||||
while (runLength-- > 0) {
|
||||
pix[count++] = dataByte;
|
||||
x++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// write one pixel
|
||||
pix[count++] = dataByte;
|
||||
x++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return pix;
|
||||
return pcx.decode();
|
||||
}
|
||||
|
||||
private Throwable gotoBreakOut = new Throwable();
|
||||
|
||||
Reference in New Issue
Block a user