From 687cd9e92439f9ed5b94960e0a0994f025dee790 Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Tue, 28 May 2019 01:06:52 +0300 Subject: [PATCH] PcxTexture --- .../java/dmx/lwjake2/render/PcxTexture.java | 113 ++++++++++++++++++ src/main/java/lwjake2/client/SCR.java | 57 ++------- src/main/java/lwjake2/qcommon/qfiles.java | 58 --------- src/main/java/lwjake2/render/lwjgl/Image.java | 53 +------- 4 files changed, 127 insertions(+), 154 deletions(-) create mode 100644 src/main/java/dmx/lwjake2/render/PcxTexture.java diff --git a/src/main/java/dmx/lwjake2/render/PcxTexture.java b/src/main/java/dmx/lwjake2/render/PcxTexture.java new file mode 100644 index 0000000..085af0b --- /dev/null +++ b/src/main/java/dmx/lwjake2/render/PcxTexture.java @@ -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; + } +} diff --git a/src/main/java/lwjake2/client/SCR.java b/src/main/java/lwjake2/client/SCR.java index 3d1edbf..6198033 100644 --- a/src/main/java/lwjake2/client/SCR.java +++ b/src/main/java/lwjake2/client/SCR.java @@ -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(); } /** diff --git a/src/main/java/lwjake2/qcommon/qfiles.java b/src/main/java/lwjake2/qcommon/qfiles.java index abdbda4..5ba7dbd 100644 --- a/src/main/java/lwjake2/qcommon/qfiles.java +++ b/src/main/java/lwjake2/qcommon/qfiles.java @@ -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 ======================================================================== diff --git a/src/main/java/lwjake2/render/lwjgl/Image.java b/src/main/java/lwjake2/render/lwjgl/Image.java index 8cf2aec..c315305 100644 --- a/src/main/java/lwjake2/render/lwjgl/Image.java +++ b/src/main/java/lwjake2/render/lwjgl/Image.java @@ -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();