summaryrefslogtreecommitdiffstats
path: root/src/jake2/render/jogl/Model.java
diff options
context:
space:
mode:
authorHolger Zickner <[email protected]>2004-07-07 19:59:59 +0000
committerHolger Zickner <[email protected]>2004-07-07 19:59:59 +0000
commit6e23fc1074d1f0c2c2812f4c2e663f5a21a43c20 (patch)
tree46ecc6d0255c874ba4cd26dc3d0733f785019896 /src/jake2/render/jogl/Model.java
import of Jake2 version sunrisesunrise
Diffstat (limited to 'src/jake2/render/jogl/Model.java')
-rw-r--r--src/jake2/render/jogl/Model.java1278
1 files changed, 1278 insertions, 0 deletions
diff --git a/src/jake2/render/jogl/Model.java b/src/jake2/render/jogl/Model.java
new file mode 100644
index 0000000..8c2cfc8
--- /dev/null
+++ b/src/jake2/render/jogl/Model.java
@@ -0,0 +1,1278 @@
+/*
+ * Model.java
+ * Copyright (C) 2003
+ *
+ * $Id: Model.java,v 1.1 2004-07-07 19:59:42 hzi Exp $
+ */
+/*
+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.
+
+*/
+package jake2.render.jogl;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Arrays;
+import java.util.Vector;
+
+import jake2.Defines;
+import jake2.game.cplane_t;
+import jake2.game.cvar_t;
+import jake2.qcommon.lump_t;
+import jake2.qcommon.qfiles;
+import jake2.qcommon.texinfo_t;
+import jake2.render.medge_t;
+import jake2.render.mleaf_t;
+import jake2.render.mmodel_t;
+import jake2.render.mnode_t;
+import jake2.render.model_t;
+import jake2.render.msurface_t;
+import jake2.render.mtexinfo_t;
+import jake2.render.mvertex_t;
+import jake2.util.Math3D;
+import jake2.util.Vargs;
+
+/**
+ * Model
+ *
+ * @author cwei
+ */
+public abstract class Model extends Surf {
+
+ // models.c -- model loading and caching
+
+ model_t loadmodel;
+ int modfilelen;
+
+ byte[] mod_novis = new byte[Defines.MAX_MAP_LEAFS/8];
+
+ static final int MAX_MOD_KNOWN = 512;
+ model_t[] mod_known = new model_t[MAX_MOD_KNOWN];
+ int mod_numknown;
+
+ // the inline * models from the current map are kept seperate
+ model_t[] mod_inline = new model_t[MAX_MOD_KNOWN];
+
+ abstract void GL_SubdivideSurface(msurface_t surface); // Warp.java
+
+ /*
+ ===============
+ Mod_PointInLeaf
+ ===============
+ */
+ mleaf_t Mod_PointInLeaf(float[] p, model_t model)
+ {
+ mnode_t node;
+ float d;
+ cplane_t plane;
+
+ if (model == null || model.nodes == null)
+ ri.Sys_Error (Defines.ERR_DROP, "Mod_PointInLeaf: bad model");
+
+ node = model.nodes[0]; // root node
+ while (true)
+ {
+ if (node.contents != -1)
+ return (mleaf_t)node;
+
+ plane = node.plane;
+ d = Math3D.DotProduct(p, plane.normal) - plane.dist;
+ if (d > 0)
+ node = node.children[0];
+ else
+ node = node.children[1];
+ }
+ // never reached
+ }
+
+
+ byte[] decompressed = new byte[Defines.MAX_MAP_LEAFS / 8];
+ byte[] model_visibility = new byte[Defines.MAX_MAP_VISIBILITY];
+
+ /*
+ ===================
+ Mod_DecompressVis
+ ===================
+ */
+ byte[] Mod_DecompressVis(byte[] in, int offset, model_t model)
+ {
+ int c;
+ byte[] out;
+ int outp, inp;
+ int row;
+
+ row = (model.vis.numclusters+7)>>3;
+ out = decompressed;
+ outp = 0;
+ inp = offset;
+
+ if (in == null)
+ { // no vis info, so make all visible
+ while (row != 0)
+ {
+ out[outp++] = (byte)0xFF;
+ row--;
+ }
+ return decompressed;
+ }
+
+ do
+ {
+ if (in[inp] != 0)
+ {
+ out[outp++] = in[inp++];
+ continue;
+ }
+
+ c = in[inp + 1] & 0xFF;
+ inp += 2;
+ while (c != 0)
+ {
+ out[outp++] = 0;
+ c--;
+ }
+ } while (outp < row);
+
+ return decompressed;
+ }
+
+ /*
+ ==============
+ Mod_ClusterPVS
+ ==============
+ */
+ byte[] Mod_ClusterPVS(int cluster, model_t model)
+ {
+ if (cluster == -1 || model.vis == null)
+ return mod_novis;
+ //return Mod_DecompressVis( (byte *)model.vis + model.vis.bitofs[cluster][Defines.DVIS_PVS], model);
+ return Mod_DecompressVis(model_visibility, model.vis.bitofs[cluster][Defines.DVIS_PVS], model);
+ }
+
+
+// ===============================================================================
+
+ /*
+ ================
+ Mod_Modellist_f
+ ================
+ */
+ void Mod_Modellist_f()
+ {
+ int i;
+ model_t mod;
+ int total;
+
+ total = 0;
+ ri.Con_Printf(Defines.PRINT_ALL,"Loaded models:\n");
+ for (i=0; i < mod_numknown ; i++)
+ {
+ mod = mod_known[i];
+ if (mod.name == "")
+ continue;
+
+ ri.Con_Printf (Defines.PRINT_ALL, "%8i : %s\n", new Vargs(2).add(mod.extradatasize).add(mod.name));
+ total += mod.extradatasize;
+ }
+ ri.Con_Printf (Defines.PRINT_ALL, "Total resident: " + total +'\n');
+ }
+
+ /*
+ ===============
+ Mod_Init
+ ===============
+ */
+ void Mod_Init()
+ {
+ // init mod_known
+ for (int i=0; i < MAX_MOD_KNOWN; i++) {
+ mod_known[i] = new model_t();
+ }
+ Arrays.fill(mod_novis, (byte)0xff);
+ }
+
+ byte[] fileBuffer;
+
+ /*
+ ==================
+ Mod_ForName
+
+ Loads in a model for the given name
+ ==================
+ */
+ model_t Mod_ForName(String name, boolean crash)
+ {
+ model_t mod = null;
+ int i;
+
+ if (name == null || name.length() == 0)
+ ri.Sys_Error(Defines.ERR_DROP, "Mod_ForName: NULL name");
+
+ //
+ // inline models are grabbed only from worldmodel
+ //
+ if (name.charAt(0) == '*')
+ {
+ i = Integer.parseInt(name.substring(1));
+ if (i < 1 || r_worldmodel == null || i >= r_worldmodel.numsubmodels)
+ ri.Sys_Error (Defines.ERR_DROP, "bad inline model number");
+ return mod_inline[i];
+ }
+
+ //
+ // search the currently loaded models
+ //
+ for (i=0; i<mod_numknown ; i++)
+ {
+ mod = mod_known[i];
+
+ if (mod.name == "")
+ continue;
+ if (mod.name.equals(name) )
+ return mod;
+ }
+
+ //
+ // find a free model slot spot
+ //
+ for (i=0; i<mod_numknown ; i++)
+ {
+ mod = mod_known[i];
+
+ if (mod.name == "")
+ break; // free spot
+ }
+ if (i == mod_numknown)
+ {
+ if (mod_numknown == MAX_MOD_KNOWN)
+ ri.Sys_Error (Defines.ERR_DROP, "mod_numknown == MAX_MOD_KNOWN");
+ mod_numknown++;
+ mod = mod_known[i];
+ }
+
+ mod.name = name;
+
+ //
+ // load the file
+ //
+ fileBuffer = ri.FS_LoadFile(name);
+
+ if (fileBuffer == null)
+ {
+ if (crash)
+ ri.Sys_Error(Defines.ERR_DROP, "Mod_NumForName: " + mod.name + " not found");
+
+ mod.name = "";
+ return null;
+ }
+
+ modfilelen = fileBuffer.length;
+
+ loadmodel = mod;
+
+ //
+ // fill it in
+ //
+ ByteBuffer bb = ByteBuffer.wrap(fileBuffer);
+ bb.order(ByteOrder.LITTLE_ENDIAN);
+
+ // call the apropriate loader
+
+ bb.mark();
+ int ident = bb.getInt();
+
+ bb.reset();
+
+ switch (ident)
+ {
+ case qfiles.IDALIASHEADER:
+ Mod_LoadAliasModel(mod, bb);
+ break;
+ case qfiles.IDSPRITEHEADER:
+ Mod_LoadSpriteModel(mod, bb);
+ break;
+ case qfiles.IDBSPHEADER:
+ Mod_LoadBrushModel(mod, bb);
+ break;
+ default:
+ ri.Sys_Error(Defines.ERR_DROP,"Mod_NumForName: unknown fileid for " + mod.name);
+ break;
+ }
+
+ this.fileBuffer = null; // free it for garbage collection
+ return mod;
+ }
+
+ /*
+ ===============================================================================
+
+ BRUSHMODEL LOADING
+
+ ===============================================================================
+ */
+
+ byte[] mod_base;
+
+
+ /*
+ =================
+ Mod_LoadLighting
+ =================
+ */
+ void Mod_LoadLighting(lump_t l)
+ {
+ if (l.filelen == 0)
+ {
+ loadmodel.lightdata = null;
+ return;
+ }
+ // memcpy (loadmodel.lightdata, mod_base + l.fileofs, l.filelen);
+ loadmodel.lightdata = new byte[l.filelen];
+ System.arraycopy(mod_base, l.fileofs, loadmodel.lightdata, 0, l.filelen);
+ }
+
+
+ /*
+ =================
+ Mod_LoadVisibility
+ =================
+ */
+ void Mod_LoadVisibility(lump_t l)
+ {
+ int i;
+
+ if (l.filelen == 0)
+ {
+ loadmodel.vis = null;
+ return;
+ }
+
+ System.arraycopy(mod_base, l.fileofs, model_visibility, 0, l.filelen);
+
+ ByteBuffer bb = ByteBuffer.wrap(model_visibility, 0, l.filelen);
+
+ loadmodel.vis = new qfiles.dvis_t(bb.order(ByteOrder.LITTLE_ENDIAN));
+
+ /* done:
+ memcpy (loadmodel.vis, mod_base + l.fileofs, l.filelen);
+
+ loadmodel.vis.numclusters = LittleLong (loadmodel.vis.numclusters);
+ for (i=0 ; i<loadmodel.vis.numclusters ; i++)
+ {
+ loadmodel.vis.bitofs[i][0] = LittleLong (loadmodel.vis.bitofs[i][0]);
+ loadmodel.vis.bitofs[i][1] = LittleLong (loadmodel.vis.bitofs[i][1]);
+ }
+ */
+ }
+
+
+ /*
+ =================
+ Mod_LoadVertexes
+ =================
+ */
+ void Mod_LoadVertexes(lump_t l)
+ {
+ mvertex_t[] vertexes;
+ int i, count;
+
+ if ( (l.filelen % mvertex_t.DISK_SIZE) != 0)
+ ri.Sys_Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size in " + loadmodel.name);
+
+ count = l.filelen / mvertex_t.DISK_SIZE;
+
+ vertexes = new mvertex_t[count];
+
+ loadmodel.vertexes = vertexes;
+ loadmodel.numvertexes = count;
+
+ ByteBuffer bb = ByteBuffer.wrap(mod_base, l.fileofs, l.filelen);
+ bb.order(ByteOrder.LITTLE_ENDIAN);
+
+ for ( i=0 ; i<count ; i++)
+ {
+ vertexes[i] = new mvertex_t(bb);
+ }
+ }
+
+ /*
+ =================
+ RadiusFromBounds
+ =================
+ */
+ float RadiusFromBounds(float[] mins, float[] maxs)
+ {
+ float[] corner = {0, 0, 0};
+
+ for (int i=0 ; i<3 ; i++)
+ {
+ corner[i] = Math.abs(mins[i]) > Math.abs(maxs[i]) ? Math.abs(mins[i]) : Math.abs(maxs[i]);
+ }
+ return Math3D.VectorLength(corner);
+ }
+
+
+ /*
+ =================
+ Mod_LoadSubmodels
+ =================
+ */
+ void Mod_LoadSubmodels(lump_t l)
+ {
+ qfiles.dmodel_t in;
+ mmodel_t[] out;
+ int i, j, count;
+
+ if ((l.filelen % qfiles.dmodel_t.SIZE) != 0)
+ ri.Sys_Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size in " + loadmodel.name);
+
+ count = l.filelen / qfiles.dmodel_t.SIZE;
+ // out = Hunk_Alloc ( count*sizeof(*out));
+ out = new mmodel_t[count];
+
+ loadmodel.submodels = out;
+ loadmodel.numsubmodels = count;
+
+ ByteBuffer bb = ByteBuffer.wrap(mod_base, l.fileofs, l.filelen);
+ bb.order(ByteOrder.LITTLE_ENDIAN);
+
+ for ( i=0 ; i<count ; i++)
+ {
+ in = new qfiles.dmodel_t(bb);
+ out[i] = new mmodel_t();
+ for (j=0 ; j<3 ; j++)
+ { // spread the mins / maxs by a pixel
+ out[i].mins[j] = in.mins[j] - 1;
+ out[i].maxs[j] = in.maxs[j] + 1;
+ out[i].origin[j] = in.origin[j];
+ }
+ out[i].radius = RadiusFromBounds(out[i].mins, out[i].maxs);
+ out[i].headnode = in.headnode;
+ out[i].firstface = in.firstface;
+ out[i].numfaces = in.numfaces;
+ }
+ }
+
+ /*
+ =================
+ Mod_LoadEdges
+ =================
+ */
+ void Mod_LoadEdges (lump_t l)
+ {
+ medge_t[] edges;
+ int i, count;
+
+ if ( (l.filelen % medge_t.DISK_SIZE) != 0)
+ ri.Sys_Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size in " + loadmodel.name);
+
+ count = l.filelen / medge_t.DISK_SIZE;
+ // out = Hunk_Alloc ( (count + 1) * sizeof(*out));
+ edges = new medge_t[count + 1];
+
+ loadmodel.edges = edges;
+ loadmodel.numedges = count;
+
+ ByteBuffer bb = ByteBuffer.wrap(mod_base, l.fileofs, l.filelen);
+ bb.order(ByteOrder.LITTLE_ENDIAN);
+
+ for ( i=0 ; i<count ; i++)
+ {
+ edges[i] = new medge_t(bb);
+ }
+ }
+
+ /*
+ =================
+ Mod_LoadTexinfo
+ =================
+ */
+ void Mod_LoadTexinfo(lump_t l)
+ {
+ texinfo_t in;
+ mtexinfo_t[] out;
+ mtexinfo_t step;
+ int i, j, count;
+ int next;
+ String name;
+
+ if ((l.filelen % texinfo_t.SIZE) != 0)
+ ri.Sys_Error (Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size in " + loadmodel.name);
+
+ count = l.filelen / texinfo_t.SIZE;
+ // out = Hunk_Alloc ( count*sizeof(*out));
+ out = new mtexinfo_t[count];
+
+ loadmodel.texinfo = out;
+ loadmodel.numtexinfo = count;
+
+ ByteBuffer bb = ByteBuffer.wrap(mod_base, l.fileofs, l.filelen);
+ bb.order(ByteOrder.LITTLE_ENDIAN);
+
+ for ( i=0 ; i<count ; i++)
+ {
+ in = new texinfo_t(bb);
+ out[i] = new mtexinfo_t();
+ //for (j=0 ; j<8 ; j++)
+ out[i].vecs = in.vecs;
+
+ out[i].flags = in.flags;
+ next = in.nexttexinfo;
+ if (next > 0)
+ out[i].next = loadmodel.texinfo[next];
+ else
+ out[i].next = null;
+
+ name = "textures/" + in.texture + ".wal";
+
+ out[i].image = GL_FindImage(name, it_wall);
+ if (out[i].image == null)
+ {
+ ri.Con_Printf(Defines.PRINT_ALL, "Couldn't load " + name + '\n');
+ out[i].image = r_notexture;
+ }
+ }
+
+ // count animation frames
+ for (i=0 ; i<count ; i++)
+ {
+ // out = &loadmodel.texinfo[i];
+ out[i].numframes = 1;
+ for (step = out[i].next ; (step != null) && (step != out[i]) ; step=step.next)
+ out[i].numframes++;
+ }
+ }
+
+ /*
+ ================
+ CalcSurfaceExtents
+
+ Fills in s.texturemins[] and s.extents[]
+ ================
+ */
+ void CalcSurfaceExtents(msurface_t s)
+ {
+ float[] mins = {0, 0};
+ float[] maxs = {0, 0};
+ float val;
+
+ int i, j, e;
+ mvertex_t v;
+ mtexinfo_t tex;
+ int[] bmins = {0, 0};
+ int[] bmaxs = {0, 0};
+
+ mins[0] = mins[1] = 999999;
+ maxs[0] = maxs[1] = -99999;
+
+ tex = s.texinfo;
+
+ for (i=0 ; i<s.numedges ; i++)
+ {
+ e = loadmodel.surfedges[s.firstedge+i];
+ if (e >= 0)
+ v = loadmodel.vertexes[loadmodel.edges[e].v[0]];
+ else
+ v = loadmodel.vertexes[loadmodel.edges[-e].v[1]];
+
+ for (j=0 ; j<2 ; j++)
+ {
+ val = v.position[0] * tex.vecs[j][0] +
+ v.position[1] * tex.vecs[j][1] +
+ v.position[2] * tex.vecs[j][2] +
+ tex.vecs[j][3];
+ if (val < mins[j])
+ mins[j] = val;
+ if (val > maxs[j])
+ maxs[j] = val;
+ }
+ }
+
+ for (i=0 ; i<2 ; i++)
+ {
+ bmins[i] = (int)Math.floor(mins[i]/16);
+ bmaxs[i] = (int)Math.ceil(maxs[i]/16);
+
+ s.texturemins[i] = (short)(bmins[i] * 16);
+ s.extents[i] = (short)((bmaxs[i] - bmins[i]) * 16);
+
+ }
+ }
+
+ /*
+ =================
+ Mod_LoadFaces
+ =================
+ */
+ void Mod_LoadFaces (lump_t l)
+ {
+ qfiles.dface_t in;
+ msurface_t[] out;
+ int i, count, surfnum;
+ int planenum, side;
+ int ti;
+
+ if ((l.filelen % qfiles.dface_t.SIZE) != 0)
+ ri.Sys_Error (Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size in " + loadmodel.name);
+
+ count = l.filelen / qfiles.dface_t.SIZE;
+ // out = Hunk_Alloc ( count*sizeof(*out));
+ out = new msurface_t[count];
+
+ loadmodel.surfaces = out;
+ loadmodel.numsurfaces = count;
+
+ ByteBuffer bb = ByteBuffer.wrap(mod_base, l.fileofs, l.filelen);
+ bb.order(ByteOrder.LITTLE_ENDIAN);
+
+ currentmodel = loadmodel;
+
+ GL_BeginBuildingLightmaps(loadmodel);
+
+ for ( surfnum=0 ; surfnum<count ; surfnum++)
+ {
+ in = new qfiles.dface_t(bb);
+ out[surfnum] = new msurface_t();
+ out[surfnum].firstedge = in.firstedge;
+ out[surfnum].numedges = in.numedges;
+ out[surfnum].flags = 0;
+ out[surfnum].polys = null;
+
+ planenum = in.planenum;
+ side = in.side;
+ if (side != 0)
+ out[surfnum].flags |= Defines.SURF_PLANEBACK;
+
+ out[surfnum].plane = loadmodel.planes[planenum];
+
+ ti = in.texinfo;
+ if (ti < 0 || ti >= loadmodel.numtexinfo)
+ ri.Sys_Error(Defines.ERR_DROP, "MOD_LoadBmodel: bad texinfo number");
+
+ out[surfnum].texinfo = loadmodel.texinfo[ti];
+
+ CalcSurfaceExtents(out[surfnum]);
+
+ // lighting info
+
+ for (i=0 ; i<Defines.MAXLIGHTMAPS ; i++)
+ out[surfnum].styles[i] = in.styles[i];
+
+ i = in.lightofs;
+ if (i == -1)
+ out[surfnum].samples = null;
+ else {
+ ByteBuffer pointer = ByteBuffer.wrap(loadmodel.lightdata);
+ pointer.position(i);
+ pointer = pointer.slice();
+ pointer.mark();
+ out[surfnum].samples = pointer; // subarray
+ }
+
+ // set the drawing flags
+
+ if ((out[surfnum].texinfo.flags & Defines.SURF_WARP) != 0)
+ {
+ out[surfnum].flags |= Defines.SURF_DRAWTURB;
+ for (i=0 ; i<2 ; i++)
+ {
+ out[surfnum].extents[i] = 16384;
+ out[surfnum].texturemins[i] = -8192;
+ }
+ GL_SubdivideSurface(out[surfnum]); // cut up polygon for warps
+ }
+
+ // create lightmaps and polygons
+ if ((out[surfnum].texinfo.flags & (Defines.SURF_SKY | Defines.SURF_TRANS33 | Defines.SURF_TRANS66 | Defines.SURF_WARP)) == 0)
+ GL_CreateSurfaceLightmap(out[surfnum]);
+
+ if ((out[surfnum].texinfo.flags & Defines.SURF_WARP) == 0)
+ GL_BuildPolygonFromSurface(out[surfnum]);
+
+ }
+ GL_EndBuildingLightmaps ();
+ }
+
+
+ /*
+ =================
+ Mod_SetParent
+ =================
+ */
+ void Mod_SetParent(mnode_t node, mnode_t parent)
+ {
+ node.parent = parent;
+ if (node.contents != -1) return;
+ Mod_SetParent(node.children[0], node);
+ Mod_SetParent(node.children[1], node);
+ }
+
+ /*
+ =================
+ Mod_LoadNodes
+ =================
+ */
+ void Mod_LoadNodes(lump_t l)
+ {
+ int i, j, count, p;
+ qfiles.dnode_t in;
+ mnode_t[] out;
+
+ if ((l.filelen % qfiles.dnode_t.SIZE) != 0)
+ ri.Sys_Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size in " + loadmodel.name);
+
+ count = l.filelen / qfiles.dnode_t.SIZE;
+ // out = Hunk_Alloc ( count*sizeof(*out));
+ out = new mnode_t[count];
+
+ loadmodel.nodes = out;
+ loadmodel.numnodes = count;
+
+ ByteBuffer bb = ByteBuffer.wrap(mod_base, l.fileofs, l.filelen);
+ bb.order(ByteOrder.LITTLE_ENDIAN);
+
+ // initialize the tree array
+ for ( i=0 ; i<count ; i++) out[i] = new mnode_t(); // do first before linking
+
+ // fill and link the nodes
+ for ( i=0 ; i<count ; i++)
+ {
+ in = new qfiles.dnode_t(bb);
+ for (j=0 ; j<3 ; j++)
+ {
+ out[i].mins[j] = in.mins[j];
+ out[i].maxs[j] = in.maxs[j];
+ }
+
+ p = in.planenum;
+ out[i].plane = loadmodel.planes[p];
+
+ out[i].firstsurface = in.firstface;
+ out[i].numsurfaces = in.numfaces;
+ out[i].contents = -1; // differentiate from leafs
+
+ for (j=0 ; j<2 ; j++)
+ {
+ p = in.children[j];
+ if (p >= 0)
+ out[i].children[j] = loadmodel.nodes[p];
+ else
+ out[i].children[j] = loadmodel.leafs[-1 - p]; // mleaf_t extends mnode_t
+ }
+ }
+
+ Mod_SetParent(loadmodel.nodes[0], null); // sets nodes and leafs
+ }
+
+ /*
+ =================
+ Mod_LoadLeafs
+ =================
+ */
+ void Mod_LoadLeafs(lump_t l)
+ {
+ qfiles.dleaf_t in;
+ mleaf_t[] out;
+ int i, j, count, p;
+
+ if ((l.filelen % qfiles.dleaf_t.SIZE) != 0)
+ ri.Sys_Error (Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size in " + loadmodel.name);
+
+ count = l.filelen / qfiles.dleaf_t.SIZE;
+ // out = Hunk_Alloc ( count*sizeof(*out));
+ out = new mleaf_t[count];
+
+ loadmodel.leafs = out;
+ loadmodel.numleafs = count;
+
+ ByteBuffer bb = ByteBuffer.wrap(mod_base, l.fileofs, l.filelen);
+ bb.order(ByteOrder.LITTLE_ENDIAN);
+
+ for ( i=0 ; i<count ; i++)
+ {
+ in = new qfiles.dleaf_t(bb);
+ out[i] = new mleaf_t();
+ for (j=0 ; j<3 ; j++)
+ {
+ out[i].mins[j] = in.mins[j];
+ out[i].maxs[j] = in.maxs[j];
+
+ }
+
+ out[i].contents = in.contents;
+ out[i].cluster = in.cluster;
+ out[i].area = in.area;
+
+ out[i].setMarkSurface(in.firstleafface, loadmodel.marksurfaces);
+ out[i].nummarksurfaces = in.numleaffaces;
+ }
+ }
+
+
+ /*
+ =================
+ Mod_LoadMarksurfaces
+ =================
+ */
+ void Mod_LoadMarksurfaces(lump_t l)
+ {
+ int i, j, count;
+
+ msurface_t[] out;
+
+ if ((l.filelen % Defines.SIZE_OF_SHORT) != 0)
+ ri.Sys_Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size in " + loadmodel.name);
+ count = l.filelen / Defines.SIZE_OF_SHORT;
+ // out = Hunk_Alloc ( count*sizeof(*out));
+ out = new msurface_t[count];
+
+ loadmodel.marksurfaces = out;
+ loadmodel.nummarksurfaces = count;
+
+ ByteBuffer bb = ByteBuffer.wrap(mod_base, l.fileofs, l.filelen);
+ bb.order(ByteOrder.LITTLE_ENDIAN);
+
+ for ( i=0 ; i<count ; i++)
+ {
+ j = bb.getShort();
+ if (j < 0 || j >= loadmodel.numsurfaces)
+ ri.Sys_Error(Defines.ERR_DROP, "Mod_ParseMarksurfaces: bad surface number");
+
+ out[i] = loadmodel.surfaces[j];
+ }
+ }
+
+
+ /*
+ =================
+ Mod_LoadSurfedges
+ =================
+ */
+ void Mod_LoadSurfedges(lump_t l)
+ {
+ int i, count;
+ int[] offsets;
+
+ if ( (l.filelen % Defines.SIZE_OF_INT) != 0)
+ ri.Sys_Error (Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size in " + loadmodel.name);
+
+ count = l.filelen / Defines.SIZE_OF_INT;
+ if (count < 1 || count >= Defines.MAX_MAP_SURFEDGES)
+ ri.Sys_Error (Defines.ERR_DROP, "MOD_LoadBmodel: bad surfedges count in " + loadmodel.name + ": " + count);
+
+ offsets = new int[count];
+
+ loadmodel.surfedges = offsets;
+ loadmodel.numsurfedges = count;
+
+ ByteBuffer bb = ByteBuffer.wrap(mod_base, l.fileofs, l.filelen);
+ bb.order(ByteOrder.LITTLE_ENDIAN);
+
+ for ( i=0 ; i<count ; i++) offsets[i] = bb.getInt();
+ }
+
+
+ /*
+ =================
+ Mod_LoadPlanes
+ =================
+ */
+ void Mod_LoadPlanes(lump_t l)
+ {
+ int i, j;
+ cplane_t[] out;
+ qfiles.dplane_t in;
+ int count;
+ int bits;
+
+ if ((l.filelen % qfiles.dplane_t.SIZE) != 0)
+ ri.Sys_Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size in " + loadmodel.name);
+
+ count = l.filelen / qfiles.dplane_t.SIZE;
+ // out = Hunk_Alloc ( count*2*sizeof(*out));
+ out = new cplane_t[count * 2];
+
+ loadmodel.planes = out;
+ loadmodel.numplanes = count;
+
+ ByteBuffer bb = ByteBuffer.wrap(mod_base, l.fileofs, l.filelen);
+ bb.order(ByteOrder.LITTLE_ENDIAN);
+
+ for ( i=0 ; i<count ; i++)
+ {
+ bits = 0;
+ in = new qfiles.dplane_t(bb);
+ out[i] = new cplane_t();
+ for (j=0 ; j<3 ; j++)
+ {
+ out[i].normal[j] = in.normal[j];
+ if (out[i].normal[j] < 0)
+ bits |= (1<<j);
+ }
+
+ out[i].dist = in.dist;
+ out[i].type = (byte)in.type;
+ out[i].signbits = (byte)bits;
+ }
+ }
+
+ /*
+ =================
+ Mod_LoadBrushModel
+ =================
+ */
+ void Mod_LoadBrushModel(model_t mod, ByteBuffer buffer)
+ {
+ int i;
+ qfiles.dheader_t header;
+ mmodel_t bm;
+
+ loadmodel.type = mod_brush;
+ if (loadmodel != mod_known[0])
+ ri.Sys_Error(Defines.ERR_DROP, "Loaded a brush model after the world");
+
+ header = new qfiles.dheader_t(buffer);
+
+ i = header.version;
+ if (i != Defines.BSPVERSION)
+ ri.Sys_Error (Defines.ERR_DROP, "Mod_LoadBrushModel: " + mod.name + " has wrong version number (" + i + " should be " + Defines.BSPVERSION + ")");
+
+ mod_base = fileBuffer; //(byte *)header;
+
+ // load into heap
+ Mod_LoadVertexes(header.lumps[Defines.LUMP_VERTEXES]); // ok
+ Mod_LoadEdges(header.lumps[Defines.LUMP_EDGES]); // ok
+ Mod_LoadSurfedges(header.lumps[Defines.LUMP_SURFEDGES]); // ok
+ Mod_LoadLighting(header.lumps[Defines.LUMP_LIGHTING]); // ok
+ Mod_LoadPlanes(header.lumps[Defines.LUMP_PLANES]); // ok
+ Mod_LoadTexinfo(header.lumps[Defines.LUMP_TEXINFO]); // ok
+ Mod_LoadFaces(header.lumps[Defines.LUMP_FACES]); // ok
+ Mod_LoadMarksurfaces(header.lumps[Defines.LUMP_LEAFFACES]);
+ Mod_LoadVisibility(header.lumps[Defines.LUMP_VISIBILITY]); // ok
+ Mod_LoadLeafs(header.lumps[Defines.LUMP_LEAFS]); // ok
+ Mod_LoadNodes(header.lumps[Defines.LUMP_NODES]); // ok
+ Mod_LoadSubmodels(header.lumps[Defines.LUMP_MODELS]);
+ mod.numframes = 2; // regular and alternate animation
+
+ //
+ // set up the submodels
+ //
+ model_t starmod;
+
+ for (i=0 ; i<mod.numsubmodels ; i++)
+ {
+
+ bm = mod.submodels[i];
+ starmod = mod_inline[i] = loadmodel.copy();
+
+ starmod.firstmodelsurface = bm.firstface;
+ starmod.nummodelsurfaces = bm.numfaces;
+ starmod.firstnode = bm.headnode;
+ if (starmod.firstnode >= loadmodel.numnodes)
+ ri.Sys_Error(Defines.ERR_DROP, "Inline model " + i + " has bad firstnode");
+
+ Math3D.VectorCopy(bm.maxs, starmod.maxs);
+ Math3D.VectorCopy(bm.mins, starmod.mins);
+ starmod.radius = bm.radius;
+
+ if (i == 0)
+ loadmodel = starmod.copy();
+
+ starmod.numleafs = bm.visleafs;
+ }
+ }
+
+ /*
+ ==============================================================================
+
+ ALIAS MODELS
+
+ ==============================================================================
+ */
+
+ /*
+ =================
+ Mod_LoadAliasModel
+ =================
+ */
+ void Mod_LoadAliasModel (model_t mod, ByteBuffer buffer)
+ {
+ int i, j;
+ qfiles.dmdl_t pheader;
+ qfiles.dstvert_t[] poutst;
+ qfiles.dtriangle_t[] pouttri;
+ qfiles.daliasframe_t[] poutframe;
+ int[] poutcmd;
+
+ pheader = new qfiles.dmdl_t(buffer);
+
+ if (pheader.version != qfiles.ALIAS_VERSION)
+ ri.Sys_Error(Defines.ERR_DROP, "%s has wrong version number (%i should be %i)",
+ new Vargs(3).add(mod.name).add(pheader.version).add(qfiles.ALIAS_VERSION));
+
+ if (pheader.skinheight > MAX_LBM_HEIGHT)
+ ri.Sys_Error(Defines.ERR_DROP, "model "+ mod.name +" has a skin taller than " + MAX_LBM_HEIGHT);
+
+ if (pheader.num_xyz <= 0)
+ ri.Sys_Error(Defines.ERR_DROP, "model " + mod.name + " has no vertices");
+
+ if (pheader.num_xyz > qfiles.MAX_VERTS)
+ ri.Sys_Error(Defines.ERR_DROP, "model " + mod.name +" has too many vertices");
+
+ if (pheader.num_st <= 0)
+ ri.Sys_Error(Defines.ERR_DROP, "model " + mod.name + " has no st vertices");
+
+ if (pheader.num_tris <= 0)
+ ri.Sys_Error(Defines.ERR_DROP, "model " + mod.name + " has no triangles");
+
+ if (pheader.num_frames <= 0)
+ ri.Sys_Error(Defines.ERR_DROP, "model " + mod.name + " has no frames");
+
+ //
+ // load base s and t vertices (not used in gl version)
+ //
+ poutst = new qfiles.dstvert_t[pheader.num_st];
+ buffer.position(pheader.ofs_st);
+ for (i=0 ; i<pheader.num_st ; i++)
+ {
+ poutst[i] = new qfiles.dstvert_t(buffer);
+ }
+
+ //
+ // load triangle lists
+ //
+ pouttri = new qfiles.dtriangle_t[pheader.num_tris];
+ buffer.position(pheader.ofs_tris);
+ for (i=0 ; i<pheader.num_tris ; i++)
+ {
+ pouttri[i] = new qfiles.dtriangle_t(buffer);
+ }
+
+ //
+ // load the frames
+ //
+ poutframe = new qfiles.daliasframe_t[pheader.num_frames];
+ buffer.position(pheader.ofs_frames);
+ for (i=0 ; i<pheader.num_frames ; i++)
+ {
+ poutframe[i] = new qfiles.daliasframe_t(buffer);
+ // verts are all 8 bit, so no swapping needed
+ poutframe[i].verts = new qfiles.dtrivertx_t[pheader.num_xyz];
+ for (int k=0; k < pheader.num_xyz; k++) {
+ poutframe[i].verts[k] = new qfiles.dtrivertx_t(buffer);
+ }
+ }
+
+ mod.type = mod_alias;
+
+ //
+ // load the glcmds
+ //
+ poutcmd = new int[pheader.num_glcmds];
+ buffer.position(pheader.ofs_glcmds);
+ for (i=0 ; i<pheader.num_glcmds ; i++)
+ poutcmd[i] = buffer.getInt(); // LittleLong (pincmd[i]);
+
+ // register all skins
+ String[] skinNames = new String[pheader.num_skins];
+ byte[] nameBuf = new byte[qfiles.MAX_SKINNAME];
+ buffer.position(pheader.ofs_skins);
+ for (i=0 ; i<pheader.num_skins ; i++)
+ {
+ buffer.get(nameBuf);
+ skinNames[i] = new String(nameBuf).trim();
+ mod.skins[i] = GL_FindImage(skinNames[i], it_skin);
+ }
+
+ // set the model arrays
+ pheader.skinNames = skinNames; // skin names
+ pheader.stVerts = poutst; // textur koordinaten
+ pheader.triAngles = pouttri; // dreiecke
+ pheader.glCmds = poutcmd; // STRIP or FAN
+ pheader.aliasFrames = poutframe; // frames mit vertex array
+
+ mod.extradata = pheader;
+
+ mod.mins[0] = -32;
+ mod.mins[1] = -32;
+ mod.mins[2] = -32;
+ mod.maxs[0] = 32;
+ mod.maxs[1] = 32;
+ mod.maxs[2] = 32;
+ }
+
+ /*
+ ==============================================================================
+
+ SPRITE MODELS
+
+ ==============================================================================
+ */
+
+ /*
+ =================
+ Mod_LoadSpriteModel
+ =================
+ */
+ void Mod_LoadSpriteModel(model_t mod, ByteBuffer buffer)
+ {
+ qfiles.dsprite_t sprout = new qfiles.dsprite_t(buffer);
+
+ if (sprout.version != qfiles.SPRITE_VERSION)
+ ri.Sys_Error(Defines.ERR_DROP, "%s has wrong version number (%i should be %i)",
+ new Vargs(3).add(mod.name).add(sprout.version).add(qfiles.SPRITE_VERSION));
+
+ if (sprout.numframes > qfiles.MAX_MD2SKINS)
+ ri.Sys_Error(Defines.ERR_DROP, "%s has too many frames (%i > %i)",
+ new Vargs(3).add(mod.name).add(sprout.numframes).add(qfiles.MAX_MD2SKINS));
+
+ for (int i=0 ; i<sprout.numframes ; i++)
+ {
+ mod.skins[i] = GL_FindImage(sprout.frames[i].name, it_sprite);
+ }
+
+ mod.type = mod_sprite;
+ mod.extradata = sprout;
+ }
+
+// =============================================================================
+
+ /*
+ @@@@@@@@@@@@@@@@@@@@@
+ R_BeginRegistration
+
+ Specifies the model that will be used as the world
+ @@@@@@@@@@@@@@@@@@@@@
+ */
+ protected void R_BeginRegistration(String model)
+ {
+ cvar_t flushmap;
+
+ registration_sequence++;
+ r_oldviewcluster = -1; // force markleafs
+
+ String fullname = "maps/" + model + ".bsp";
+
+ // explicitly free the old map if different
+ // this guarantees that mod_known[0] is the world map
+ flushmap = ri.Cvar_Get("flushmap", "0", 0);
+ if ( !mod_known[0].name.equals(fullname) || flushmap.value != 0.0f)
+ Mod_Free(mod_known[0]);
+ r_worldmodel = Mod_ForName(fullname, true);
+
+ r_viewcluster = -1;
+ }
+
+
+ /*
+ @@@@@@@@@@@@@@@@@@@@@
+ R_RegisterModel
+
+ @@@@@@@@@@@@@@@@@@@@@
+ */
+ protected model_t R_RegisterModel(String name)
+ {
+ model_t mod = null;
+ int i;
+ qfiles.dsprite_t sprout;
+ qfiles.dmdl_t pheader;
+
+ mod = Mod_ForName(name, false);
+ if (mod != null)
+ {
+ mod.registration_sequence = registration_sequence;
+
+ // register any images used by the models
+ if (mod.type == mod_sprite)
+ {
+ sprout = (qfiles.dsprite_t)mod.extradata;
+ for (i=0 ; i<sprout.numframes ; i++)
+ mod.skins[i] = GL_FindImage(sprout.frames[i].name, it_sprite);
+ }
+ else if (mod.type == mod_alias)
+ {
+ pheader = (qfiles.dmdl_t)mod.extradata;
+ for (i=0 ; i<pheader.num_skins ; i++)
+ mod.skins[i] = GL_FindImage(pheader.skinNames[i], it_skin);
+ // PGM
+ mod.numframes = pheader.num_frames;
+ // PGM
+ }
+ else if (mod.type == mod_brush)
+ {
+ for (i=0 ; i<mod.numtexinfo ; i++)
+ mod.texinfo[i].image.registration_sequence = registration_sequence;
+ }
+ }
+ return mod;
+ }
+
+
+ /*
+ @@@@@@@@@@@@@@@@@@@@@
+ R_EndRegistration
+
+ @@@@@@@@@@@@@@@@@@@@@
+ */
+ protected void R_EndRegistration()
+ {
+ model_t mod;
+
+ for (int i=0; i<mod_numknown ; i++)
+ {
+ mod = mod_known[i];
+ if (mod.name == "")
+ continue;
+ if (mod.registration_sequence != registration_sequence)
+ { // don't need this model
+ Mod_Free(mod);
+ }
+ }
+ GL_FreeUnusedImages();
+ }
+
+
+// =============================================================================
+
+
+ /*
+ ================
+ Mod_Free
+ ================
+ */
+ void Mod_Free (model_t mod)
+ {
+ mod.clear();
+ }
+
+ /*
+ ================
+ Mod_FreeAll
+ ================
+ */
+ void Mod_FreeAll()
+ {
+ for (int i=0 ; i<mod_numknown ; i++)
+ {
+ if (mod_known[i].extradata != null)
+ Mod_Free(mod_known[i]);
+ }
+ }
+
+
+}