/*
Copyright (C) 1997-2001 Id Software, Inc.
This program 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.
This program 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.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* Modifications
Copyright 2003-2004 Bytonic Software
Copyright 2010 Google Inc.
*/
package com.googlecode.gwtquake.shared.common;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
/**
* qfiles
*
* @author cwei
*/
public class QuakeFiles {
//
// qfiles.h: quake file formats
// This file must be identical in the quake and utils directories
//
/*
========================================================================
The .pak files are just a linear collapse of a directory tree
========================================================================
*/
/*
========================================================================
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
========================================================================
*/
public static class tga_t {
// targa header
public int id_length, colormap_type, image_type; // unsigned char
public int colormap_index, colormap_length; // unsigned short
public int colormap_size; // unsigned char
public int x_origin, y_origin, width, height; // unsigned short
public int pixel_size, attributes; // unsigned char
public ByteBuffer data; // (un)compressed data
public tga_t(byte[] dataBytes) {
this(ByteBuffer.wrap(dataBytes));
}
public tga_t(ByteBuffer b) {
// is stored as little endian
b.order(ByteOrder.LITTLE_ENDIAN);
// fill header
id_length = b.get() & 0xFF;
colormap_type = b.get() & 0xFF;
image_type = b.get() & 0xFF;
colormap_index = b.getShort() & 0xFFFF;
colormap_length = b.getShort() & 0xFFFF;
colormap_size = b.get() & 0xFF;
x_origin = b.getShort() & 0xFFFF;
y_origin = b.getShort() & 0xFFFF;
width = b.getShort() & 0xFFFF;
height = b.getShort() & 0xFFFF;
pixel_size = b.get() & 0xFF;
attributes = b.get() & 0xFF;
// fill data
data = b.slice();
}
}
/*
========================================================================
.MD2 triangle model file format
========================================================================
*/
public static final int IDALIASHEADER = (('2'<<24)+('P'<<16)+('D'<<8)+'I');
public static final int ALIAS_VERSION = 8;
public static final int MAX_TRIANGLES = 4096;
public static final int MAX_VERTS = 2048;
public static final int MAX_FRAMES = 512;
public static final int MAX_MD2SKINS = 32;
public static final int MAX_SKINNAME = 64;
public static class dstvert_t {
public short s;
public short t;
public dstvert_t(ByteBuffer b) {
s = b.getShort();
t = b.getShort();
}
}
public static class dtriangle_t {
public short index_xyz[] = { 0, 0, 0 };
public short index_st[] = { 0, 0, 0 };
public dtriangle_t(ByteBuffer b) {
index_xyz[0] = b.getShort();
index_xyz[1] = b.getShort();
index_xyz[2] = b.getShort();
index_st[0] = b.getShort();
index_st[1] = b.getShort();
index_st[2] = b.getShort();
}
}
public static final int DTRIVERTX_V0 = 0;
public static final int DTRIVERTX_V1 = 1;
public static final int DTRIVERTX_V2 = 2;
public static final int DTRIVERTX_LNI = 3;
public static final int DTRIVERTX_SIZE = 4;
public static class daliasframe_t {
public float[] scale = {0, 0, 0}; // multiply byte verts by this
public float[] translate = {0, 0, 0}; // then add this
public String name; // frame name from grabbing (size 16)
public int[] verts; // variable sized
public daliasframe_t(ByteBuffer b) {
scale[0] = b.getFloat(); scale[1] = b.getFloat(); scale[2] = b.getFloat();
translate[0] = b.getFloat(); translate[1] = b.getFloat(); translate[2] = b.getFloat();
byte[] nameBuf = new byte[16];
b.get(nameBuf);
name = Compatibility.newString(nameBuf).trim();
}
}
// the glcmd format:
// a positive integer starts a tristrip command, followed by that many
// vertex structures.
// a negative integer starts a trifan command, followed by -x vertexes
// a zero indicates the end of the command list.
// a vertex consists of a floating point s, a floating point t,
// and an integer vertex index.
public static class dmdl_t {
public int ident;
public int version;
public int skinwidth;
public int skinheight;
public int framesize; // byte size of each frame
public int num_skins;
public int num_xyz;
public int num_st; // greater than num_xyz for seams
public int num_tris;
public int num_glcmds; // dwords in strip/fan command list
public int num_frames;
public int ofs_skins; // each skin is a MAX_SKINNAME string
public int ofs_st; // byte offset from start for stverts
public int ofs_tris; // offset for dtriangles
public int ofs_frames; // offset for first frame
public int ofs_glcmds;
public int ofs_end; // end of file
// wird extra gebraucht
public String[] skinNames;
public dstvert_t[] stVerts;
public dtriangle_t[] triAngles;
public int[] glCmds;
public daliasframe_t[] aliasFrames;
public dmdl_t(ByteBuffer b) {
ident = b.getInt();
version = b.getInt();
skinwidth = b.getInt();
skinheight = b.getInt();
framesize = b.getInt(); // byte size of each frame
num_skins = b.getInt();
num_xyz = b.getInt();
num_st = b.getInt(); // greater than num_xyz for seams
num_tris = b.getInt();
num_glcmds = b.getInt(); // dwords in strip/fan command list
num_frames = b.getInt();
ofs_skins = b.getInt(); // each skin is a MAX_SKINNAME string
ofs_st = b.getInt(); // byte offset from start for stverts
ofs_tris = b.getInt(); // offset for dtriangles
ofs_frames = b.getInt(); // offset for first frame
ofs_glcmds = b.getInt();
ofs_end = b.getInt(); // end of file
}
/*
* new members for vertex array handling
*/
public FloatBuffer textureCoordBuf = null;
public ShortBuffer vertexIndexBuf = null;
public int[] counts = null;
public ShortBuffer[] indexElements = null;
public int staticTextureBufId = -1;
}
/*
========================================================================
.SP2 sprite file format
========================================================================
*/
// little-endian "IDS2"
public static final int IDSPRITEHEADER = (('2'<<24)+('S'<<16)+('D'<<8)+'I');
public static final int SPRITE_VERSION = 2;
public static class dsprframe_t {
public int width, height;
public int origin_x, origin_y; // raster coordinates inside pic
public String name; // name of pcx file (MAX_SKINNAME)
public dsprframe_t(ByteBuffer b) {
width = b.getInt();
height = b.getInt();
origin_x = b.getInt();
origin_y = b.getInt();
byte[] nameBuf = new byte[MAX_SKINNAME];
b.get(nameBuf);
name = Compatibility.newString(nameBuf).trim();
}
}
public static class dsprite_t {
public int ident;
public int version;
public int numframes;
public dsprframe_t frames[]; // variable sized
public dsprite_t(ByteBuffer b) {
ident = b.getInt();
version = b.getInt();
numframes = b.getInt();
frames = new dsprframe_t[numframes];
for (int i=0; i < numframes; i++) {
frames[i] = new dsprframe_t(b);
}
}
}
/*
==============================================================================
.WAL texture file format
==============================================================================
*/
public static class miptex_t {
static final int MIPLEVELS = 4;
static final int NAME_SIZE = 32;
public String name; // char name[32];
public int width, height;
public int[] offsets = new int[MIPLEVELS]; // 4 mip maps stored
// next frame in animation chain
public String animname; // char animname[32];
public int flags;
public int contents;
public int value;
public miptex_t(byte[] dataBytes) {
this(ByteBuffer.wrap(dataBytes));
}
public miptex_t(ByteBuffer b) {
// is stored as little endian
b.order(ByteOrder.LITTLE_ENDIAN);
byte[] nameBuf = new byte[NAME_SIZE];
// fill header
b.get(nameBuf);
name = Compatibility.newString(nameBuf).trim();
width = b.getInt();
height = b.getInt();
offsets[0] = b.getInt();
offsets[1] = b.getInt();
offsets[2] = b.getInt();
offsets[3] = b.getInt();
b.get(nameBuf);
animname = Compatibility.newString(nameBuf).trim();
flags = b.getInt();
contents = b.getInt();
value = b.getInt();
}
}
/*
==============================================================================
.BSP file format
==============================================================================
*/
public static final int IDBSPHEADER = (('P'<<24)+('S'<<16)+('B'<<8)+'I');
// =============================================================================
public static class dheader_t {
public dheader_t(ByteBuffer bb) {
bb.order(ByteOrder.LITTLE_ENDIAN);
this.ident = bb.getInt();
this.version = bb.getInt();
for (int n = 0; n < Constants.HEADER_LUMPS; n++)
lumps[n] = new Lump(bb.getInt(), bb.getInt());
}
public int ident;
public int version;
public Lump lumps[] = new Lump[Constants.HEADER_LUMPS];
}
public static class dmodel_t {
public dmodel_t(ByteBuffer bb) {
bb.order(ByteOrder.LITTLE_ENDIAN);
for (int j = 0; j < 3; j++)
mins[j] = bb.getFloat();
for (int j = 0; j < 3; j++)
maxs[j] = bb.getFloat();
for (int j = 0; j < 3; j++)
origin[j] = bb.getFloat();
headnode = bb.getInt();
firstface = bb.getInt();
numfaces = bb.getInt();
}
public float mins[] = { 0, 0, 0 };
public float maxs[] = { 0, 0, 0 };
public float origin[] = { 0, 0, 0 }; // for sounds or lights
public int headnode;
public int firstface, numfaces; // submodels just draw faces
// without walking the bsp tree
public static int SIZE = 3 * 4 + 3 * 4 + 3 * 4 + 4 + 8;
}
public static class dvertex_t {
public static final int SIZE = 3 * 4; // 3 mal 32 bit float
public float[] point = { 0, 0, 0 };
public dvertex_t(ByteBuffer b) {
point[0] = b.getFloat();
point[1] = b.getFloat();
point[2] = b.getFloat();
}
}
// planes (x&~1) and (x&~1)+1 are always opposites
public static class dplane_t {
public dplane_t(ByteBuffer bb) {
bb.order(ByteOrder.LITTLE_ENDIAN);
normal[0] = (bb.getFloat());
normal[1] = (bb.getFloat());
normal[2] = (bb.getFloat());
dist = (bb.getFloat());
type = (bb.getInt());
}
public float normal[] = { 0, 0, 0 };
public float dist;
public int type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate
public static final int SIZE = 3 * 4 + 4 + 4;
}
public static class dnode_t {
public dnode_t(ByteBuffer bb) {
bb.order(ByteOrder.LITTLE_ENDIAN);
planenum = bb.getInt();
children[0] = bb.getInt();
children[1] = bb.getInt();
for (int j = 0; j < 3; j++)
mins[j] = bb.getShort();
for (int j = 0; j < 3; j++)
maxs[j] = bb.getShort();
firstface = bb.getShort() & 0xffff;
numfaces = bb.getShort() & 0xffff;
}
public int planenum;
public int children[] = { 0, 0 };
// negative numbers are -(leafs+1), not nodes
public short mins[] = { 0, 0, 0 }; // for frustom culling
public short maxs[] = { 0, 0, 0 };
/*
unsigned short firstface;
unsigned short numfaces; // counting both sides
*/
public int firstface;
public int numfaces;
public static int SIZE = 4 + 8 + 6 + 6 + 2 + 2; // counting both sides
}
// note that edge 0 is never used, because negative edge nums are used for
// counterclockwise use of the edge in a face
public static class dedge_t {
// unsigned short v[2];
int v[] = { 0, 0 };
}
public static class dface_t {
public static final int SIZE =
4 * Constants.SIZE_OF_SHORT
+ 2 * Constants.SIZE_OF_INT
+ Constants.MAXLIGHTMAPS;
//unsigned short planenum;
public int planenum;
public short side;
public int firstedge; // we must support > 64k edges
public short numedges;
public short texinfo;
// lighting info
public byte styles[] = new byte[Constants.MAXLIGHTMAPS];
public int lightofs; // start of [numstyles*surfsize] samples
public dface_t(ByteBuffer b) {
planenum = b.getShort() & 0xFFFF;
side = b.getShort();
firstedge = b.getInt();
numedges = b.getShort();
texinfo = b.getShort();
b.get(styles);
lightofs = b.getInt();
}
}
public static class dleaf_t {
public dleaf_t(byte[] cmod_base, int i, int j) {
this(ByteBuffer.wrap(cmod_base, i, j).order(ByteOrder.LITTLE_ENDIAN));
}
public dleaf_t(ByteBuffer bb) {
contents = bb.getInt();
cluster = bb.getShort();
area = bb.getShort();
mins[0] = bb.getShort();
mins[1] = bb.getShort();
mins[2] = bb.getShort();
maxs[0] = bb.getShort();
maxs[1] = bb.getShort();
maxs[2] = bb.getShort();
firstleafface = bb.getShort() & 0xffff;
numleaffaces = bb.getShort() & 0xffff;
firstleafbrush = bb.getShort() & 0xffff;
numleafbrushes = bb.getShort() & 0xffff;
}
public static final int SIZE = 4 + 8 * 2 + 4 * 2;
public int contents; // OR of all brushes (not needed?)
public short cluster;
public short area;
public short mins[] = { 0, 0, 0 }; // for frustum culling
public short maxs[] = { 0, 0, 0 };
public int firstleafface; // unsigned short
public int numleaffaces; // unsigned short
public int firstleafbrush; // unsigned short
public int numleafbrushes; // unsigned short
}
public static class dbrushside_t {
public dbrushside_t(ByteBuffer bb) {
bb.order(ByteOrder.LITTLE_ENDIAN);
planenum = bb.getShort() & 0xffff;
texinfo = bb.getShort();
}
//unsigned short planenum;
public int planenum; // facing out of the leaf
public short texinfo;
public static int SIZE = 4;
}
public static class dbrush_t {
public dbrush_t(ByteBuffer bb) {
bb.order(ByteOrder.LITTLE_ENDIAN);
firstside = bb.getInt();
numsides = bb.getInt();
contents = bb.getInt();
}
public static int SIZE = 3 * 4;
public int firstside;
public int numsides;
public int contents;
}
// #define ANGLE_UP -1
// #define ANGLE_DOWN -2
// the visibility lump consists of a header with a count, then
// byte offsets for the PVS and PHS of each cluster, then the raw
// compressed bit vectors
// #define DVIS_PVS 0
// #define DVIS_PHS 1
public static class dvis_t {
public dvis_t(ByteBuffer bb) {
numclusters = bb.getInt();
bitofs = new int[numclusters][2];
for (int i = 0; i < numclusters; i++) {
bitofs[i][0] = bb.getInt();
bitofs[i][1] = bb.getInt();
}
}
public int numclusters;
public int bitofs[][] = new int[8][2]; // bitofs[numclusters][2]
}
// each area has a list of portals that lead into other areas
// when portals are closed, other areas may not be visible or
// hearable even if the vis info says that it should be
public static class dareaportal_t {
public dareaportal_t() {
}
public dareaportal_t(ByteBuffer bb) {
bb.order(ByteOrder.LITTLE_ENDIAN);
portalnum = bb.getInt();
otherarea = bb.getInt();
}
public int portalnum;
public int otherarea;
public static int SIZE = 8;
}
public static class darea_t {
public darea_t(ByteBuffer bb) {
bb.order(ByteOrder.LITTLE_ENDIAN);
numareaportals = bb.getInt();
firstareaportal = bb.getInt();
}
public int numareaportals;
public int firstareaportal;
public static int SIZE = 8;
}
}