0

PcxTexture

This commit is contained in:
2019-05-28 01:06:52 +03:00
parent 4bad58a041
commit 687cd9e924
4 changed files with 127 additions and 154 deletions

View 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;
}
}

View File

@@ -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();
}
/**

View File

@@ -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
========================================================================

View File

@@ -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();