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;
|
package lwjake2.client;
|
||||||
|
|
||||||
|
import dmx.lwjake2.render.PcxTexture;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import lwjake2.Defines;
|
import lwjake2.Defines;
|
||||||
import lwjake2.Globals;
|
import lwjake2.Globals;
|
||||||
@@ -1366,76 +1367,34 @@ public final class SCR {
|
|||||||
* LoadPCX
|
* LoadPCX
|
||||||
*/
|
*/
|
||||||
static int LoadPCX(String filename, byte[] palette, cinematics_t cin) {
|
static int LoadPCX(String filename, byte[] palette, cinematics_t cin) {
|
||||||
qfiles.pcx_t pcx;
|
|
||||||
|
|
||||||
// load the file
|
// load the file
|
||||||
ByteBuffer raw = UnpackLoader.loadFileAsByteBuffer(filename);
|
ByteBuffer raw = UnpackLoader.loadFileAsByteBuffer(filename);
|
||||||
|
|
||||||
if (raw == null) {
|
if (raw == null) {
|
||||||
VID.Printf(Defines.PRINT_DEVELOPER, "Bad pcx file " + filename
|
VID.Printf(Defines.PRINT_DEVELOPER, "Bad pcx file " + filename + '\n');
|
||||||
+ '\n');
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse the PCX file
|
// parse the PCX file
|
||||||
pcx = new qfiles.pcx_t(raw);
|
PcxTexture pcx = new PcxTexture(raw);
|
||||||
|
|
||||||
if (pcx.manufacturer != 0x0a || pcx.version != 5 || pcx.encoding != 1
|
|
||||||
|| pcx.bits_per_pixel != 8 || pcx.xmax >= 640
|
|
||||||
|| pcx.ymax >= 480) {
|
|
||||||
|
|
||||||
|
if (PcxTexture.isValid(pcx)) {
|
||||||
VID.Printf(Defines.PRINT_ALL, "Bad pcx file " + filename + '\n');
|
VID.Printf(Defines.PRINT_ALL, "Bad pcx file " + filename + '\n');
|
||||||
return 0;
|
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) {
|
if (palette != null) {
|
||||||
raw.position(raw.limit() - 768);
|
raw.position(raw.limit() - 768);
|
||||||
raw.get(palette);
|
raw.get(palette);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cin != null) {
|
if (cin != null) {
|
||||||
cin.pic = pix;
|
cin.pic = pcx.decode();
|
||||||
cin.width = width;
|
cin.width = pcx.getWidth();
|
||||||
cin.height = height;
|
cin.height = pcx.getHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
return pcx.getWidth() * 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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
|
TGA files are used for sky planes
|
||||||
|
|
||||||
========================================================================
|
========================================================================
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
package lwjake2.render.lwjgl;
|
package lwjake2.render.lwjgl;
|
||||||
|
|
||||||
|
import dmx.lwjake2.render.PcxTexture;
|
||||||
import lwjake2.Defines;
|
import lwjake2.Defines;
|
||||||
import lwjake2.ErrorCode;
|
import lwjake2.ErrorCode;
|
||||||
import dmx.lwjake2.UnpackLoader;
|
import dmx.lwjake2.UnpackLoader;
|
||||||
@@ -444,8 +445,6 @@ public abstract class Image extends Main {
|
|||||||
==============
|
==============
|
||||||
*/
|
*/
|
||||||
byte[] LoadPCX(String filename, byte[][] palette, Dimension dim) {
|
byte[] LoadPCX(String filename, byte[][] palette, Dimension dim) {
|
||||||
qfiles.pcx_t pcx;
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// load the file
|
// load the file
|
||||||
//
|
//
|
||||||
@@ -459,64 +458,24 @@ public abstract class Image extends Main {
|
|||||||
//
|
//
|
||||||
// parse the PCX file
|
// parse the PCX file
|
||||||
//
|
//
|
||||||
pcx = new qfiles.pcx_t(raw);
|
PcxTexture pcx = new PcxTexture(raw);
|
||||||
|
|
||||||
if (pcx.manufacturer != 0x0a
|
|
||||||
|| pcx.version != 5
|
|
||||||
|| pcx.encoding != 1
|
|
||||||
|| pcx.bits_per_pixel != 8
|
|
||||||
|| pcx.xmax >= 640
|
|
||||||
|| pcx.ymax >= 480) {
|
|
||||||
|
|
||||||
|
if (PcxTexture.isValid(pcx)) {
|
||||||
VID.Printf(Defines.PRINT_ALL, "Bad pcx file " + filename + '\n');
|
VID.Printf(Defines.PRINT_ALL, "Bad pcx file " + filename + '\n');
|
||||||
return null;
|
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) {
|
if (palette != null) {
|
||||||
palette[0] = new byte[768];
|
palette[0] = new byte[768];
|
||||||
System.arraycopy(raw, raw.length - 768, palette[0], 0, 768);
|
System.arraycopy(raw, raw.length - 768, palette[0], 0, 768);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dim != null) {
|
if (dim != null) {
|
||||||
dim.width = width;
|
dim.width = pcx.getWidth();
|
||||||
dim.height = height;
|
dim.height = pcx.getHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
return pcx.decode();
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Throwable gotoBreakOut = new Throwable();
|
private Throwable gotoBreakOut = new Throwable();
|
||||||
|
|||||||
Reference in New Issue
Block a user