diff options
Diffstat (limited to 'src/jake2/qcommon/CM.java')
-rw-r--r-- | src/jake2/qcommon/CM.java | 3779 |
1 files changed, 1878 insertions, 1901 deletions
diff --git a/src/jake2/qcommon/CM.java b/src/jake2/qcommon/CM.java index 5978f88..52495db 100644 --- a/src/jake2/qcommon/CM.java +++ b/src/jake2/qcommon/CM.java @@ -1,29 +1,29 @@ /* -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. - -*/ + * 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. + * + */ // Created on 02.01.2004 by RST. -// $Id: CM.java,v 1.5 2004-07-28 12:01:27 hzi Exp $ - +// $Id: CM.java,v 1.6 2004-09-22 19:22:09 salomo Exp $ package jake2.qcommon; import jake2.Defines; +import jake2.Globals; import jake2.game.*; import jake2.util.*; @@ -31,1889 +31,1866 @@ import java.io.RandomAccessFile; import java.nio.*; import java.util.Arrays; -public class CM extends Game { - - public static class cnode_t { - cplane_t plane; // ptr - int children[] = { 0, 0 }; // negative numbers are leafs - } - - public static class cbrushside_t { - cplane_t plane; // ptr - mapsurface_t surface; // ptr - } - - public static class cleaf_t { - int contents; - int cluster; - int area; - - // was unsigned short, but is ok (rst) - short firstleafbrush; - // was unsigned short, but is ok (rst) - short numleafbrushes; - } - - public static class cbrush_t { - int contents; - int numsides; - int firstbrushside; - int checkcount; // to avoid repeated testings - } - - public static class carea_t { - int numareaportals; - int firstareaportal; - int floodnum; // if two areas have equal floodnums, they are connected - int floodvalid; - } +public class CM { + + public static class cnode_t { + cplane_t plane; // ptr + + int children[] = { 0, 0 }; // negative numbers are leafs + } + + public static class cbrushside_t { + cplane_t plane; // ptr + + mapsurface_t surface; // ptr + } + + public static class cleaf_t { + int contents; + + int cluster; + + int area; + + // was unsigned short, but is ok (rst) + short firstleafbrush; + + // was unsigned short, but is ok (rst) + short numleafbrushes; + } + + public static class cbrush_t { + int contents; + + int numsides; + + int firstbrushside; + + int checkcount; // to avoid repeated testings + } + + public static class carea_t { + int numareaportals; + + int firstareaportal; + + int floodnum; // if two areas have equal floodnums, they are connected + + int floodvalid; + } + + static int checkcount; + + static String map_name = ""; + + static int numbrushsides; + + static cbrushside_t map_brushsides[] = new cbrushside_t[Defines.MAX_MAP_BRUSHSIDES]; + static { + for (int n = 0; n < Defines.MAX_MAP_BRUSHSIDES; n++) + map_brushsides[n] = new cbrushside_t(); + } + + public static int numtexinfo; + + public static mapsurface_t map_surfaces[] = new mapsurface_t[Defines.MAX_MAP_TEXINFO]; + static { + for (int n = 0; n < Defines.MAX_MAP_TEXINFO; n++) + map_surfaces[n] = new mapsurface_t(); + } + + static int numplanes; + + // extra for box hull ( +6) + static cplane_t map_planes[] = new cplane_t[Defines.MAX_MAP_PLANES + 6]; + + static { + for (int n = 0; n < Defines.MAX_MAP_PLANES + 6; n++) + map_planes[n] = new cplane_t(); + } + + static int numnodes; + + // extra for box hull ( +6) + static cnode_t map_nodes[] = new cnode_t[Defines.MAX_MAP_NODES + 6]; + + static { + for (int n = 0; n < Defines.MAX_MAP_NODES + 6; n++) + map_nodes[n] = new cnode_t(); + } + + static int numleafs = 1; // allow leaf funcs to be called without a map + + static cleaf_t map_leafs[] = new cleaf_t[Defines.MAX_MAP_LEAFS]; + static { + for (int n = 0; n < Defines.MAX_MAP_LEAFS; n++) + map_leafs[n] = new cleaf_t(); + } + + static int emptyleaf, solidleaf; + + static int numleafbrushes; + + //static unsigned short map_leafbrushes[Defines.MAX_MAP_LEAFBRUSHES]; + public static int map_leafbrushes[] = new int[Defines.MAX_MAP_LEAFBRUSHES]; + + public static int numcmodels; + + public static cmodel_t map_cmodels[] = new cmodel_t[Defines.MAX_MAP_MODELS]; + static { + for (int n = 0; n < Defines.MAX_MAP_MODELS; n++) + map_cmodels[n] = new cmodel_t(); + + } + + public static int numbrushes; + + public static cbrush_t map_brushes[] = new cbrush_t[Defines.MAX_MAP_BRUSHES]; + static { + for (int n = 0; n < Defines.MAX_MAP_BRUSHES; n++) + map_brushes[n] = new cbrush_t(); + + } + + public static int numvisibility; + + public static byte map_visibility[] = new byte[Defines.MAX_MAP_VISIBILITY]; + + // main visibility data. rst + // was: static dvis_t *map_vis = (dvis_t *)map_visibility; + public static qfiles.dvis_t map_vis = new qfiles.dvis_t(ByteBuffer + .wrap(map_visibility)); + + public static int numentitychars; + + public static String map_entitystring; + + public static int numareas = 1; + + public static carea_t map_areas[] = new carea_t[Defines.MAX_MAP_AREAS]; + static { + for (int n = 0; n < Defines.MAX_MAP_AREAS; n++) + map_areas[n] = new carea_t(); + + } + + public static int numareaportals; + + public static qfiles.dareaportal_t map_areaportals[] = new qfiles.dareaportal_t[Defines.MAX_MAP_AREAPORTALS]; + + static { + for (int n = 0; n < Defines.MAX_MAP_AREAPORTALS; n++) + map_areaportals[n] = new qfiles.dareaportal_t(); + + } + + public static int numclusters = 1; + + public static mapsurface_t nullsurface = new mapsurface_t(); + + public static int floodvalid; + + public static boolean portalopen[] = new boolean[Defines.MAX_MAP_AREAPORTALS]; + + public static cvar_t map_noareas; + + /* + * =============================================================================== + * + * MAP LOADING + * + * =============================================================================== + */ + + public static byte cmod_base[]; + + // is that right (rst) ? + public static int checksum; + + public static int last_checksum; + + /* + * ================== CM_LoadMap + * + * Loads in the map and all submodels ================== + */ + public static cmodel_t CM_LoadMap(String name, boolean clientload, + int checksum[]) { + Com.DPrintf("CM_LoadMap...\n"); + byte buf[]; + int i; + qfiles.dheader_t header; + int length; + + map_noareas = Cvar.Get("map_noareas", "0", 0); + + if (map_name.equals(name) + && (clientload || 0 == Cvar.VariableValue("flushmap"))) { + + checksum[0] = last_checksum; + + if (!clientload) { + Arrays.fill(portalopen, false); + FloodAreaConnections(); + } + return map_cmodels[0]; // still have the right version + } + + // free old stuff + numnodes = 0; + numleafs = 0; + numcmodels = 0; + numvisibility = 0; + numentitychars = 0; + map_entitystring = ""; + map_name = ""; + + if (name == null || name.length() == 0) { + numleafs = 1; + numclusters = 1; + numareas = 1; + checksum[0] = 0; + return map_cmodels[0]; + // cinematic servers won't have anything at all + } + + // + // load the file + // + buf = FS.LoadFile(name); + + if (buf == null) + Com.Error(Defines.ERR_DROP, "Couldn't load " + name); + + length = buf.length; + + ByteBuffer bbuf = ByteBuffer.wrap(buf); + + last_checksum = MD4.Com_BlockChecksum(buf, length); + checksum[0] = last_checksum; + + header = new qfiles.dheader_t(bbuf.slice()); + + if (header.version != Defines.BSPVERSION) + Com.Error(Defines.ERR_DROP, "CMod_LoadBrushModel: " + name + + " has wrong version number (" + header.version + + " should be " + Defines.BSPVERSION + ")"); + + cmod_base = buf; + + // load into heap + CMod_LoadSurfaces(header.lumps[Defines.LUMP_TEXINFO]); // ok. + CMod_LoadLeafs(header.lumps[Defines.LUMP_LEAFS]); + CMod_LoadLeafBrushes(header.lumps[Defines.LUMP_LEAFBRUSHES]); + CMod_LoadPlanes(header.lumps[Defines.LUMP_PLANES]); + CMod_LoadBrushes(header.lumps[Defines.LUMP_BRUSHES]); + CMod_LoadBrushSides(header.lumps[Defines.LUMP_BRUSHSIDES]); + CMod_LoadSubmodels(header.lumps[Defines.LUMP_MODELS]); + + CMod_LoadNodes(header.lumps[Defines.LUMP_NODES]); + CMod_LoadAreas(header.lumps[Defines.LUMP_AREAS]); + CMod_LoadAreaPortals(header.lumps[Defines.LUMP_AREAPORTALS]); + CMod_LoadVisibility(header.lumps[Defines.LUMP_VISIBILITY]); + CMod_LoadEntityString(header.lumps[Defines.LUMP_ENTITIES]); + + FS.FreeFile(buf); + + CM_InitBoxHull(); + + Arrays.fill(portalopen, false); + + FloodAreaConnections(); + + map_name = name; + + // debug (rst) + /* + * Com.p("Testing pointleafes:"); for (int n = 0; n < 20; n++) { float + * pos[] = new float[] {(float) (Math.random() * 1000), (float) + * (Math.random() * 1000), 0 }; int x = CM_PointLeafnum(pos); + * Com.p(Lib.vtofsbeaty(pos) + " ---> leaf=" + x + " area = " + * +map_leafs[x].area); } + */ + return map_cmodels[0]; + } + + /* + * ================= CMod_LoadSubmodels ================= + */ + public static void CMod_LoadSubmodels(lump_t l) { + Com.DPrintf("CMod_LoadSubmodels...\n"); + qfiles.dmodel_t in; + cmodel_t out; + int i, j, count; + + if ((l.filelen % qfiles.dmodel_t.SIZE) != 0) + Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size"); + + count = l.filelen / qfiles.dmodel_t.SIZE; + + if (count < 1) + Com.Error(Defines.ERR_DROP, "Map with no models"); + if (count > Defines.MAX_MAP_MODELS) + Com.Error(Defines.ERR_DROP, "Map has too many models"); + + Com.DPrintf(" numcmodels=" + count + "\n"); + numcmodels = count; + + if (debugloadmap) { + Com.DPrintf("submodles(headnode, <origin>, <mins>, <maxs>)\n"); + } + for (i = 0; i < count; i++) { + in = new qfiles.dmodel_t(ByteBuffer.wrap(cmod_base, i + * qfiles.dmodel_t.SIZE + l.fileofs, qfiles.dmodel_t.SIZE)); + out = map_cmodels[i]; + + for (j = 0; j < 3; j++) { // spread the mins / maxs by a pixel + out.mins[j] = in.mins[j] - 1; + out.maxs[j] = in.maxs[j] + 1; + out.origin[j] = in.origin[j]; + } + out.headnode = in.headnode; + if (debugloadmap) { + Com + .DPrintf( + "|%6i|%8.2f|%8.2f|%8.2f| %8.2f|%8.2f|%8.2f| %8.2f|%8.2f|%8.2f|\n", + new Vargs().add(out.headnode) + .add(out.origin[0]).add(out.origin[1]) + .add(out.origin[2]).add(out.mins[0]) + .add(out.mins[1]).add(out.mins[2]).add( + out.maxs[0]).add(out.maxs[1]) + .add(out.maxs[2])); + } + } + } + + static boolean debugloadmap = false; + + /* + * ================= CMod_LoadSurfaces ================= + */ + public static void CMod_LoadSurfaces(lump_t l) { + Com.DPrintf("CMod_LoadSurfaces...\n"); + texinfo_t in; + mapsurface_t out; + int i, count; + + if ((l.filelen % texinfo_t.SIZE) != 0) + Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size"); + + count = l.filelen / texinfo_t.SIZE; + if (count < 1) + Com.Error(Defines.ERR_DROP, "Map with no surfaces"); + if (count > Defines.MAX_MAP_TEXINFO) + Com.Error(Defines.ERR_DROP, "Map has too many surfaces"); + + numtexinfo = count; + Com.DPrintf("numtexinfo=" + count + "\n"); + if (debugloadmap) + Com.DPrintf("surfaces:\n"); + + for (i = 0; i < count; i++) { + out = map_surfaces[i] = new mapsurface_t(); + in = new texinfo_t(cmod_base, l.fileofs + i * texinfo_t.SIZE, + texinfo_t.SIZE); + + out.c.name = in.texture; + out.rname = in.texture; + out.c.flags = in.flags; + out.c.value = in.value; + + if (debugloadmap) { + Com.DPrintf("|%20s|%20s|%6i|%6i|\n", new Vargs() + .add(out.c.name).add(out.rname).add(out.c.value).add( + out.c.flags)); + } + + } + } + + /* + * ================= CMod_LoadNodes + * + * ================= + */ + public static void CMod_LoadNodes(lump_t l) { + Com.DPrintf("CMod_LoadNodes...\n"); + qfiles.dnode_t in; + int child; + cnode_t out; + int i, j, count; + + if ((l.filelen % qfiles.dnode_t.SIZE) != 0) + Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size:" + + l.fileofs + "," + qfiles.dnode_t.SIZE); + count = l.filelen / qfiles.dnode_t.SIZE; + + if (count < 1) + Com.Error(Defines.ERR_DROP, "Map has no nodes"); + if (count > Defines.MAX_MAP_NODES) + Com.Error(Defines.ERR_DROP, "Map has too many nodes"); + + numnodes = count; + Com.DPrintf(" numnodes=" + count + "\n"); + + if (debugloadmap) { + Com.DPrintf("nodes(planenum, child[0], child[1])\n"); + } + + for (i = 0; i < count; i++) { + in = new qfiles.dnode_t(ByteBuffer.wrap(cmod_base, + qfiles.dnode_t.SIZE * i + l.fileofs, qfiles.dnode_t.SIZE)); + out = map_nodes[i]; + + out.plane = map_planes[in.planenum]; + for (j = 0; j < 2; j++) { + child = in.children[j]; + out.children[j] = child; + } + if (debugloadmap) { + Com.DPrintf("|%6i| %6i| %6i|\n", new Vargs().add(in.planenum) + .add(out.children[0]).add(out.children[1])); + } + } + } + + /* + * ================= CMod_LoadBrushes + * + * ================= + */ + public static void CMod_LoadBrushes(lump_t l) { + Com.DPrintf("CMod_LoadBrushes...\n"); + qfiles.dbrush_t in; + cbrush_t out; + int i, count; + + if ((l.filelen % qfiles.dbrush_t.SIZE) != 0) + Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size"); + + count = l.filelen / qfiles.dbrush_t.SIZE; + + if (count > Defines.MAX_MAP_BRUSHES) + Com.Error(Defines.ERR_DROP, "Map has too many brushes"); + + numbrushes = count; + Com.DPrintf(" numbrushes=" + count + "\n"); + if (debugloadmap) { + Com.DPrintf("brushes:(firstbrushside, numsides, contents)\n"); + } + for (i = 0; i < count; i++) { + in = new qfiles.dbrush_t(ByteBuffer.wrap(cmod_base, i + * qfiles.dbrush_t.SIZE + l.fileofs, qfiles.dbrush_t.SIZE)); + out = map_brushes[i]; + out.firstbrushside = in.firstside; + out.numsides = in.numsides; + out.contents = in.contents; + + if (debugloadmap) { + Com + .DPrintf("| %6i| %6i| %8X|\n", new Vargs().add( + out.firstbrushside).add(out.numsides).add( + out.contents)); + } + } + } + + /* + * ================= CMod_LoadLeafs ================= + */ + public static void CMod_LoadLeafs(lump_t l) { + Com.DPrintf("CMod_LoadLeafs...\n"); + int i; + cleaf_t out; + qfiles.dleaf_t in; + int count; + + if ((l.filelen % qfiles.dleaf_t.SIZE) != 0) + Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size"); + + count = l.filelen / qfiles.dleaf_t.SIZE; + + if (count < 1) + Com.Error(Defines.ERR_DROP, "Map with no leafs"); + + // need to save space for box planes + if (count > Defines.MAX_MAP_PLANES) + Com.Error(Defines.ERR_DROP, "Map has too many planes"); + + Com.DPrintf(" numleafes=" + count + "\n"); + + numleafs = count; + numclusters = 0; + if (debugloadmap) + Com + .DPrintf("cleaf-list:(contents, cluster, area, firstleafbrush, numleafbrushes)\n"); + for (i = 0; i < count; i++) { + in = new qfiles.dleaf_t(cmod_base, i * qfiles.dleaf_t.SIZE + + l.fileofs, qfiles.dleaf_t.SIZE); + + out = map_leafs[i]; + + out.contents = in.contents; + out.cluster = in.cluster; + out.area = in.area; + out.firstleafbrush = (short) in.firstleafbrush; + out.numleafbrushes = (short) in.numleafbrushes; + + if (out.cluster >= numclusters) + numclusters = out.cluster + 1; + + if (debugloadmap) { + Com.DPrintf("|%8x|%6i|%6i|%6i|\n", new Vargs() + .add(out.contents).add(out.cluster).add(out.area).add( + out.firstleafbrush).add(out.numleafbrushes)); + } + + } + + Com.DPrintf(" numclusters=" + numclusters + "\n"); + + if (map_leafs[0].contents != Defines.CONTENTS_SOLID) + Com.Error(Defines.ERR_DROP, "Map leaf 0 is not CONTENTS_SOLID"); + + solidleaf = 0; + emptyleaf = -1; + + for (i = 1; i < numleafs; i++) { + if (map_leafs[i].contents == 0) { + emptyleaf = i; + break; + } + } + + if (emptyleaf == -1) + Com.Error(Defines.ERR_DROP, "Map does not have an empty leaf"); + } + + /* + * ================= CMod_LoadPlanes ================= + */ + public static void CMod_LoadPlanes(lump_t l) { + Com.DPrintf("CMod_LoadPlanes...\n"); + int i, j; + cplane_t out; + qfiles.dplane_t in; + int count; + int bits; + + if ((l.filelen % qfiles.dplane_t.SIZE) != 0) + Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size"); + + count = l.filelen / qfiles.dplane_t.SIZE; + + if (count < 1) + Com.Error(Defines.ERR_DROP, "Map with no planes"); + + // need to save space for box planes + if (count > Defines.MAX_MAP_PLANES) + Com.Error(Defines.ERR_DROP, "Map has too many planes"); + + Com.DPrintf(" numplanes=" + count + "\n"); + + numplanes = count; + if (debugloadmap) { + Com + .DPrintf("cplanes(normal[0],normal[1],normal[2], dist, type, signbits)\n"); + } + + for (i = 0; i < count; i++) { + in = new qfiles.dplane_t(ByteBuffer.wrap(cmod_base, i + * qfiles.dplane_t.SIZE + l.fileofs, qfiles.dplane_t.SIZE)); + + out = map_planes[i]; + + bits = 0; + for (j = 0; j < 3; j++) { + out.normal[j] = in.normal[j]; + + if (out.normal[j] < 0) + bits |= 1 << j; + } + + out.dist = in.dist; + out.type = (byte) in.type; + out.signbits = (byte) bits; + + if (debugloadmap) { + Com.DPrintf("|%6.2f|%6.2f|%6.2f| %10.2f|%3i| %1i|\n", + new Vargs().add(out.normal[0]).add(out.normal[1]).add( + out.normal[2]).add(out.dist).add(out.type).add( + out.signbits)); + } + } + } + + /* + * ================= CMod_LoadLeafBrushes ================= + */ + public static void CMod_LoadLeafBrushes(lump_t l) { + Com.DPrintf("CMod_LoadLeafBrushes...\n"); + int i; + int out[]; + short in[]; + int count; + + if ((l.filelen % 2) != 0) + Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size"); + + count = l.filelen / 2; + + Com.DPrintf(" numbrushes=" + count + "\n"); + + if (count < 1) + Com.Error(Defines.ERR_DROP, "Map with no planes"); + + // need to save space for box planes + if (count > Defines.MAX_MAP_LEAFBRUSHES) + Com.Error(Defines.ERR_DROP, "Map has too many leafbrushes"); + + out = map_leafbrushes; + numleafbrushes = count; + + ByteBuffer bb = ByteBuffer.wrap(cmod_base, l.fileofs, count * 2).order( + ByteOrder.LITTLE_ENDIAN); + + if (debugloadmap) { + Com.DPrintf("map_brushes:\n"); + } + + for (i = 0; i < count; i++) { + out[i] = bb.getShort(); + if (debugloadmap) { + Com.DPrintf("|%6i|%6i|\n", new Vargs().add(i).add(out[i])); + } + } + } + + /* + * ================= CMod_LoadBrushSides ================= + */ + public static void CMod_LoadBrushSides(lump_t l) { + Com.DPrintf("CMod_LoadBrushSides...\n"); + int i, j; + cbrushside_t out; + qfiles.dbrushside_t in; + int count; + int num; + + if ((l.filelen % qfiles.dbrushside_t.SIZE) != 0) + Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size"); + count = l.filelen / qfiles.dbrushside_t.SIZE; + + // need to save space for box planes + if (count > Defines.MAX_MAP_BRUSHSIDES) + Com.Error(Defines.ERR_DROP, "Map has too many planes"); + + numbrushsides = count; + + Com.DPrintf(" numbrushsides=" + count + "\n"); + + if (debugloadmap) { + Com.DPrintf("brushside(planenum, surfacenum):\n"); + } + for (i = 0; i < count; i++) { + + in = new qfiles.dbrushside_t(ByteBuffer.wrap(cmod_base, i + * qfiles.dbrushside_t.SIZE + l.fileofs, + qfiles.dbrushside_t.SIZE)); + + out = map_brushsides[i]; + + num = in.planenum; + + out.plane = map_planes[num]; // pointer + + j = in.texinfo; + + if (j >= numtexinfo) + Com.Error(Defines.ERR_DROP, "Bad brushside texinfo"); + + // rst: some mysterious happens here, even in the original code ???, + // texinfo is -1!!! + // hoz: checked against c version: ok. + if (j == -1) + out.surface = new mapsurface_t(); // just for safety + else + out.surface = map_surfaces[j]; + + if (debugloadmap) { + Com.DPrintf("| %6i| %6i|\n", new Vargs().add(num).add(j)); + } + } + } + + /* + * ================= CMod_LoadAreas ================= + */ + public static void CMod_LoadAreas(lump_t l) { + Com.DPrintf("CMod_LoadAreas...\n"); + int i; + carea_t out; + qfiles.darea_t in; + int count; + + if ((l.filelen % qfiles.darea_t.SIZE) != 0) + Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size"); + + count = l.filelen / qfiles.darea_t.SIZE; + + if (count > Defines.MAX_MAP_AREAS) + Com.Error(Defines.ERR_DROP, "Map has too many areas"); + + Com.DPrintf(" numareas=" + count + "\n"); + numareas = count; + + if (debugloadmap) { + Com.DPrintf("areas(numportals, firstportal)\n"); + } + + for (i = 0; i < count; i++) { + + in = new qfiles.darea_t(ByteBuffer.wrap(cmod_base, i + * qfiles.darea_t.SIZE + l.fileofs, qfiles.darea_t.SIZE)); + out = map_areas[i]; + + out.numareaportals = in.numareaportals; + out.firstareaportal = in.firstareaportal; + out.floodvalid = 0; + out.floodnum = 0; + if (debugloadmap) { + Com.DPrintf("| %6i| %6i|\n", new Vargs() + .add(out.numareaportals).add(out.firstareaportal)); + } + } + } + + /* + * ================= CMod_LoadAreaPortals ================= + */ + public static void CMod_LoadAreaPortals(lump_t l) { + Com.DPrintf("CMod_LoadAreaPortals...\n"); + int i; + qfiles.dareaportal_t out; + qfiles.dareaportal_t in; + int count; + + if ((l.filelen % qfiles.dareaportal_t.SIZE) != 0) + Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size"); + count = l.filelen / qfiles.dareaportal_t.SIZE; - static int checkcount; - - static String map_name = ""; - - static int numbrushsides; - static cbrushside_t map_brushsides[] = new cbrushside_t[MAX_MAP_BRUSHSIDES]; - static { - for (int n = 0; n < MAX_MAP_BRUSHSIDES; n++) - map_brushsides[n] = new cbrushside_t(); - } - - public static int numtexinfo; - public static mapsurface_t map_surfaces[] = new mapsurface_t[MAX_MAP_TEXINFO]; - static { - for (int n = 0; n < MAX_MAP_TEXINFO; n++) - map_surfaces[n] = new mapsurface_t(); - } - - static int numplanes; - // extra for box hull ( +6) - static cplane_t map_planes[] = new cplane_t[MAX_MAP_PLANES + 6]; - - static { - for (int n = 0; n < MAX_MAP_PLANES + 6; n++) - map_planes[n] = new cplane_t(); - } - - static int numnodes; - // extra for box hull ( +6) - static cnode_t map_nodes[] = new cnode_t[MAX_MAP_NODES + 6]; - - static { - for (int n = 0; n < MAX_MAP_NODES + 6; n++) - map_nodes[n] = new cnode_t(); - } - - static int numleafs = 1; // allow leaf funcs to be called without a map - static cleaf_t map_leafs[] = new cleaf_t[MAX_MAP_LEAFS]; - static { - for (int n = 0; n < MAX_MAP_LEAFS; n++) - map_leafs[n] = new cleaf_t(); - } - - static int emptyleaf, solidleaf; - - static int numleafbrushes; - //static unsigned short map_leafbrushes[MAX_MAP_LEAFBRUSHES]; - public static int map_leafbrushes[] = new int[MAX_MAP_LEAFBRUSHES]; - public static int numcmodels; - public static cmodel_t map_cmodels[] = new cmodel_t[MAX_MAP_MODELS]; - static { - for (int n = 0; n < MAX_MAP_MODELS; n++) - map_cmodels[n] = new cmodel_t(); - - } - - public static int numbrushes; - public static cbrush_t map_brushes[] = new cbrush_t[MAX_MAP_BRUSHES]; - static { - for (int n = 0; n < MAX_MAP_BRUSHES; n++) - map_brushes[n] = new cbrush_t(); - - } - - public static int numvisibility; - public static byte map_visibility[] = new byte[MAX_MAP_VISIBILITY]; - - // main visibility data. rst - // was: static dvis_t *map_vis = (dvis_t *)map_visibility; - public static qfiles.dvis_t map_vis = new qfiles.dvis_t(ByteBuffer.wrap(map_visibility)); - - public static int numentitychars; - public static String map_entitystring; - - public static int numareas = 1; - public static carea_t map_areas[] = new carea_t[MAX_MAP_AREAS]; - static { - for (int n = 0; n < MAX_MAP_AREAS; n++) - map_areas[n] = new carea_t(); - - } - public static int numareaportals; - public static qfiles.dareaportal_t map_areaportals[] = new qfiles.dareaportal_t[MAX_MAP_AREAPORTALS]; - - static { - for (int n = 0; n < MAX_MAP_AREAPORTALS; n++) - map_areaportals[n] = new qfiles.dareaportal_t(); - - } - - public static int numclusters = 1; - - public static mapsurface_t nullsurface = new mapsurface_t(); - - public static int floodvalid; - - public static boolean portalopen[] = new boolean[MAX_MAP_AREAPORTALS]; - - public static cvar_t map_noareas; - - /* - =============================================================================== - - MAP LOADING - - =============================================================================== - */ - - public static byte cmod_base[]; - - // is that right (rst) ? - public static int checksum; - public static int last_checksum; - - /* - ================== - CM_LoadMap - - Loads in the map and all submodels - ================== - */ - public static cmodel_t CM_LoadMap(String name, boolean clientload, int checksum[]) { - Com.DPrintf("CM_LoadMap...\n"); - byte buf[]; - int i; - qfiles.dheader_t header; - int length; - - map_noareas = Cvar.Get("map_noareas", "0", 0); - - if (map_name.equals(name) && (clientload || 0 == Cvar.VariableValue("flushmap"))) { - - checksum[0] = last_checksum; - - if (!clientload) { - Arrays.fill(portalopen, false); - FloodAreaConnections(); - } - return map_cmodels[0]; // still have the right version - } - - // free old stuff - numnodes = 0; - numleafs = 0; - numcmodels = 0; - numvisibility = 0; - numentitychars = 0; - map_entitystring = ""; - map_name = ""; - - if (name == null || name.length() == 0) { - numleafs = 1; - numclusters = 1; - numareas = 1; - checksum[0] = 0; - return map_cmodels[0]; - // cinematic servers won't have anything at all - } - - // - // load the file - // - buf = FS.LoadFile(name); - - if (buf == null) - Com.Error(ERR_DROP, "Couldn't load " + name); - - length = buf.length; - - ByteBuffer bbuf = ByteBuffer.wrap(buf); - - last_checksum = MD4.Com_BlockChecksum(buf, length); - checksum[0] = last_checksum; - - header = new qfiles.dheader_t(bbuf.slice()); - - if (header.version != BSPVERSION) - Com.Error( - ERR_DROP, - "CMod_LoadBrushModel: " + name + " has wrong version number (" + header.version + " should be " + BSPVERSION + ")"); - - cmod_base = buf; - - // load into heap - CMod_LoadSurfaces(header.lumps[LUMP_TEXINFO]); // ok. - CMod_LoadLeafs(header.lumps[LUMP_LEAFS]); - CMod_LoadLeafBrushes(header.lumps[LUMP_LEAFBRUSHES]); - CMod_LoadPlanes(header.lumps[LUMP_PLANES]); - CMod_LoadBrushes(header.lumps[LUMP_BRUSHES]); - CMod_LoadBrushSides(header.lumps[LUMP_BRUSHSIDES]); - CMod_LoadSubmodels(header.lumps[LUMP_MODELS]); - - CMod_LoadNodes(header.lumps[LUMP_NODES]); - CMod_LoadAreas(header.lumps[LUMP_AREAS]); - CMod_LoadAreaPortals(header.lumps[LUMP_AREAPORTALS]); - CMod_LoadVisibility(header.lumps[LUMP_VISIBILITY]); - CMod_LoadEntityString(header.lumps[LUMP_ENTITIES]); - - FS.FreeFile(buf); - - CM_InitBoxHull(); - - Arrays.fill(portalopen, false); - - FloodAreaConnections(); - - map_name = name; - - // debug (rst) - /* - Com.p("Testing pointleafes:"); - for (int n = 0; n < 20; n++) { - float pos[] = new float[] {(float) (Math.random() * 1000), (float) (Math.random() * 1000), 0 }; - int x = CM_PointLeafnum(pos); - Com.p(Lib.vtofsbeaty(pos) + " ---> leaf=" + x + " area = " +map_leafs[x].area); - } - */ - return map_cmodels[0]; - } - - /* - ================= - CMod_LoadSubmodels - ================= - */ - public static void CMod_LoadSubmodels(lump_t l) { - Com.DPrintf("CMod_LoadSubmodels...\n"); - qfiles.dmodel_t in; - cmodel_t out; - int i, j, count; - - if ((l.filelen % qfiles.dmodel_t.SIZE) != 0) - Com.Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); - - count = l.filelen / qfiles.dmodel_t.SIZE; - - if (count < 1) - Com.Error(ERR_DROP, "Map with no models"); - if (count > MAX_MAP_MODELS) - Com.Error(ERR_DROP, "Map has too many models"); - - Com.DPrintf(" numcmodels=" + count + "\n"); - numcmodels = count; - - if (debugloadmap) { - Com.DPrintf("submodles(headnode, <origin>, <mins>, <maxs>)\n"); - } - for (i = 0; i < count; i++) { - in = new qfiles.dmodel_t(ByteBuffer.wrap(cmod_base, i * qfiles.dmodel_t.SIZE + l.fileofs, qfiles.dmodel_t.SIZE)); - out = map_cmodels[i]; - - for (j = 0; j < 3; j++) { // spread the mins / maxs by a pixel - out.mins[j] = in.mins[j] - 1; - out.maxs[j] = in.maxs[j] + 1; - out.origin[j] = in.origin[j]; - } - out.headnode = in.headnode; - if (debugloadmap) { - Com.DPrintf( - "|%6i|%8.2f|%8.2f|%8.2f| %8.2f|%8.2f|%8.2f| %8.2f|%8.2f|%8.2f|\n", - new Vargs() - .add(out.headnode) - .add(out.origin[0]) - .add(out.origin[1]) - .add(out.origin[2]) - .add(out.mins[0]) - .add(out.mins[1]) - .add(out.mins[2]) - .add(out.maxs[0]) - .add(out.maxs[1]) - .add(out.maxs[2])); - } - } - } - static boolean debugloadmap = false; - - /* - ================= - CMod_LoadSurfaces - ================= - */ - public static void CMod_LoadSurfaces(lump_t l) { - Com.DPrintf("CMod_LoadSurfaces...\n"); - texinfo_t in; - mapsurface_t out; - int i, count; - - if ((l.filelen % texinfo_t.SIZE) != 0) - Com.Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); - - count = l.filelen / texinfo_t.SIZE; - if (count < 1) - Com.Error(ERR_DROP, "Map with no surfaces"); - if (count > MAX_MAP_TEXINFO) - Com.Error(ERR_DROP, "Map has too many surfaces"); - - numtexinfo = count; - Com.DPrintf("numtexinfo=" + count + "\n"); - if (debugloadmap) - Com.DPrintf("surfaces:\n"); - - for (i = 0; i < count; i++) { - out = map_surfaces[i] = new mapsurface_t(); - in = new texinfo_t(cmod_base, l.fileofs + i * texinfo_t.SIZE, texinfo_t.SIZE); - - out.c.name = in.texture; - out.rname = in.texture; - out.c.flags = in.flags; - out.c.value = in.value; - - if (debugloadmap) { - Com.DPrintf("|%20s|%20s|%6i|%6i|\n", new Vargs().add(out.c.name).add(out.rname).add(out.c.value).add(out.c.flags)); - } - - } - } - - /* - ================= - CMod_LoadNodes - - ================= - */ - public static void CMod_LoadNodes(lump_t l) { - Com.DPrintf("CMod_LoadNodes...\n"); - qfiles.dnode_t in; - int child; - cnode_t out; - int i, j, count; - - if ((l.filelen % qfiles.dnode_t.SIZE) != 0) - Com.Error(ERR_DROP, "MOD_LoadBmodel: funny lump size:" + l.fileofs + "," + qfiles.dnode_t.SIZE); - count = l.filelen / qfiles.dnode_t.SIZE; - - if (count < 1) - Com.Error(ERR_DROP, "Map has no nodes"); - if (count > MAX_MAP_NODES) - Com.Error(ERR_DROP, "Map has too many nodes"); - - numnodes = count; - Com.DPrintf(" numnodes=" + count + "\n"); - - if (debugloadmap) { - Com.DPrintf("nodes(planenum, child[0], child[1])\n"); - } - - for (i = 0; i < count; i++) { - in = new qfiles.dnode_t(ByteBuffer.wrap(cmod_base, qfiles.dnode_t.SIZE * i + l.fileofs, qfiles.dnode_t.SIZE)); - out = map_nodes[i]; - - out.plane = map_planes[in.planenum]; - for (j = 0; j < 2; j++) { - child = in.children[j]; - out.children[j] = child; - } - if (debugloadmap) { - Com.DPrintf("|%6i| %6i| %6i|\n", new Vargs().add(in.planenum).add(out.children[0]).add(out.children[1])); - } - } - } - - /* - ================= - CMod_LoadBrushes - - ================= - */ - public static void CMod_LoadBrushes(lump_t l) { - Com.DPrintf("CMod_LoadBrushes...\n"); - qfiles.dbrush_t in; - cbrush_t out; - int i, count; - - if ((l.filelen % qfiles.dbrush_t.SIZE) != 0) - Com.Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); - - count = l.filelen / qfiles.dbrush_t.SIZE; - - if (count > MAX_MAP_BRUSHES) - Com.Error(ERR_DROP, "Map has too many brushes"); - - numbrushes = count; - Com.DPrintf(" numbrushes=" + count + "\n"); - if (debugloadmap) { - Com.DPrintf("brushes:(firstbrushside, numsides, contents)\n"); - } - for (i = 0; i < count; i++) { - in = new qfiles.dbrush_t(ByteBuffer.wrap(cmod_base, i * qfiles.dbrush_t.SIZE + l.fileofs, qfiles.dbrush_t.SIZE)); - out = map_brushes[i]; - out.firstbrushside = in.firstside; - out.numsides = in.numsides; - out.contents = in.contents; - - if (debugloadmap) { - Com.DPrintf("| %6i| %6i| %8X|\n", new Vargs().add(out.firstbrushside).add(out.numsides).add(out.contents)); - } - } - } - - /* - ================= - CMod_LoadLeafs - ================= - */ - public static void CMod_LoadLeafs(lump_t l) { - Com.DPrintf("CMod_LoadLeafs...\n"); - int i; - cleaf_t out; - qfiles.dleaf_t in; - int count; - - if ((l.filelen % qfiles.dleaf_t.SIZE) != 0) - Com.Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); - - count = l.filelen / qfiles.dleaf_t.SIZE; - - if (count < 1) - Com.Error(ERR_DROP, "Map with no leafs"); - - // need to save space for box planes - if (count > MAX_MAP_PLANES) - Com.Error(ERR_DROP, "Map has too many planes"); - - Com.DPrintf(" numleafes=" + count + "\n"); - - numleafs = count; - numclusters = 0; - if (debugloadmap) - Com.DPrintf("cleaf-list:(contents, cluster, area, firstleafbrush, numleafbrushes)\n"); - for (i = 0; i < count; i++) { - in = new qfiles.dleaf_t(cmod_base, i * qfiles.dleaf_t.SIZE + l.fileofs, qfiles.dleaf_t.SIZE); - - out = map_leafs[i]; - - out.contents = in.contents; - out.cluster = in.cluster; - out.area = in.area; - out.firstleafbrush = (short) in.firstleafbrush; - out.numleafbrushes = (short) in.numleafbrushes; - - if (out.cluster >= numclusters) - numclusters = out.cluster + 1; - - if (debugloadmap) { - Com.DPrintf( - "|%8x|%6i|%6i|%6i|\n", - new Vargs().add(out.contents).add(out.cluster).add(out.area).add(out.firstleafbrush).add(out.numleafbrushes)); - } - - } - - Com.DPrintf(" numclusters=" + numclusters + "\n"); - - if (map_leafs[0].contents != CONTENTS_SOLID) - Com.Error(ERR_DROP, "Map leaf 0 is not CONTENTS_SOLID"); - - solidleaf = 0; - emptyleaf = -1; - - for (i = 1; i < numleafs; i++) { - if (map_leafs[i].contents == 0) { - emptyleaf = i; - break; - } - } - - if (emptyleaf == -1) - Com.Error(ERR_DROP, "Map does not have an empty leaf"); - } - - /* - ================= - CMod_LoadPlanes - ================= - */ - public static void CMod_LoadPlanes(lump_t l) { - Com.DPrintf("CMod_LoadPlanes...\n"); - int i, j; - cplane_t out; - qfiles.dplane_t in; - int count; - int bits; - - if ((l.filelen % qfiles.dplane_t.SIZE) != 0) - Com.Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); - - count = l.filelen / qfiles.dplane_t.SIZE; - - if (count < 1) - Com.Error(ERR_DROP, "Map with no planes"); - - // need to save space for box planes - if (count > MAX_MAP_PLANES) - Com.Error(ERR_DROP, "Map has too many planes"); - - Com.DPrintf(" numplanes=" + count + "\n"); - - numplanes = count; - if (debugloadmap) { - Com.DPrintf("cplanes(normal[0],normal[1],normal[2], dist, type, signbits)\n"); - } - - for (i = 0; i < count; i++) { - in = new qfiles.dplane_t(ByteBuffer.wrap(cmod_base, i * qfiles.dplane_t.SIZE + l.fileofs, qfiles.dplane_t.SIZE)); - - out = map_planes[i]; - - bits = 0; - for (j = 0; j < 3; j++) { - out.normal[j] = in.normal[j]; + if (count > Defines.MAX_MAP_AREAS) + Com.Error(Defines.ERR_DROP, "Map has too many areas"); - if (out.normal[j] < 0) - bits |= 1 << j; - } - - out.dist = in.dist; - out.type = (byte) in.type; - out.signbits = (byte) bits; - - if (debugloadmap) { - Com.DPrintf( - "|%6.2f|%6.2f|%6.2f| %10.2f|%3i| %1i|\n", - new Vargs().add(out.normal[0]).add(out.normal[1]).add(out.normal[2]).add(out.dist).add(out.type).add( - out.signbits)); - } - } - } - - /* - ================= - CMod_LoadLeafBrushes - ================= - */ - public static void CMod_LoadLeafBrushes(lump_t l) { - Com.DPrintf("CMod_LoadLeafBrushes...\n"); - int i; - int out[]; - short in[]; - int count; - - if ((l.filelen % 2) != 0) - Com.Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); - - count = l.filelen / 2; - - Com.DPrintf(" numbrushes=" + count + "\n"); - - if (count < 1) - Com.Error(ERR_DROP, "Map with no planes"); - - // need to save space for box planes - if (count > MAX_MAP_LEAFBRUSHES) - Com.Error(ERR_DROP, "Map has too many leafbrushes"); - - out = map_leafbrushes; - numleafbrushes = count; - - ByteBuffer bb = ByteBuffer.wrap(cmod_base, l.fileofs, count * 2).order(ByteOrder.LITTLE_ENDIAN); - - if (debugloadmap) { - Com.DPrintf("map_brushes:\n"); - } - - for (i = 0; i < count; i++) { - out[i] = bb.getShort(); - if (debugloadmap) { - Com.DPrintf("|%6i|%6i|\n", new Vargs().add(i).add(out[i])); - } - } - } - - /* - ================= - CMod_LoadBrushSides - ================= - */ - public static void CMod_LoadBrushSides(lump_t l) { - Com.DPrintf("CMod_LoadBrushSides...\n"); - int i, j; - cbrushside_t out; - qfiles.dbrushside_t in; - int count; - int num; - - if ((l.filelen % qfiles.dbrushside_t.SIZE) != 0) - Com.Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); - count = l.filelen / qfiles.dbrushside_t.SIZE; - - // need to save space for box planes - if (count > MAX_MAP_BRUSHSIDES) - Com.Error(ERR_DROP, "Map has too many planes"); - - numbrushsides = count; - - Com.DPrintf(" numbrushsides=" + count + "\n"); - - if (debugloadmap) { - Com.DPrintf("brushside(planenum, surfacenum):\n"); - } - for (i = 0; i < count; i++) { - - in = - new qfiles.dbrushside_t( - ByteBuffer.wrap(cmod_base, i * qfiles.dbrushside_t.SIZE + l.fileofs, qfiles.dbrushside_t.SIZE)); - - out = map_brushsides[i]; - - num = in.planenum; - - out.plane = map_planes[num]; // pointer - - j = in.texinfo; - - if (j >= numtexinfo) - Com.Error(ERR_DROP, "Bad brushside texinfo"); - - // rst: some mysterious happens here, even in the original code ???, texinfo is -1!!! - // hoz: checked against c version: ok. - if (j == -1) - out.surface = new mapsurface_t(); // just for safety - else - out.surface = map_surfaces[j]; - - if (debugloadmap) { - Com.DPrintf("| %6i| %6i|\n", new Vargs().add(num).add(j)); - } - } - } - - /* - ================= - CMod_LoadAreas - ================= - */ - public static void CMod_LoadAreas(lump_t l) { - Com.DPrintf("CMod_LoadAreas...\n"); - int i; - carea_t out; - qfiles.darea_t in; - int count; - - if ((l.filelen % qfiles.darea_t.SIZE) != 0) - Com.Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); - - count = l.filelen / qfiles.darea_t.SIZE; - - if (count > MAX_MAP_AREAS) - Com.Error(ERR_DROP, "Map has too many areas"); - - Com.DPrintf(" numareas=" + count + "\n"); - numareas = count; - - if (debugloadmap) { - Com.DPrintf("areas(numportals, firstportal)\n"); - } - - for (i = 0; i < count; i++) { - - in = new qfiles.darea_t(ByteBuffer.wrap(cmod_base, i * qfiles.darea_t.SIZE + l.fileofs, qfiles.darea_t.SIZE)); - out = map_areas[i]; - - out.numareaportals = in.numareaportals; - out.firstareaportal = in.firstareaportal; - out.floodvalid = 0; - out.floodnum = 0; - if (debugloadmap) { - Com.DPrintf("| %6i| %6i|\n", new Vargs().add(out.numareaportals).add(out.firstareaportal)); - } - } - } - - /* - ================= - CMod_LoadAreaPortals - ================= - */ - public static void CMod_LoadAreaPortals(lump_t l) { - Com.DPrintf("CMod_LoadAreaPortals...\n"); - int i; - qfiles.dareaportal_t out; - qfiles.dareaportal_t in; - int count; + numareaportals = count; + Com.DPrintf(" numareaportals=" + count + "\n"); + if (debugloadmap) { + Com.DPrintf("areaportals(portalnum, otherarea)\n"); + } + for (i = 0; i < count; i++) { + in = new qfiles.dareaportal_t(ByteBuffer.wrap(cmod_base, i + * qfiles.dareaportal_t.SIZE + l.fileofs, + qfiles.dareaportal_t.SIZE)); + + out = map_areaportals[i]; - if ((l.filelen % qfiles.dareaportal_t.SIZE) != 0) - Com.Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); - count = l.filelen / qfiles.dareaportal_t.SIZE; + out.portalnum = in.portalnum; + out.otherarea = in.otherarea; - if (count > MAX_MAP_AREAS) - Com.Error(ERR_DROP, "Map has too many areas"); + if (debugloadmap) { + Com.DPrintf("|%6i|%6i|\n", new Vargs().add(out.portalnum).add( + out.otherarea)); + } + } + } - numareaportals = count; - Com.DPrintf(" numareaportals=" + count + "\n"); - if (debugloadmap) { - Com.DPrintf("areaportals(portalnum, otherarea)\n"); - } - for (i = 0; i < count; i++) { - in = - new qfiles.dareaportal_t( - ByteBuffer.wrap(cmod_base, i * qfiles.dareaportal_t.SIZE + l.fileofs, qfiles.dareaportal_t.SIZE)); - - out = map_areaportals[i]; - - out.portalnum = in.portalnum; - out.otherarea = in.otherarea; - - if (debugloadmap) { - Com.DPrintf("|%6i|%6i|\n", new Vargs().add(out.portalnum).add(out.otherarea)); - } - } - } - - - /* - ================= - CMod_LoadVisibility - ================= - */ - public static void CMod_LoadVisibility(lump_t l) { - Com.DPrintf("CMod_LoadVisibility...\n"); - int i; - - numvisibility = l.filelen; - - Com.DPrintf(" numvisibility=" + numvisibility + "\n"); - - if (l.filelen > MAX_MAP_VISIBILITY) - Com.Error(ERR_DROP, "Map has too large visibility lump"); - - System.arraycopy(cmod_base, l.fileofs, map_visibility, 0, l.filelen); - - ByteBuffer bb = ByteBuffer.wrap(map_visibility, 0, l.filelen); - bb.order(ByteOrder.LITTLE_ENDIAN); - - map_vis = new qfiles.dvis_t(bb); - - } - - /* - ================= - CMod_LoadEntityString - ================= - */ - public static void CMod_LoadEntityString(lump_t l) { - Com.DPrintf("CMod_LoadEntityString...\n"); - - numentitychars = l.filelen; - - if (l.filelen > MAX_MAP_ENTSTRING) - Com.Error(ERR_DROP, "Map has too large entity lump"); - - int x = 0; - for (; x < l.filelen && cmod_base[x + l.fileofs] != 0; x++); - - map_entitystring = new String(cmod_base, l.fileofs, x).trim(); - } - - /* - ================== - CM_InlineModel - ================== - */ - - // works fine - public static cmodel_t InlineModel(String name) { - int num; - - if (name == null || name.charAt(0) != '*') - Com.Error(ERR_DROP, "CM_InlineModel: bad name"); - - num = atoi(name.substring(1)); - - if (num < 1 || num >= numcmodels) - Com.Error(ERR_DROP, "CM_InlineModel: bad number"); - - return map_cmodels[num]; - } - - public static int CM_NumClusters() { - return numclusters; - } - - public static int CM_NumInlineModels() { - return numcmodels; - } - - public static String CM_EntityString() { - return map_entitystring; - } - - public static int CM_LeafContents(int leafnum) { - if (leafnum < 0 || leafnum >= numleafs) - Com.Error(ERR_DROP, "CM_LeafContents: bad number"); - return map_leafs[leafnum].contents; - } - - public static int CM_LeafCluster(int leafnum) { - if (leafnum < 0 || leafnum >= numleafs) - Com.Error(ERR_DROP, "CM_LeafCluster: bad number"); - return map_leafs[leafnum].cluster; - } - - public static int CM_LeafArea(int leafnum) { - if (leafnum < 0 || leafnum >= numleafs) - Com.Error(ERR_DROP, "CM_LeafArea: bad number"); - return map_leafs[leafnum].area; - } - - //======================================================================= - - static cplane_t box_planes[]; - static int box_headnode; - static cbrush_t box_brush; - static cleaf_t box_leaf; - - /* - =================== - CM_InitBoxHull - - Set up the planes and nodes so that the six floats of a bounding box - can just be stored out and get a proper clipping hull structure. - =================== - */ - public static void CM_InitBoxHull() { - int i; - int side; - cnode_t c; - cplane_t p; - cbrushside_t s; - - box_headnode = numnodes; // noch platz f?r 6 brushes - - box_planes = - new cplane_t[] { - map_planes[numplanes], - map_planes[numplanes + 1], - map_planes[numplanes + 2], - map_planes[numplanes + 3], - map_planes[numplanes + 4], - map_planes[numplanes + 5], - map_planes[numplanes + 6], - map_planes[numplanes + 7], - map_planes[numplanes + 8], - map_planes[numplanes + 9], - map_planes[numplanes + 10], - map_planes[numplanes + 11], - map_planes[numplanes + 12] }; - - if (numnodes + 6 > MAX_MAP_NODES - || numbrushes + 1 > MAX_MAP_BRUSHES - || numleafbrushes + 1 > MAX_MAP_LEAFBRUSHES - || numbrushsides + 6 > MAX_MAP_BRUSHSIDES - || numplanes + 12 > MAX_MAP_PLANES) - Com.Error(ERR_DROP, "Not enough room for box tree"); - - box_brush = map_brushes[numbrushes]; - box_brush.numsides = 6; - box_brush.firstbrushside = numbrushsides; - box_brush.contents = CONTENTS_MONSTER; - - box_leaf = map_leafs[numleafs]; - box_leaf.contents = CONTENTS_MONSTER; - box_leaf.firstleafbrush = (short) numleafbrushes; - box_leaf.numleafbrushes = 1; - - map_leafbrushes[numleafbrushes] = numbrushes; - - for (i = 0; i < 6; i++) { - side = i & 1; - - // brush sides - s = map_brushsides[numbrushsides + i]; - s.plane = map_planes[(numplanes + i * 2 + side)]; - s.surface = nullsurface; - - // nodes - c = map_nodes[box_headnode + i]; - c.plane = map_planes[(numplanes + i * 2)]; - c.children[side] = -1 - emptyleaf; - if (i != 5) - c.children[side ^ 1] = box_headnode + i + 1; - else - c.children[side ^ 1] = -1 - numleafs; - - // planes - p = box_planes[i * 2]; - p.type = (byte) (i >> 1); - p.signbits = 0; - VectorClear(p.normal); - p.normal[i >> 1] = 1; - - p = box_planes[i * 2 + 1]; - p.type = (byte) (3 + (i >> 1)); - p.signbits = 0; - VectorClear(p.normal); - p.normal[i >> 1] = -1; - } - } - - /* - =================== - CM_HeadnodeForBox - - To keep everything totally uniform, bounding boxes are turned into small - BSP trees instead of being compared directly. - =================== - */ - public static int HeadnodeForBox(float[] mins, float[] maxs) { - box_planes[0].dist = maxs[0]; - box_planes[1].dist = -maxs[0]; - box_planes[2].dist = mins[0]; - box_planes[3].dist = -mins[0]; - box_planes[4].dist = maxs[1]; - box_planes[5].dist = -maxs[1]; - box_planes[6].dist = mins[1]; - box_planes[7].dist = -mins[1]; - box_planes[8].dist = maxs[2]; - box_planes[9].dist = -maxs[2]; - box_planes[10].dist = mins[2]; - box_planes[11].dist = -mins[2]; - - return box_headnode; - } - - /* - ================== - CM_PointLeafnum_r - ================== - */ - public static int CM_PointLeafnum_r(float[] p, int num) { - float d; - cnode_t node; - cplane_t plane; - - while (num >= 0) { - node = map_nodes[num]; - plane = node.plane; - - if (plane.type < 3) - d = p[plane.type] - plane.dist; - else - d = DotProduct(plane.normal, p) - plane.dist; - if (d < 0) - num = node.children[1]; - else - num = node.children[0]; - } - - c_pointcontents++; // optimize counter - - return -1 - num; - } - - public static int CM_PointLeafnum(float[] p) { - if (numplanes == 0) - return 0; // sound may call this without map loaded - return CM_PointLeafnum_r(p, 0); - } - - /* - ============= - CM_BoxLeafnums - - Fills in a list of all the leafs touched - ============= - */ - static int leaf_count, leaf_maxcount; - static int leaf_list[]; - static float leaf_mins[], leaf_maxs[]; - static int leaf_topnode; - - public static void CM_BoxLeafnums_r(int nodenum) { - cplane_t plane; - cnode_t node; - int s; - - while (true) { - if (nodenum < 0) { - if (leaf_count >= leaf_maxcount) { - //TODO: here is still an error. - //Com.DPrintf("CM_BoxLeafnums_r: overflow\n"); - return; - } - leaf_list[leaf_count++] = -1 - nodenum; - return; - } - - node = map_nodes[nodenum]; - plane = node.plane; - - s = Math3D.BoxOnPlaneSide(leaf_mins, leaf_maxs, plane); - - if (s == 1) - nodenum = node.children[0]; - else if (s == 2) - nodenum = node.children[1]; - else { - // go down both - if (leaf_topnode == -1) - leaf_topnode = nodenum; - CM_BoxLeafnums_r(node.children[0]); - nodenum = node.children[1]; - } - } - } - - public static int CM_BoxLeafnums_headnode(float[] mins, float[] maxs, int list[], int listsize, int headnode, int topnode[]) { - leaf_list = list; - leaf_count = 0; - leaf_maxcount = listsize; - leaf_mins = mins; - leaf_maxs = maxs; - - leaf_topnode = -1; - - CM_BoxLeafnums_r(headnode); - - if (topnode != null) - topnode[0] = leaf_topnode; - - return leaf_count; - } - - public static int CM_BoxLeafnums(float[] mins, float[] maxs, int list[], int listsize, int topnode[]) { - return CM_BoxLeafnums_headnode(mins, maxs, list, listsize, map_cmodels[0].headnode, topnode); - } - - /* - public static class intwrap1 { - public intwrap(int i) { - this.i = i; - } - public int i; - } - */ - /* - ================== - CM_PointContents - ================== - */ - public static int PointContents(float[] p, int headnode) { - int l; - - if (numnodes == 0) // map not loaded - return 0; - - l = CM_PointLeafnum_r(p, headnode); - - return map_leafs[l].contents; - } - - /* - ================== - CM_TransformedPointContents - - Handles offseting and rotation of the end points for moving and - rotating entities - ================== - */ - public static int TransformedPointContents(float[] p, int headnode, float[] origin, float[] angles) { - float[] p_l = { 0, 0, 0 }; - float[] temp = { 0, 0, 0 }; - float[] forward = { 0, 0, 0 }, right = { 0, 0, 0 }, up = { 0, 0, 0 }; - int l; - - // subtract origin offset - VectorSubtract(p, origin, p_l); - - // rotate start and end into the models frame of reference - if (headnode != box_headnode && (angles[0] != 0 || angles[1] != 0 || angles[2] != 0)) { - AngleVectors(angles, forward, right, up); - - VectorCopy(p_l, temp); - p_l[0] = DotProduct(temp, forward); - p_l[1] = -DotProduct(temp, right); - p_l[2] = DotProduct(temp, up); - } - - l = CM_PointLeafnum_r(p_l, headnode); - - return map_leafs[l].contents; - } - - /* - =============================================================================== - - BOX TRACING - - =============================================================================== - */ - - // 1/32 epsilon to keep floating point happy - private static final float DIST_EPSILON = 0.03125f; - - private static float[] trace_start = { 0, 0, 0 }, trace_end = { 0, 0, 0 }; - private static float[] trace_mins = { 0, 0, 0 }, trace_maxs = { 0, 0, 0 }; - private static float[] trace_extents = { 0, 0, 0 }; - - private static trace_t trace_trace = new trace_t(); - private static int trace_contents; - private static boolean trace_ispoint; // optimized case - - /* - ================ - CM_ClipBoxToBrush - ================ - */ - public static void CM_ClipBoxToBrush(float[] mins, float[] maxs, float[] p1, float[] p2, trace_t trace, cbrush_t brush) { - int i, j; - cplane_t plane, clipplane; - float dist; - float enterfrac, leavefrac; - float[] ofs = { 0, 0, 0 }; - float d1, d2; - boolean getout, startout; - float f; - cbrushside_t side, leadside; - - enterfrac = -1; - leavefrac = 1; - clipplane = null; - - if (brush.numsides == 0) - return; - - c_brush_traces++; - - getout = false; - startout = false; - leadside = null; - - for (i = 0; i < brush.numsides; i++) { - side = map_brushsides[brush.firstbrushside + i]; - plane = side.plane; - - // FIXME: special case for axial - - if (!trace_ispoint) { // general box case - - // push the plane out apropriately for mins/maxs - - // FIXME: use signbits into 8 way lookup for each mins/maxs - for (j = 0; j < 3; j++) { - if (plane.normal[j] < 0) - ofs[j] = maxs[j]; - else - ofs[j] = mins[j]; - } - dist = DotProduct(ofs, plane.normal); - dist = plane.dist - dist; - } - else { // special point case - dist = plane.dist; - } - - d1 = DotProduct(p1, plane.normal) - dist; - d2 = DotProduct(p2, plane.normal) - dist; - - if (d2 > 0) - getout = true; // endpoint is not in solid - if (d1 > 0) - startout = true; - - // if completely in front of face, no intersection - if (d1 > 0 && d2 >= d1) - return; - - if (d1 <= 0 && d2 <= 0) - continue; - - // crosses face - if (d1 > d2) { // enter - f = (d1 - DIST_EPSILON) / (d1 - d2); - if (f > enterfrac) { - enterfrac = f; - clipplane = plane; - leadside = side; - } - } - else { // leave - f = (d1 + DIST_EPSILON) / (d1 - d2); - if (f < leavefrac) - leavefrac = f; - } - } - - if (!startout) { // original point was inside brush - trace.startsolid = true; - if (!getout) - trace.allsolid = true; - return; - } - if (enterfrac < leavefrac) { - if (enterfrac > -1 && enterfrac < trace.fraction) { - if (enterfrac < 0) - enterfrac = 0; - trace.fraction = enterfrac; - // copy - trace.plane.set(clipplane); - trace.surface = leadside.surface.c; - trace.contents = brush.contents; - } - } - } - - /* - ================ - CM_TestBoxInBrush - ================ - */ - public static void CM_TestBoxInBrush(float[] mins, float[] maxs, float[] p1, trace_t trace, cbrush_t brush) { - int i, j; - cplane_t plane; - float dist; - float[] ofs = { 0, 0, 0 }; - float d1; - cbrushside_t side; - - if (brush.numsides == 0) - return; - - for (i = 0; i < brush.numsides; i++) { - side = map_brushsides[brush.firstbrushside + i]; - plane = side.plane; - - // FIXME: special case for axial - // general box case - // push the plane out apropriately for mins/maxs - // FIXME: use signbits into 8 way lookup for each mins/maxs - - for (j = 0; j < 3; j++) { - if (plane.normal[j] < 0) - ofs[j] = maxs[j]; - else - ofs[j] = mins[j]; - } - dist = DotProduct(ofs, plane.normal); - dist = plane.dist - dist; - - d1 = DotProduct(p1, plane.normal) - dist; - - // if completely in front of face, no intersection - if (d1 > 0) - return; - - } - - // inside this brush - trace.startsolid = trace.allsolid = true; - trace.fraction = 0; - trace.contents = brush.contents; - } - - /* - ================ - CM_TraceToLeaf - ================ - */ - public static void CM_TraceToLeaf(int leafnum) { - int k; - int brushnum; - cleaf_t leaf; - cbrush_t b; - - leaf = map_leafs[leafnum]; - if (0 == (leaf.contents & trace_contents)) - return; - - // trace line against all brushes in the leaf - for (k = 0; k < leaf.numleafbrushes; k++) { - - brushnum = map_leafbrushes[leaf.firstleafbrush + k]; - b = map_brushes[brushnum]; - if (b.checkcount == checkcount) - continue; // already checked this brush in another leaf - b.checkcount = checkcount; - - if (0 == (b.contents & trace_contents)) - continue; - CM_ClipBoxToBrush(trace_mins, trace_maxs, trace_start, trace_end, trace_trace, b); - if (0 == trace_trace.fraction) - return; - } - - } - - /* - ================ - CM_TestInLeaf - ================ - */ - public static void CM_TestInLeaf(int leafnum) { - int k; - int brushnum; - cleaf_t leaf; - cbrush_t b; - - leaf = map_leafs[leafnum]; - if (0 == (leaf.contents & trace_contents)) - return; - // trace line against all brushes in the leaf - for (k = 0; k < leaf.numleafbrushes; k++) { - brushnum = map_leafbrushes[leaf.firstleafbrush + k]; - b = map_brushes[brushnum]; - if (b.checkcount == checkcount) - continue; // already checked this brush in another leaf - b.checkcount = checkcount; - - if (0 == (b.contents & trace_contents)) - continue; - CM_TestBoxInBrush(trace_mins, trace_maxs, trace_start, trace_trace, b); - if (0 == trace_trace.fraction) - return; - } - - } - - /* - ================== - CM_RecursiveHullCheck - ================== - */ - public static void CM_RecursiveHullCheck(int num, float p1f, float p2f, float[] p1, float[] p2) { - cnode_t node; - cplane_t plane; - float t1, t2, offset; - float frac, frac2; - float idist; - int i; - float[] mid = { 0, 0, 0 }; - int side; - float midf; - - if (trace_trace.fraction <= p1f) - return; // already hit something nearer - - // if < 0, we are in a leaf node - if (num < 0) { - CM_TraceToLeaf(-1 - num); - return; - } - - // - // find the point distances to the seperating plane - // and the offset for the size of the box - // - node = map_nodes[num]; - plane = node.plane; - - if (plane.type < 3) { - t1 = p1[plane.type] - plane.dist; - t2 = p2[plane.type] - plane.dist; - offset = trace_extents[plane.type]; - } - else { - t1 = DotProduct(plane.normal, p1) - plane.dist; - t2 = DotProduct(plane.normal, p2) - plane.dist; - if (trace_ispoint) - offset = 0; - else - offset = - Math.abs(trace_extents[0] * plane.normal[0]) - + Math.abs(trace_extents[1] * plane.normal[1]) - + Math.abs(trace_extents[2] * plane.normal[2]); - } - - // see which sides we need to consider - if (t1 >= offset && t2 >= offset) { - CM_RecursiveHullCheck(node.children[0], p1f, p2f, p1, p2); - return; - } - if (t1 < -offset && t2 < -offset) { - CM_RecursiveHullCheck(node.children[1], p1f, p2f, p1, p2); - return; - } - - // put the crosspoint DIST_EPSILON pixels on the near side - if (t1 < t2) { - idist = 1.0f / (t1 - t2); - side = 1; - frac2 = (t1 + offset + DIST_EPSILON) * idist; - frac = (t1 - offset + DIST_EPSILON) * idist; - } - else if (t1 > t2) { - idist = 1.0f / (t1 - t2); - side = 0; - frac2 = (t1 - offset - DIST_EPSILON) * idist; - frac = (t1 + offset + DIST_EPSILON) * idist; - } - else { - side = 0; - frac = 1; - frac2 = 0; - } - - // move up to the node - if (frac < 0) - frac = 0; - if (frac > 1) - frac = 1; - - midf = p1f + (p2f - p1f) * frac; - for (i = 0; i < 3; i++) - mid[i] = p1[i] + frac * (p2[i] - p1[i]); - - CM_RecursiveHullCheck(node.children[side], p1f, midf, p1, mid); - - // go past the node - if (frac2 < 0) - frac2 = 0; - if (frac2 > 1) - frac2 = 1; - - midf = p1f + (p2f - p1f) * frac2; - for (i = 0; i < 3; i++) - mid[i] = p1[i] + frac2 * (p2[i] - p1[i]); - - CM_RecursiveHullCheck(node.children[side ^ 1], midf, p2f, mid, p2); - } - - //====================================================================== - - /* - ================== - CM_BoxTrace - ================== - */ - public static trace_t BoxTrace(float[] start, float[] end, float[] mins, float[] maxs, int headnode, int brushmask) { - - // for multi-check avoidance - checkcount++; - - // for statistics, may be zeroed - c_traces++; - - // fill in a default trace - //was: memset(& trace_trace, 0, sizeof(trace_trace)); - trace_trace = new trace_t(); - - trace_trace.fraction = 1; - trace_trace.surface = nullsurface.c; - - if (numnodes == 0) // map not loaded - { - Com.DPrintf("dummy trace zurueck, da map not loaded!\n"); - return trace_trace; - } - - trace_contents = brushmask; - VectorCopy(start, trace_start); - VectorCopy(end, trace_end); - VectorCopy(mins, trace_mins); - VectorCopy(maxs, trace_maxs); - - // - // check for position test special case - // - if (start[0] == end[0] && start[1] == end[1] && start[2] == end[2]) { - - int leafs[] = new int[1024]; - int i, numleafs; - float[] c1 = { 0, 0, 0 }, c2 = { 0, 0, 0 }; - int topnode = 0; - - VectorAdd(start, mins, c1); - VectorAdd(start, maxs, c2); - - for (i = 0; i < 3; i++) { - c1[i] -= 1; - c2[i] += 1; - } - - int tn[] = {topnode}; - - numleafs = CM_BoxLeafnums_headnode(c1, c2, leafs, 1024, headnode, tn); - topnode = tn[0]; - for (i = 0; i < numleafs; i++) { - CM_TestInLeaf(leafs[i]); - if (trace_trace.allsolid) - break; - } - VectorCopy(start, trace_trace.endpos); - return trace_trace; - } - - // - // check for point special case - // - if (mins[0] == 0 && mins[1] == 0 && mins[2] == 0 && maxs[0] == 0 && maxs[1] == 0 && maxs[2] == 0) { - trace_ispoint = true; - VectorClear(trace_extents); - } - else { - trace_ispoint = false; - trace_extents[0] = -mins[0] > maxs[0] ? -mins[0] : maxs[0]; - trace_extents[1] = -mins[1] > maxs[1] ? -mins[1] : maxs[1]; - trace_extents[2] = -mins[2] > maxs[2] ? -mins[2] : maxs[2]; - } - - // - // general sweeping through world - // - CM_RecursiveHullCheck(headnode, 0, 1, start, end); - - if (trace_trace.fraction == 1) { - VectorCopy(end, trace_trace.endpos); - } - else { - for (int i = 0; i < 3; i++) - trace_trace.endpos[i] = start[i] + trace_trace.fraction * (end[i] - start[i]); - } - return trace_trace; - } - - /* - ================== - CM_TransformedBoxTrace - - Handles offseting and rotation of the end points for moving and - rotating entities - ================== - */ - public static trace_t TransformedBoxTrace( - float[] start, - float[] end, - float[] mins, - float[] maxs, - int headnode, - int brushmask, - float[] origin, - float[] angles) { - trace_t trace; - float[] start_l = { 0, 0, 0 }, end_l = { 0, 0, 0 }; - float[] a = { 0, 0, 0 }; - float[] forward = { 0, 0, 0 }, right = { 0, 0, 0 }, up = { 0, 0, 0 }; - float[] temp = { 0, 0, 0 }; - boolean rotated; - - // subtract origin offset - VectorSubtract(start, origin, start_l); - VectorSubtract(end, origin, end_l); - - // rotate start and end into the models frame of reference - if (headnode != box_headnode && (angles[0] != 0 || angles[1] != 0 || angles[2] != 0)) - rotated = true; - else - rotated = false; - - if (rotated) { - AngleVectors(angles, forward, right, up); - - VectorCopy(start_l, temp); - start_l[0] = DotProduct(temp, forward); - start_l[1] = -DotProduct(temp, right); - start_l[2] = DotProduct(temp, up); - - VectorCopy(end_l, temp); - end_l[0] = DotProduct(temp, forward); - end_l[1] = -DotProduct(temp, right); - end_l[2] = DotProduct(temp, up); - } - - // sweep the box through the model - trace = BoxTrace(start_l, end_l, mins, maxs, headnode, brushmask); - - if (rotated && trace.fraction != 1.0) { - // FIXME: figure out how to do this with existing angles - VectorNegate(angles, a); - AngleVectors(a, forward, right, up); - - VectorCopy(trace.plane.normal, temp); - trace.plane.normal[0] = DotProduct(temp, forward); - trace.plane.normal[1] = -DotProduct(temp, right); - trace.plane.normal[2] = DotProduct(temp, up); - } - - trace.endpos[0] = start[0] + trace.fraction * (end[0] - start[0]); - trace.endpos[1] = start[1] + trace.fraction * (end[1] - start[1]); - trace.endpos[2] = start[2] + trace.fraction * (end[2] - start[2]); - - return trace; - } - - /* - =============================================================================== - PVS / PHS - =============================================================================== - */ - - /* - =================== - CM_DecompressVis - =================== - */ - public static void CM_DecompressVis(byte in[], int offset, byte out[]) { - int c; - - int row; - - row = (numclusters + 7) >> 3; - int outp = 0; - int inp = offset; - - if (in == null || numvisibility == 0) { // no vis info, so make all visible - while (row != 0) { - out[outp++] = (byte) 0xFF; - row--; - } - return; - } - - do { - if (in[inp] != 0) { - out[outp++] = in[inp++]; - continue; - } - - c = in[inp + 1] & 0xFF; - inp += 2; - if (outp + c > row) { - c = row - (outp); - Com.DPrintf("warning: Vis decompression overrun\n"); - } - while (c != 0) { - out[outp++] = 0; - c--; - } - } - while (outp < row); - } - - public static byte pvsrow[] = new byte[MAX_MAP_LEAFS / 8]; - public static byte phsrow[] = new byte[MAX_MAP_LEAFS / 8]; - - public static byte[] CM_ClusterPVS(int cluster) { - if (cluster == -1) - Arrays.fill(pvsrow, 0, (numclusters + 7) >> 3, (byte)0); - else - CM_DecompressVis(map_visibility, map_vis.bitofs[cluster][DVIS_PVS], pvsrow); - return pvsrow; - } - - public static byte[] CM_ClusterPHS(int cluster) { - if (cluster == -1) - Arrays.fill(phsrow, 0, (numclusters + 7) >> 3, (byte)0); - else - CM_DecompressVis(map_visibility, map_vis.bitofs[cluster][Defines.DVIS_PHS], phsrow); - return phsrow; - } - - /* - =============================================================================== - AREAPORTALS - =============================================================================== - */ - - public static void FloodArea_r(carea_t area, int floodnum) { - //Com.Printf("FloodArea_r(" + floodnum + ")...\n"); - int i; - qfiles.dareaportal_t p; - - if (area.floodvalid == floodvalid) { - if (area.floodnum == floodnum) - return; - Com.Error(ERR_DROP, "FloodArea_r: reflooded"); - } - - area.floodnum = floodnum; - area.floodvalid = floodvalid; - - for (i = 0; i < area.numareaportals; i++) { - p = map_areaportals[area.firstareaportal + i]; - if (portalopen[p.portalnum]) - FloodArea_r(map_areas[p.otherarea], floodnum); - } - } - - /* - ==================== - FloodAreaConnections - ==================== - */ - public static void FloodAreaConnections() { - Com.DPrintf("FloodAreaConnections...\n"); - - int i; - carea_t area; - int floodnum; - - // all current floods are now invalid - floodvalid++; - floodnum = 0; - - // area 0 is not used - for (i = 1; i < numareas; i++) { - - area = map_areas[i]; - - if (area.floodvalid == floodvalid) - continue; // already flooded into - floodnum++; - FloodArea_r(area, floodnum); - } - } - - /* - ================= - CM_SetAreaPortalState - ================= - */ - public static void CM_SetAreaPortalState(int portalnum, boolean open) { - if (portalnum > numareaportals) - Com.Error(ERR_DROP, "areaportal > numareaportals"); - - portalopen[portalnum] = open; - FloodAreaConnections(); - } - - /* - ================= - CM_AreasConnected - ================= - */ - - public static boolean CM_AreasConnected(int area1, int area2) { - if (map_noareas.value != 0) - return true; - - if (area1 > numareas || area2 > numareas) - Com.Error(ERR_DROP, "area > numareas"); - - if (map_areas[area1].floodnum == map_areas[area2].floodnum) - return true; - - return false; - } - - /* - ================= - CM_WriteAreaBits - - Writes a length byte followed by a bit vector of all the areas - that area in the same flood as the area parameter - - This is used by the client refreshes to cull visibility - ================= - */ - public static int CM_WriteAreaBits(byte buffer[], int area) { - int i; - int floodnum; - int bytes; - - bytes = (numareas + 7) >> 3; - - if (map_noareas.value != 0) { // for debugging, send everything - Arrays.fill(buffer, 0, bytes, (byte)255); - } - else { - Arrays.fill(buffer, 0, bytes, (byte)0); - floodnum = map_areas[area].floodnum; - for (i = 0; i < numareas; i++) { - if (map_areas[i].floodnum == floodnum || area == 0) - buffer[i >> 3] |= 1 << (i & 7); - } - } - - return bytes; - } - - /* - =================== - CM_WritePortalState - - Writes the portal state to a savegame file - =================== - */ - - public static void CM_WritePortalState(RandomAccessFile os) { - - //was: fwrite(portalopen, sizeof(portalopen), 1, f); - try { - - for (int n = 0; n < portalopen.length; n++) - if (portalopen[n]) - os.writeInt(1); - else - os.writeInt(0); - } - catch (Exception e) { - Com.Printf("ERROR:" + e); - e.printStackTrace(); - } - } - - /* - =================== - CM_ReadPortalState - - Reads the portal state from a savegame file - and recalculates the area connections - =================== - */ - public static void CM_ReadPortalState(RandomAccessFile f) { - - //was: FS_Read(portalopen, sizeof(portalopen), f); - int len = portalopen.length * 4; - - byte buf[] = new byte[len]; - - - FS.Read(buf, len, f); - - ByteBuffer bb = ByteBuffer.wrap(buf); - IntBuffer ib = bb.asIntBuffer(); - - for (int n = 0; n < portalopen.length; n++) - portalopen[n] = ib.get() != 0; - - FloodAreaConnections(); - } - - /* - ============= - CM_HeadnodeVisible - - Returns true if any leaf under headnode has a cluster that - is potentially visible - ============= - */ - public static boolean CM_HeadnodeVisible(int nodenum, byte visbits[]) { - int leafnum; - int cluster; - cnode_t node; - - if (nodenum < 0) { - leafnum = -1 - nodenum; - cluster = map_leafs[leafnum].cluster; - if (cluster == -1) - return false; - if (0 != (visbits[cluster >>> 3] & (1 << (cluster & 7)))) - return true; - return false; - } - - node = map_nodes[nodenum]; - if (CM_HeadnodeVisible(node.children[0], visbits)) - return true; - return CM_HeadnodeVisible(node.children[1], visbits); - } -} + /* + * ================= CMod_LoadVisibility ================= + */ + public static void CMod_LoadVisibility(lump_t l) { + Com.DPrintf("CMod_LoadVisibility...\n"); + int i; + + numvisibility = l.filelen; + + Com.DPrintf(" numvisibility=" + numvisibility + "\n"); + + if (l.filelen > Defines.MAX_MAP_VISIBILITY) + Com.Error(Defines.ERR_DROP, "Map has too large visibility lump"); + + System.arraycopy(cmod_base, l.fileofs, map_visibility, 0, l.filelen); + + ByteBuffer bb = ByteBuffer.wrap(map_visibility, 0, l.filelen); + bb.order(ByteOrder.LITTLE_ENDIAN); + + map_vis = new qfiles.dvis_t(bb); + + } + + /* + * ================= CMod_LoadEntityString ================= + */ + public static void CMod_LoadEntityString(lump_t l) { + Com.DPrintf("CMod_LoadEntityString...\n"); + + numentitychars = l.filelen; + + if (l.filelen > Defines.MAX_MAP_ENTSTRING) + Com.Error(Defines.ERR_DROP, "Map has too large entity lump"); + + int x = 0; + for (; x < l.filelen && cmod_base[x + l.fileofs] != 0; x++) + ; + + map_entitystring = new String(cmod_base, l.fileofs, x).trim(); + } + + /* + * ================== CM_InlineModel ================== + */ + + // works fine + public static cmodel_t InlineModel(String name) { + int num; + + if (name == null || name.charAt(0) != '*') + Com.Error(Defines.ERR_DROP, "CM_InlineModel: bad name"); + + num = Lib.atoi(name.substring(1)); + + if (num < 1 || num >= numcmodels) + Com.Error(Defines.ERR_DROP, "CM_InlineModel: bad number"); + + return map_cmodels[num]; + } + + public static int CM_NumClusters() { + return numclusters; + } + + public static int CM_NumInlineModels() { + return numcmodels; + } + + public static String CM_EntityString() { + return map_entitystring; + } + + public static int CM_LeafContents(int leafnum) { + if (leafnum < 0 || leafnum >= numleafs) + Com.Error(Defines.ERR_DROP, "CM_LeafContents: bad number"); + return map_leafs[leafnum].contents; + } + + public static int CM_LeafCluster(int leafnum) { + if (leafnum < 0 || leafnum >= numleafs) + Com.Error(Defines.ERR_DROP, "CM_LeafCluster: bad number"); + return map_leafs[leafnum].cluster; + } + + public static int CM_LeafArea(int leafnum) { + if (leafnum < 0 || leafnum >= numleafs) + Com.Error(Defines.ERR_DROP, "CM_LeafArea: bad number"); + return map_leafs[leafnum].area; + } + + //======================================================================= + + static cplane_t box_planes[]; + + static int box_headnode; + + static cbrush_t box_brush; + + static cleaf_t box_leaf; + + /* + * =================== CM_InitBoxHull + * + * Set up the planes and nodes so that the six floats of a bounding box can + * just be stored out and get a proper clipping hull structure. + * =================== + */ + public static void CM_InitBoxHull() { + int i; + int side; + cnode_t c; + cplane_t p; + cbrushside_t s; + + box_headnode = numnodes; // noch platz f?r 6 brushes + + box_planes = new cplane_t[] { map_planes[numplanes], + map_planes[numplanes + 1], map_planes[numplanes + 2], + map_planes[numplanes + 3], map_planes[numplanes + 4], + map_planes[numplanes + 5], map_planes[numplanes + 6], + map_planes[numplanes + 7], map_planes[numplanes + 8], + map_planes[numplanes + 9], map_planes[numplanes + 10], + map_planes[numplanes + 11], map_planes[numplanes + 12] }; + + if (numnodes + 6 > Defines.MAX_MAP_NODES + || numbrushes + 1 > Defines.MAX_MAP_BRUSHES + || numleafbrushes + 1 > Defines.MAX_MAP_LEAFBRUSHES + || numbrushsides + 6 > Defines.MAX_MAP_BRUSHSIDES + || numplanes + 12 > Defines.MAX_MAP_PLANES) + Com.Error(Defines.ERR_DROP, "Not enough room for box tree"); + + box_brush = map_brushes[numbrushes]; + box_brush.numsides = 6; + box_brush.firstbrushside = numbrushsides; + box_brush.contents = Defines.CONTENTS_MONSTER; + + box_leaf = map_leafs[numleafs]; + box_leaf.contents = Defines.CONTENTS_MONSTER; + box_leaf.firstleafbrush = (short) numleafbrushes; + box_leaf.numleafbrushes = 1; + + map_leafbrushes[numleafbrushes] = numbrushes; + + for (i = 0; i < 6; i++) { + side = i & 1; + + // brush sides + s = map_brushsides[numbrushsides + i]; + s.plane = map_planes[(numplanes + i * 2 + side)]; + s.surface = nullsurface; + + // nodes + c = map_nodes[box_headnode + i]; + c.plane = map_planes[(numplanes + i * 2)]; + c.children[side] = -1 - emptyleaf; + if (i != 5) + c.children[side ^ 1] = box_headnode + i + 1; + else + c.children[side ^ 1] = -1 - numleafs; + + // planes + p = box_planes[i * 2]; + p.type = (byte) (i >> 1); + p.signbits = 0; + Math3D.VectorClear(p.normal); + p.normal[i >> 1] = 1; + + p = box_planes[i * 2 + 1]; + p.type = (byte) (3 + (i >> 1)); + p.signbits = 0; + Math3D.VectorClear(p.normal); + p.normal[i >> 1] = -1; + } + } + + /* + * =================== CM_HeadnodeForBox + * + * To keep everything totally uniform, bounding boxes are turned into small + * BSP trees instead of being compared directly. =================== + */ + public static int HeadnodeForBox(float[] mins, float[] maxs) { + box_planes[0].dist = maxs[0]; + box_planes[1].dist = -maxs[0]; + box_planes[2].dist = mins[0]; + box_planes[3].dist = -mins[0]; + box_planes[4].dist = maxs[1]; + box_planes[5].dist = -maxs[1]; + box_planes[6].dist = mins[1]; + box_planes[7].dist = -mins[1]; + box_planes[8].dist = maxs[2]; + box_planes[9].dist = -maxs[2]; + box_planes[10].dist = mins[2]; + box_planes[11].dist = -mins[2]; + + return box_headnode; + } + + /* + * ================== CM_PointLeafnum_r ================== + */ + public static int CM_PointLeafnum_r(float[] p, int num) { + float d; + cnode_t node; + cplane_t plane; + + while (num >= 0) { + node = map_nodes[num]; + plane = node.plane; + + if (plane.type < 3) + d = p[plane.type] - plane.dist; + else + d = Math3D.DotProduct(plane.normal, p) - plane.dist; + if (d < 0) + num = node.children[1]; + else + num = node.children[0]; + } + + Globals.c_pointcontents++; // optimize counter + + return -1 - num; + } + + public static int CM_PointLeafnum(float[] p) { + if (numplanes == 0) + return 0; // sound may call this without map loaded + return CM_PointLeafnum_r(p, 0); + } + + /* + * ============= CM_BoxLeafnums + * + * Fills in a list of all the leafs touched ============= + */ + static int leaf_count, leaf_maxcount; + + static int leaf_list[]; + + static float leaf_mins[], leaf_maxs[]; + + static int leaf_topnode; + + public static void CM_BoxLeafnums_r(int nodenum) { + cplane_t plane; + cnode_t node; + int s; + + while (true) { + if (nodenum < 0) { + if (leaf_count >= leaf_maxcount) { + //TODO: here is still an error. + //Com.DPrintf("CM_BoxLeafnums_r: overflow\n"); + return; + } + leaf_list[leaf_count++] = -1 - nodenum; + return; + } + + node = map_nodes[nodenum]; + plane = node.plane; + + s = Math3D.BoxOnPlaneSide(leaf_mins, leaf_maxs, plane); + + if (s == 1) + nodenum = node.children[0]; + else if (s == 2) + nodenum = node.children[1]; + else { + // go down both + if (leaf_topnode == -1) + leaf_topnode = nodenum; + CM_BoxLeafnums_r(node.children[0]); + nodenum = node.children[1]; + } + } + } + + public static int CM_BoxLeafnums_headnode(float[] mins, float[] maxs, + int list[], int listsize, int headnode, int topnode[]) { + leaf_list = list; + leaf_count = 0; + leaf_maxcount = listsize; + leaf_mins = mins; + leaf_maxs = maxs; + + leaf_topnode = -1; + + CM_BoxLeafnums_r(headnode); + + if (topnode != null) + topnode[0] = leaf_topnode; + + return leaf_count; + } + + public static int CM_BoxLeafnums(float[] mins, float[] maxs, int list[], + int listsize, int topnode[]) { + return CM_BoxLeafnums_headnode(mins, maxs, list, listsize, + map_cmodels[0].headnode, topnode); + } + + /* + * public static class intwrap1 { public intwrap(int i) { this.i = i; } + * public int i; } + */ + /* + * ================== CM_PointContents ================== + */ + public static int PointContents(float[] p, int headnode) { + int l; + + if (numnodes == 0) // map not loaded + return 0; + + l = CM_PointLeafnum_r(p, headnode); + + return map_leafs[l].contents; + } + + /* + * ================== CM_TransformedPointContents + * + * Handles offseting and rotation of the end points for moving and rotating + * entities ================== + */ + public static int TransformedPointContents(float[] p, int headnode, + float[] origin, float[] angles) { + float[] p_l = { 0, 0, 0 }; + float[] temp = { 0, 0, 0 }; + float[] forward = { 0, 0, 0 }, right = { 0, 0, 0 }, up = { 0, 0, 0 }; + int l; + + // subtract origin offset + Math3D.VectorSubtract(p, origin, p_l); + + // rotate start and end into the models frame of reference + if (headnode != box_headnode + && (angles[0] != 0 || angles[1] != 0 || angles[2] != 0)) { + Math3D.AngleVectors(angles, forward, right, up); + + Math3D.VectorCopy(p_l, temp); + p_l[0] = Math3D.DotProduct(temp, forward); + p_l[1] = -Math3D.DotProduct(temp, right); + p_l[2] = Math3D.DotProduct(temp, up); + } + + l = CM_PointLeafnum_r(p_l, headnode); + + return map_leafs[l].contents; + } + + /* + * =============================================================================== + * + * BOX TRACING + * + * =============================================================================== + */ + + // 1/32 epsilon to keep floating point happy + private static final float DIST_EPSILON = 0.03125f; + + private static float[] trace_start = { 0, 0, 0 }, trace_end = { 0, 0, 0 }; + + private static float[] trace_mins = { 0, 0, 0 }, trace_maxs = { 0, 0, 0 }; + + private static float[] trace_extents = { 0, 0, 0 }; + + private static trace_t trace_trace = new trace_t(); + + private static int trace_contents; + + private static boolean trace_ispoint; // optimized case + + /* + * ================ CM_ClipBoxToBrush ================ + */ + public static void CM_ClipBoxToBrush(float[] mins, float[] maxs, + float[] p1, float[] p2, trace_t trace, cbrush_t brush) { + int i, j; + cplane_t plane, clipplane; + float dist; + float enterfrac, leavefrac; + float[] ofs = { 0, 0, 0 }; + float d1, d2; + boolean getout, startout; + float f; + cbrushside_t side, leadside; + + enterfrac = -1; + leavefrac = 1; + clipplane = null; + + if (brush.numsides == 0) + return; + + Globals.c_brush_traces++; + + getout = false; + startout = false; + leadside = null; + + for (i = 0; i < brush.numsides; i++) { + side = map_brushsides[brush.firstbrushside + i]; + plane = side.plane; + + // FIXME: special case for axial + + if (!trace_ispoint) { // general box case + + // push the plane out apropriately for mins/maxs + + // FIXME: use signbits into 8 way lookup for each mins/maxs + for (j = 0; j < 3; j++) { + if (plane.normal[j] < 0) + ofs[j] = maxs[j]; + else + ofs[j] = mins[j]; + } + dist = Math3D.DotProduct(ofs, plane.normal); + dist = plane.dist - dist; + } else { // special point case + dist = plane.dist; + } + + d1 = Math3D.DotProduct(p1, plane.normal) - dist; + d2 = Math3D.DotProduct(p2, plane.normal) - dist; + + if (d2 > 0) + getout = true; // endpoint is not in solid + if (d1 > 0) + startout = true; + + // if completely in front of face, no intersection + if (d1 > 0 && d2 >= d1) + return; + + if (d1 <= 0 && d2 <= 0) + continue; + + // crosses face + if (d1 > d2) { // enter + f = (d1 - DIST_EPSILON) / (d1 - d2); + if (f > enterfrac) { + enterfrac = f; + clipplane = plane; + leadside = side; + } + } else { // leave + f = (d1 + DIST_EPSILON) / (d1 - d2); + if (f < leavefrac) + leavefrac = f; + } + } + + if (!startout) { // original point was inside brush + trace.startsolid = true; + if (!getout) + trace.allsolid = true; + return; + } + if (enterfrac < leavefrac) { + if (enterfrac > -1 && enterfrac < trace.fraction) { + if (enterfrac < 0) + enterfrac = 0; + trace.fraction = enterfrac; + // copy + trace.plane.set(clipplane); + trace.surface = leadside.surface.c; + trace.contents = brush.contents; + } + } + } + + /* + * ================ CM_TestBoxInBrush ================ + */ + public static void CM_TestBoxInBrush(float[] mins, float[] maxs, + float[] p1, trace_t trace, cbrush_t brush) { + int i, j; + cplane_t plane; + float dist; + float[] ofs = { 0, 0, 0 }; + float d1; + cbrushside_t side; + + if (brush.numsides == 0) + return; + + for (i = 0; i < brush.numsides; i++) { + side = map_brushsides[brush.firstbrushside + i]; + plane = side.plane; + + // FIXME: special case for axial + // general box case + // push the plane out apropriately for mins/maxs + // FIXME: use signbits into 8 way lookup for each mins/maxs + + for (j = 0; j < 3; j++) { + if (plane.normal[j] < 0) + ofs[j] = maxs[j]; + else + ofs[j] = mins[j]; + } + dist = Math3D.DotProduct(ofs, plane.normal); + dist = plane.dist - dist; + + d1 = Math3D.DotProduct(p1, plane.normal) - dist; + + // if completely in front of face, no intersection + if (d1 > 0) + return; + + } + + // inside this brush + trace.startsolid = trace.allsolid = true; + trace.fraction = 0; + trace.contents = brush.contents; + } + + /* + * ================ CM_TraceToLeaf ================ + */ + public static void CM_TraceToLeaf(int leafnum) { + int k; + int brushnum; + cleaf_t leaf; + cbrush_t b; + + leaf = map_leafs[leafnum]; + if (0 == (leaf.contents & trace_contents)) + return; + + // trace line against all brushes in the leaf + for (k = 0; k < leaf.numleafbrushes; k++) { + + brushnum = map_leafbrushes[leaf.firstleafbrush + k]; + b = map_brushes[brushnum]; + if (b.checkcount == checkcount) + continue; // already checked this brush in another leaf + b.checkcount = checkcount; + + if (0 == (b.contents & trace_contents)) + continue; + CM_ClipBoxToBrush(trace_mins, trace_maxs, trace_start, trace_end, + trace_trace, b); + if (0 == trace_trace.fraction) + return; + } + + } + + /* + * ================ CM_TestInLeaf ================ + */ + public static void CM_TestInLeaf(int leafnum) { + int k; + int brushnum; + cleaf_t leaf; + cbrush_t b; + + leaf = map_leafs[leafnum]; + if (0 == (leaf.contents & trace_contents)) + return; + // trace line against all brushes in the leaf + for (k = 0; k < leaf.numleafbrushes; k++) { + brushnum = map_leafbrushes[leaf.firstleafbrush + k]; + b = map_brushes[brushnum]; + if (b.checkcount == checkcount) + continue; // already checked this brush in another leaf + b.checkcount = checkcount; + + if (0 == (b.contents & trace_contents)) + continue; + CM_TestBoxInBrush(trace_mins, trace_maxs, trace_start, trace_trace, + b); + if (0 == trace_trace.fraction) + return; + } + + } + + /* + * ================== CM_RecursiveHullCheck ================== + */ + public static void CM_RecursiveHullCheck(int num, float p1f, float p2f, + float[] p1, float[] p2) { + cnode_t node; + cplane_t plane; + float t1, t2, offset; + float frac, frac2; + float idist; + int i; + float[] mid = { 0, 0, 0 }; + int side; + float midf; + + if (trace_trace.fraction <= p1f) + return; // already hit something nearer + + // if < 0, we are in a leaf node + if (num < 0) { + CM_TraceToLeaf(-1 - num); + return; + } + + // + // find the point distances to the seperating plane + // and the offset for the size of the box + // + node = map_nodes[num]; + plane = node.plane; + + if (plane.type < 3) { + t1 = p1[plane.type] - plane.dist; + t2 = p2[plane.type] - plane.dist; + offset = trace_extents[plane.type]; + } else { + t1 = Math3D.DotProduct(plane.normal, p1) - plane.dist; + t2 = Math3D.DotProduct(plane.normal, p2) - plane.dist; + if (trace_ispoint) + offset = 0; + else + offset = Math.abs(trace_extents[0] * plane.normal[0]) + + Math.abs(trace_extents[1] * plane.normal[1]) + + Math.abs(trace_extents[2] * plane.normal[2]); + } + + // see which sides we need to consider + if (t1 >= offset && t2 >= offset) { + CM_RecursiveHullCheck(node.children[0], p1f, p2f, p1, p2); + return; + } + if (t1 < -offset && t2 < -offset) { + CM_RecursiveHullCheck(node.children[1], p1f, p2f, p1, p2); + return; + } + + // put the crosspoint DIST_EPSILON pixels on the near side + if (t1 < t2) { + idist = 1.0f / (t1 - t2); + side = 1; + frac2 = (t1 + offset + DIST_EPSILON) * idist; + frac = (t1 - offset + DIST_EPSILON) * idist; + } else if (t1 > t2) { + idist = 1.0f / (t1 - t2); + side = 0; + frac2 = (t1 - offset - DIST_EPSILON) * idist; + frac = (t1 + offset + DIST_EPSILON) * idist; + } else { + side = 0; + frac = 1; + frac2 = 0; + } + + // move up to the node + if (frac < 0) + frac = 0; + if (frac > 1) + frac = 1; + + midf = p1f + (p2f - p1f) * frac; + for (i = 0; i < 3; i++) + mid[i] = p1[i] + frac * (p2[i] - p1[i]); + + CM_RecursiveHullCheck(node.children[side], p1f, midf, p1, mid); + + // go past the node + if (frac2 < 0) + frac2 = 0; + if (frac2 > 1) + frac2 = 1; + + midf = p1f + (p2f - p1f) * frac2; + for (i = 0; i < 3; i++) + mid[i] = p1[i] + frac2 * (p2[i] - p1[i]); + + CM_RecursiveHullCheck(node.children[side ^ 1], midf, p2f, mid, p2); + } + + //====================================================================== + + /* + * ================== CM_BoxTrace ================== + */ + public static trace_t BoxTrace(float[] start, float[] end, float[] mins, + float[] maxs, int headnode, int brushmask) { + + // for multi-check avoidance + checkcount++; + + // for statistics, may be zeroed + Globals.c_traces++; + + // fill in a default trace + //was: memset(& trace_trace, 0, sizeof(trace_trace)); + trace_trace = new trace_t(); + + trace_trace.fraction = 1; + trace_trace.surface = nullsurface.c; + + if (numnodes == 0) // map not loaded + { + Com.DPrintf("dummy trace zurueck, da map not loaded!\n"); + return trace_trace; + } + + trace_contents = brushmask; + Math3D.VectorCopy(start, trace_start); + Math3D.VectorCopy(end, trace_end); + Math3D.VectorCopy(mins, trace_mins); + Math3D.VectorCopy(maxs, trace_maxs); + + // + // check for position test special case + // + if (start[0] == end[0] && start[1] == end[1] && start[2] == end[2]) { + + int leafs[] = new int[1024]; + int i, numleafs; + float[] c1 = { 0, 0, 0 }, c2 = { 0, 0, 0 }; + int topnode = 0; + + Math3D.VectorAdd(start, mins, c1); + Math3D.VectorAdd(start, maxs, c2); + + for (i = 0; i < 3; i++) { + c1[i] -= 1; + c2[i] += 1; + } + + int tn[] = { topnode }; + + numleafs = CM_BoxLeafnums_headnode(c1, c2, leafs, 1024, headnode, + tn); + topnode = tn[0]; + for (i = 0; i < numleafs; i++) { + CM_TestInLeaf(leafs[i]); + if (trace_trace.allsolid) + break; + } + Math3D.VectorCopy(start, trace_trace.endpos); + return trace_trace; + } + + // + // check for point special case + // + if (mins[0] == 0 && mins[1] == 0 && mins[2] == 0 && maxs[0] == 0 + && maxs[1] == 0 && maxs[2] == 0) { + trace_ispoint = true; + Math3D.VectorClear(trace_extents); + } else { + trace_ispoint = false; + trace_extents[0] = -mins[0] > maxs[0] ? -mins[0] : maxs[0]; + trace_extents[1] = -mins[1] > maxs[1] ? -mins[1] : maxs[1]; + trace_extents[2] = -mins[2] > maxs[2] ? -mins[2] : maxs[2]; + } + + // + // general sweeping through world + // + CM_RecursiveHullCheck(headnode, 0, 1, start, end); + + if (trace_trace.fraction == 1) { + Math3D.VectorCopy(end, trace_trace.endpos); + } else { + for (int i = 0; i < 3; i++) + trace_trace.endpos[i] = start[i] + trace_trace.fraction + * (end[i] - start[i]); + } + return trace_trace; + } + + /* + * ================== CM_TransformedBoxTrace + * + * Handles offseting and rotation of the end points for moving and rotating + * entities ================== + */ + public static trace_t TransformedBoxTrace(float[] start, float[] end, + float[] mins, float[] maxs, int headnode, int brushmask, + float[] origin, float[] angles) { + trace_t trace; + float[] start_l = { 0, 0, 0 }, end_l = { 0, 0, 0 }; + float[] a = { 0, 0, 0 }; + float[] forward = { 0, 0, 0 }, right = { 0, 0, 0 }, up = { 0, 0, 0 }; + float[] temp = { 0, 0, 0 }; + boolean rotated; + + // subtract origin offset + Math3D.VectorSubtract(start, origin, start_l); + Math3D.VectorSubtract(end, origin, end_l); + + // rotate start and end into the models frame of reference + if (headnode != box_headnode + && (angles[0] != 0 || angles[1] != 0 || angles[2] != 0)) + rotated = true; + else + rotated = false; + + if (rotated) { + Math3D.AngleVectors(angles, forward, right, up); + + Math3D.VectorCopy(start_l, temp); + start_l[0] = Math3D.DotProduct(temp, forward); + start_l[1] = -Math3D.DotProduct(temp, right); + start_l[2] = Math3D.DotProduct(temp, up); + + Math3D.VectorCopy(end_l, temp); + end_l[0] = Math3D.DotProduct(temp, forward); + end_l[1] = -Math3D.DotProduct(temp, right); + end_l[2] = Math3D.DotProduct(temp, up); + } + + // sweep the box through the model + trace = BoxTrace(start_l, end_l, mins, maxs, headnode, brushmask); + + if (rotated && trace.fraction != 1.0) { + // FIXME: figure out how to do this with existing angles + Math3D.VectorNegate(angles, a); + Math3D.AngleVectors(a, forward, right, up); + + Math3D.VectorCopy(trace.plane.normal, temp); + trace.plane.normal[0] = Math3D.DotProduct(temp, forward); + trace.plane.normal[1] = -Math3D.DotProduct(temp, right); + trace.plane.normal[2] = Math3D.DotProduct(temp, up); + } + + trace.endpos[0] = start[0] + trace.fraction * (end[0] - start[0]); + trace.endpos[1] = start[1] + trace.fraction * (end[1] - start[1]); + trace.endpos[2] = start[2] + trace.fraction * (end[2] - start[2]); + + return trace; + } + + /* + * =============================================================================== + * PVS / PHS + * =============================================================================== + */ + + /* + * =================== CM_DecompressVis =================== + */ + public static void CM_DecompressVis(byte in[], int offset, byte out[]) { + int c; + + int row; + + row = (numclusters + 7) >> 3; + int outp = 0; + int inp = offset; + + if (in == null || numvisibility == 0) { // no vis info, so make all + // visible + while (row != 0) { + out[outp++] = (byte) 0xFF; + row--; + } + return; + } + + do { + if (in[inp] != 0) { + out[outp++] = in[inp++]; + continue; + } + + c = in[inp + 1] & 0xFF; + inp += 2; + if (outp + c > row) { + c = row - (outp); + Com.DPrintf("warning: Vis decompression overrun\n"); + } + while (c != 0) { + out[outp++] = 0; + c--; + } + } while (outp < row); + } + + public static byte pvsrow[] = new byte[Defines.MAX_MAP_LEAFS / 8]; + + public static byte phsrow[] = new byte[Defines.MAX_MAP_LEAFS / 8]; + + public static byte[] CM_ClusterPVS(int cluster) { + if (cluster == -1) + Arrays.fill(pvsrow, 0, (numclusters + 7) >> 3, (byte) 0); + else + CM_DecompressVis(map_visibility, + map_vis.bitofs[cluster][Defines.DVIS_PVS], pvsrow); + return pvsrow; + } + + public static byte[] CM_ClusterPHS(int cluster) { + if (cluster == -1) + Arrays.fill(phsrow, 0, (numclusters + 7) >> 3, (byte) 0); + else + CM_DecompressVis(map_visibility, + map_vis.bitofs[cluster][Defines.DVIS_PHS], phsrow); + return phsrow; + } + + /* + * =============================================================================== + * AREAPORTALS + * =============================================================================== + */ + + public static void FloodArea_r(carea_t area, int floodnum) { + //Com.Printf("FloodArea_r(" + floodnum + ")...\n"); + int i; + qfiles.dareaportal_t p; + + if (area.floodvalid == floodvalid) { + if (area.floodnum == floodnum) + return; + Com.Error(Defines.ERR_DROP, "FloodArea_r: reflooded"); + } + + area.floodnum = floodnum; + area.floodvalid = floodvalid; + + for (i = 0; i < area.numareaportals; i++) { + p = map_areaportals[area.firstareaportal + i]; + if (portalopen[p.portalnum]) + FloodArea_r(map_areas[p.otherarea], floodnum); + } + } + + /* + * ==================== FloodAreaConnections ==================== + */ + public static void FloodAreaConnections() { + Com.DPrintf("FloodAreaConnections...\n"); + + int i; + carea_t area; + int floodnum; + + // all current floods are now invalid + floodvalid++; + floodnum = 0; + + // area 0 is not used + for (i = 1; i < numareas; i++) { + + area = map_areas[i]; + + if (area.floodvalid == floodvalid) + continue; // already flooded into + floodnum++; + FloodArea_r(area, floodnum); + } + } + + /* + * ================= CM_SetAreaPortalState ================= + */ + public static void CM_SetAreaPortalState(int portalnum, boolean open) { + if (portalnum > numareaportals) + Com.Error(Defines.ERR_DROP, "areaportal > numareaportals"); + + portalopen[portalnum] = open; + FloodAreaConnections(); + } + + /* + * ================= CM_AreasConnected ================= + */ + + public static boolean CM_AreasConnected(int area1, int area2) { + if (map_noareas.value != 0) + return true; + + if (area1 > numareas || area2 > numareas) + Com.Error(Defines.ERR_DROP, "area > numareas"); + + if (map_areas[area1].floodnum == map_areas[area2].floodnum) + return true; + + return false; + } + + /* + * ================= CM_WriteAreaBits + * + * Writes a length byte followed by a bit vector of all the areas that area + * in the same flood as the area parameter + * + * This is used by the client refreshes to cull visibility ================= + */ + public static int CM_WriteAreaBits(byte buffer[], int area) { + int i; + int floodnum; + int bytes; + + bytes = (numareas + 7) >> 3; + + if (map_noareas.value != 0) { // for debugging, send everything + Arrays.fill(buffer, 0, bytes, (byte) 255); + } else { + Arrays.fill(buffer, 0, bytes, (byte) 0); + floodnum = map_areas[area].floodnum; + for (i = 0; i < numareas; i++) { + if (map_areas[i].floodnum == floodnum || area == 0) + buffer[i >> 3] |= 1 << (i & 7); + } + } + + return bytes; + } + + /* + * =================== CM_WritePortalState + * + * Writes the portal state to a savegame file =================== + */ + + public static void CM_WritePortalState(RandomAccessFile os) { + + //was: fwrite(portalopen, sizeof(portalopen), 1, f); + try { + + for (int n = 0; n < portalopen.length; n++) + if (portalopen[n]) + os.writeInt(1); + else + os.writeInt(0); + } catch (Exception e) { + Com.Printf("ERROR:" + e); + e.printStackTrace(); + } + } + + /* + * =================== CM_ReadPortalState + * + * Reads the portal state from a savegame file and recalculates the area + * connections =================== + */ + public static void CM_ReadPortalState(RandomAccessFile f) { + + //was: FS_Read(portalopen, sizeof(portalopen), f); + int len = portalopen.length * 4; + + byte buf[] = new byte[len]; + + FS.Read(buf, len, f); + + ByteBuffer bb = ByteBuffer.wrap(buf); + IntBuffer ib = bb.asIntBuffer(); + + for (int n = 0; n < portalopen.length; n++) + portalopen[n] = ib.get() != 0; + + FloodAreaConnections(); + } + + /* + * ============= CM_HeadnodeVisible + * + * Returns true if any leaf under headnode has a cluster that is potentially + * visible ============= + */ + public static boolean CM_HeadnodeVisible(int nodenum, byte visbits[]) { + int leafnum; + int cluster; + cnode_t node; + + if (nodenum < 0) { + leafnum = -1 - nodenum; + cluster = map_leafs[leafnum].cluster; + if (cluster == -1) + return false; + if (0 != (visbits[cluster >>> 3] & (1 << (cluster & 7)))) + return true; + return false; + } + + node = map_nodes[nodenum]; + if (CM_HeadnodeVisible(node.children[0], visbits)) + return true; + return CM_HeadnodeVisible(node.children[1], visbits); + } +}
\ No newline at end of file |