/// <summary> /// R_StoreEfrags /// FIXME: a lot of this goes away with edge-based /// </summary> static void StoreEfrags(efrag_t ef) { while (ef != null) { entity_t pent = ef.entity; model_t clmodel = pent.model; switch (clmodel.type) { case modtype_t.mod_alias: case modtype_t.mod_brush: case modtype_t.mod_sprite: if ((pent.visframe != _FrameCount) && (Client.NumVisEdicts < Client.MAX_VISEDICTS)) { Client.VisEdicts[Client.NumVisEdicts++] = pent; // mark that we've recorded this entity for this frame pent.visframe = _FrameCount; } ef = ef.leafnext; break; default: Sys.Error("R_StoreEfrags: Bad entity type {0}\n", clmodel.type); break; } } }
/// <summary> /// GL_SubdivideSurface /// Breaks a polygon up along axial 64 unit boundaries /// so that turbulent and sky warps can be done reasonably. /// </summary> public static void SubdivideSurface(msurface_t fa) { _WarpFace = fa; // // convert edges back to a normal polygon // int numverts = 0; Vector3[] verts = new Vector3[fa.numedges + 1]; // + 1 for wrap case model_t loadmodel = Mod.Model; for (int i = 0; i < fa.numedges; i++) { int lindex = loadmodel.surfedges[fa.firstedge + i]; if (lindex > 0) { verts[numverts] = loadmodel.vertexes[loadmodel.edges[lindex].v[0]].position; } else { verts[numverts] = loadmodel.vertexes[loadmodel.edges[-lindex].v[1]].position; } numverts++; } SubdividePolygon(numverts, verts); }
public void Clear() { this.entity = 0; this.model = null; this.endtime = 0; this.start = Vector3.Zero; this.end = Vector3.Zero; }
static void PrintFrameName(model_t m, int frame) { aliashdr_t hdr = Mod.GetExtraData(m); if (hdr == null) { return; } Con.Print("frame {0}: {1}\n", frame, hdr.frames[frame].name); }
static void DrawTextureChains() { if (_glTexSort.Value == 0) { DisableMultitexture(); if (_SkyChain != null) { DrawSkyChain(_SkyChain); _SkyChain = null; } return; } model_t world = Client.cl.worldmodel; for (int i = 0; i < world.numtextures; i++) { texture_t t = world.textures[i]; if (t == null) { continue; } msurface_t s = t.texturechain; if (s == null) { continue; } if (i == _SkyTextureNum) { DrawSkyChain(s); } else if (i == _MirrorTextureNum && _MirrorAlpha.Value != 1.0f) { MirrorChain(s); continue; } else { if ((s.flags & Surf.SURF_DRAWTURB) != 0 && _WaterAlpha.Value != 1.0f) { continue; // draw translucent water later } for (; s != null; s = s.texturechain) { RenderBrushPoly(s); } } t.texturechain = null; } }
/// <summary> /// SV_HullForEntity /// Returns a hull that can be used for testing or clipping an object of mins/maxs size. /// Offset is filled in to contain the adjustment that must be added to the /// testing object's origin to get a point to use with the returned hull. /// </summary> static hull_t HullForEntity(edict_t ent, ref Vector3 mins, ref Vector3 maxs, out Vector3 offset) { hull_t hull = null; // decide which clipping hull to use, based on the size if (ent.v.solid == Solids.SOLID_BSP) { // explicit hulls in the BSP model if (ent.v.movetype != Movetypes.MOVETYPE_PUSH) { Sys.Error("SOLID_BSP without MOVETYPE_PUSH"); } model_t model = sv.models[(int)ent.v.modelindex]; if (model == null || model.type != modtype_t.mod_brush) { Sys.Error("MOVETYPE_PUSH with a non bsp model"); } Vector3 size = maxs - mins; if (size.X < 3) { hull = model.hulls[0]; } else if (size.X <= 32) { hull = model.hulls[1]; } else { hull = model.hulls[2]; } // calculate an offset value to center the origin offset = hull.clip_mins - mins; offset += Common.ToVector(ref ent.v.origin); } else { // create a temp hull from bounding box sizes Vector3 hullmins = Common.ToVector(ref ent.v.mins) - maxs; Vector3 hullmaxs = Common.ToVector(ref ent.v.maxs) - mins; hull = HullForBox(ref hullmins, ref hullmaxs); offset = Common.ToVector(ref ent.v.origin); } return(hull); }
static object _LastObj; // see comments /// <summary> /// R_AddEfrags /// </summary> public static void AddEfrags(entity_t ent) { if (ent.model == null) return; _AddEnt = ent; _LastObj = ent; // lastlink = &ent->efrag; _EfragTopNode = null; model_t entmodel = ent.model; _EMins = ent.origin + entmodel.mins; _EMaxs = ent.origin + entmodel.maxs; SplitEntityOnNode(Client.cl.worldmodel.nodes[0]); ent.topnode = _EfragTopNode; }
/// <summary> /// R_MarkLeaves /// </summary> private static void MarkLeaves() { if (_OldViewLeaf == _ViewLeaf && _NoVis.Value == 0) { return; } if (_IsMirror) { return; } _VisFrameCount++; _OldViewLeaf = _ViewLeaf; byte[] vis; if (_NoVis.Value != 0) { vis = new byte[4096]; Common.FillArray <Byte>(vis, 0xff); // todo: add count parameter? //memset(solid, 0xff, (cl.worldmodel->numleafs + 7) >> 3); } else { vis = Mod.LeafPVS(_ViewLeaf, Client.cl.worldmodel); } model_t world = Client.cl.worldmodel; for (int i = 0; i < world.numleafs; i++) { if (vis[i >> 3] != 0 & (1 << (i & 7)) != 0) { mnodebase_t node = world.leafs[i + 1]; do { if (node.visframe == _VisFrameCount) { break; } node.visframe = _VisFrameCount; node = node.parent; } while (node != null); } } }
/// <summary> /// Host_Viewprev_f /// </summary> static void Viewprev_f() { edict_t e = FindViewthing(); if (e == null) { return; } model_t m = Client.cl.model_precache[(int)e.v.modelindex]; e.v.frame = e.v.frame - 1; if (e.v.frame < 0) { e.v.frame = 0; } PrintFrameName(m, (int)e.v.frame); }
/// <summary> /// Host_Viewnext_f /// </summary> static void Viewnext_f() { edict_t e = FindViewthing(); if (e == null) { return; } model_t m = Client.cl.model_precache[(int)e.v.modelindex]; e.v.frame = e.v.frame + 1; if (e.v.frame >= m.numframes) { e.v.frame = m.numframes - 1; } PrintFrameName(m, (int)e.v.frame); }
/// <summary> /// Host_Viewframe_f /// </summary> static void Viewframe_f() { edict_t e = FindViewthing(); if (e == null) { return; } model_t m = Client.cl.model_precache[(int)e.v.modelindex]; int f = Common.atoi(Cmd.Argv(1)); if (f >= m.numframes) { f = m.numframes - 1; } e.v.frame = f; }
// Host_Viewmodel_f static void Viewmodel_f() { edict_t e = FindViewthing(); if (e == null) { return; } model_t m = Mod.ForName(Cmd.Argv(1), false); if (m == null) { Con.Print("Can't load {0}\n", Cmd.Argv(1)); return; } e.v.frame = 0; Client.cl.model_precache[(int)e.v.modelindex] = m; }
/* * ================= * PF_setmodel * * setmodel(entity, model) * ================= */ static void PF_setmodel() { edict_t e = GetEdict(OFS.OFS_PARM0); int m_idx = GetInt(OFS.OFS_PARM1); string m = Progs.GetString(m_idx); // check to see if model was properly precached for (int i = 0; i < Server.sv.model_precache.Length; i++) { string check = Server.sv.model_precache[i]; if (check == null) { break; } if (check == m) { e.v.model = m_idx; // m - pr_strings; e.v.modelindex = i; model_t mod = Server.sv.models[(int)e.v.modelindex]; if (mod != null) { SetMinMaxSize(e, ref mod.mins, ref mod.maxs, true); } else { SetMinMaxSize(e, ref Common.ZeroVector, ref Common.ZeroVector, true); } return; } } Progs.RunError("no precache: {0}\n", m); }
/// <summary> /// CL_ParseBeam /// </summary> static void ParseBeam(model_t m) { int ent = Net.Reader.ReadShort(); Vector3 start = Net.Reader.ReadCoords(); Vector3 end = Net.Reader.ReadCoords(); // override any beam with the same entity for (int i = 0; i < MAX_BEAMS; i++) { beam_t b = _Beams[i]; if (b.entity == ent) { b.entity = ent; b.model = m; b.endtime = (float)(cl.time + 0.2); b.start = start; b.end = end; return; } } // find a free beam for (int i = 0; i < MAX_BEAMS; i++) { beam_t b = _Beams[i]; if (b.model == null || b.endtime < cl.time) { b.entity = ent; b.model = m; b.endtime = (float)(cl.time + 0.2); b.start = start; b.end = end; return; } } Con.Print("beam list overflow!\n"); }
public void Clear() { this.active = false; this.paused = false; this.loadgame = false; this.time = 0; this.lastcheck = 0; this.lastchecktime = 0; this.name = null; this.modelname = null; this.worldmodel = null; Array.Clear(this.model_precache, 0, this.model_precache.Length); Array.Clear(this.models, 0, this.models.Length); Array.Clear(this.sound_precache, 0, this.sound_precache.Length); Array.Clear(this.lightstyles, 0, this.lightstyles.Length); this.num_edicts = 0; this.max_edicts = 0; this.edicts = null; this.state = 0; this.datagram.Clear(); this.reliable_datagram.Clear(); this.signon.Clear(); }
/// <summary> /// R_DrawBrushModel /// </summary> private static void DrawBrushModel(entity_t e) { _CurrentEntity = e; Drawer.CurrentTexture = -1; model_t clmodel = e.model; bool rotated = false; Vector3 mins, maxs; if (e.angles.X != 0 || e.angles.Y != 0 || e.angles.Z != 0) { rotated = true; mins = e.origin; mins.X -= clmodel.radius; mins.Y -= clmodel.radius; mins.Z -= clmodel.radius; maxs = e.origin; maxs.X += clmodel.radius; maxs.Y += clmodel.radius; maxs.Z += clmodel.radius; } else { mins = e.origin + clmodel.mins; maxs = e.origin + clmodel.maxs; } if (CullBox(ref mins, ref maxs)) { return; } GL.Color3(1f, 1, 1); Array.Clear(_LightMapPolys, 0, _LightMapPolys.Length); _ModelOrg = _RefDef.vieworg - e.origin; if (rotated) { Vector3 temp = _ModelOrg; Vector3 forward, right, up; Mathlib.AngleVectors(ref e.angles, out forward, out right, out up); _ModelOrg.X = Vector3.Dot(temp, forward); _ModelOrg.Y = -Vector3.Dot(temp, right); _ModelOrg.Z = Vector3.Dot(temp, up); } // calculate dynamic lighting for bmodel if it's not an // instanced model if (clmodel.firstmodelsurface != 0 && _glFlashBlend.Value == 0) { for (int k = 0; k < Client.MAX_DLIGHTS; k++) { if ((Client.DLights[k].die < Client.cl.time) || (Client.DLights[k].radius == 0)) { continue; } MarkLights(Client.DLights[k], 1 << k, clmodel.nodes[clmodel.hulls[0].firstclipnode]); } } GL.PushMatrix(); e.angles.X = -e.angles.X; // stupid quake bug RotateForEntity(e); e.angles.X = -e.angles.X; // stupid quake bug int surfOffset = clmodel.firstmodelsurface; msurface_t[] psurf = clmodel.surfaces; //[clmodel.firstmodelsurface]; // // draw texture // for (int i = 0; i < clmodel.nummodelsurfaces; i++, surfOffset++) { // find which side of the node we are on mplane_t pplane = psurf[surfOffset].plane; float dot = Vector3.Dot(_ModelOrg, pplane.normal) - pplane.dist; // draw the polygon bool planeBack = (psurf[surfOffset].flags & Surf.SURF_PLANEBACK) != 0; if ((planeBack && (dot < -QDef.BACKFACE_EPSILON)) || (!planeBack && (dot > QDef.BACKFACE_EPSILON))) { if (_glTexSort.Value != 0) { RenderBrushPoly(psurf[surfOffset]); } else { DrawSequentialPoly(psurf[surfOffset]); } } } BlendLightmaps(); GL.PopMatrix(); }
public void Clear() { this.movemessages = 0; this.cmd.Clear(); Array.Clear(this.stats, 0, this.stats.Length); this.items = 0; Array.Clear(this.item_gettime, 0, this.item_gettime.Length); this.faceanimtime = 0; foreach (cshift_t cs in this.cshifts) { cs.Clear(); } foreach (cshift_t cs in this.prev_cshifts) { cs.Clear(); } this.mviewangles[0] = Vector3.Zero; this.mviewangles[1] = Vector3.Zero; this.viewangles = Vector3.Zero; this.mvelocity[0] = Vector3.Zero; this.mvelocity[1] = Vector3.Zero; this.velocity = Vector3.Zero; this.punchangle = Vector3.Zero; this.idealpitch = 0; this.pitchvel = 0; this.nodrift = false; this.driftmove = 0; this.laststop = 0; this.viewheight = 0; this.crouch = 0; this.paused = false; this.onground = false; this.inwater = false; this.intermission = 0; this.completed_time = 0; this.mtime[0] = 0; this.mtime[1] = 0; this.time = 0; this.oldtime = 0; this.last_received_message = 0; Array.Clear(this.model_precache, 0, this.model_precache.Length); Array.Clear(this.sound_precache, 0, this.sound_precache.Length); this.levelname = null; this.viewentity = 0; this.maxclients = 0; this.gametype = 0; this.worldmodel = null; this.free_efrags = null; this.num_entities = 0; this.num_statics = 0; this.viewent.Clear(); this.cdtrack = 0; this.looptrack = 0; this.scores = null; }
static byte[] _LightMaps = new byte[4 * MAX_LIGHTMAPS * BLOCK_WIDTH * BLOCK_HEIGHT]; // lightmaps /// <summary> /// GL_BuildLightmaps /// Builds the lightmap texture with all the surfaces from all brush models /// </summary> static void BuildLightMaps() { Array.Clear(_Allocated, 0, _Allocated.Length); //memset (allocated, 0, sizeof(allocated)); _FrameCount = 1; // no dlightcache if (_LightMapTextures == 0) { _LightMapTextures = Drawer.GenerateTextureNumberRange(MAX_LIGHTMAPS); } Drawer.LightMapFormat = PixelFormat.Luminance;// GL_LUMINANCE; // default differently on the Permedia if (Scr.IsPermedia) { Drawer.LightMapFormat = PixelFormat.Rgba; } if (Common.HasParam("-lm_1")) { Drawer.LightMapFormat = PixelFormat.Luminance; } if (Common.HasParam("-lm_a")) { Drawer.LightMapFormat = PixelFormat.Alpha; } //if (Common.HasParam("-lm_i")) // Drawer.LightMapFormat = PixelFormat.Intensity; //if (Common.HasParam("-lm_2")) // Drawer.LightMapFormat = PixelFormat.Rgba4; if (Common.HasParam("-lm_4")) { Drawer.LightMapFormat = PixelFormat.Rgba; } switch (Drawer.LightMapFormat) { case PixelFormat.Rgba: _LightMapBytes = 4; break; //case PixelFormat.Rgba4: //_LightMapBytes = 2; //break; case PixelFormat.Luminance: //case PixelFormat.Intensity: case PixelFormat.Alpha: _LightMapBytes = 1; break; } for (int j = 1; j < QDef.MAX_MODELS; j++) { model_t m = Client.cl.model_precache[j]; if (m == null) { break; } if (m.name != null && m.name.StartsWith("*")) { continue; } _CurrentVertBase = m.vertexes; _CurrentModel = m; for (int i = 0; i < m.numsurfaces; i++) { CreateSurfaceLightmap(m.surfaces[i]); if ((m.surfaces[i].flags & Surf.SURF_DRAWTURB) != 0) { continue; } if ((m.surfaces[i].flags & Surf.SURF_DRAWSKY) != 0) { continue; } BuildSurfaceDisplayList(m.surfaces[i]); } } if (_glTexSort.Value == 0) { Drawer.SelectTexture(MTexTarget.TEXTURE1_SGIS); } // // upload all lightmaps that were filled // GCHandle handle = GCHandle.Alloc(_LightMaps, GCHandleType.Pinned); try { IntPtr ptr = handle.AddrOfPinnedObject(); long lmAddr = ptr.ToInt64(); for (int i = 0; i < MAX_LIGHTMAPS; i++) { if (_Allocated[i, 0] == 0) { break; // no more used } _LightMapModified[i] = false; _LightMapRectChange[i].l = BLOCK_WIDTH; _LightMapRectChange[i].t = BLOCK_HEIGHT; _LightMapRectChange[i].w = 0; _LightMapRectChange[i].h = 0; Drawer.Bind(_LightMapTextures + i); Drawer.SetTextureFilters(TextureMinFilter.Linear, TextureMagFilter.Linear); long addr = lmAddr + i * BLOCK_WIDTH * BLOCK_HEIGHT * _LightMapBytes; GL.TexImage2D(TextureTarget.Texture2D, 0, (PixelInternalFormat)_LightMapBytes, BLOCK_WIDTH, BLOCK_HEIGHT, 0, Drawer.LightMapFormat, PixelType.UnsignedByte, new IntPtr(addr)); } } finally { handle.Free(); } if (_glTexSort.Value == 0) { Drawer.SelectTexture(MTexTarget.TEXTURE0_SGIS); } }
static int _StripCount; // stripcount /// <summary> /// GL_MakeAliasModelDisplayLists /// </summary> public static void MakeAliasModelDisplayLists(model_t m, aliashdr_t hdr) { _AliasModel = m; _AliasHdr = hdr; // // look for a cached version // string path = Path.ChangeExtension("glquake/" + Path.GetFileNameWithoutExtension(m.name), ".ms2"); DisposableWrapper <BinaryReader> file; Common.FOpenFile(path, out file); if (file != null) { using (file) { BinaryReader reader = file.Object; _NumCommands = reader.ReadInt32(); _NumOrder = reader.ReadInt32(); for (int i = 0; i < _NumCommands; i++) { _Commands[i] = reader.ReadInt32(); } for (int i = 0; i < _NumOrder; i++) { _VertexOrder[i] = reader.ReadInt32(); } } } else { // // build it from scratch // Con.Print("meshing {0}...\n", m.name); BuildTris(); // trifans or lists // // save out the cached version // string fullpath = Path.Combine(Common.GameDir, path); Stream fs = Sys.FileOpenWrite(fullpath, true); if (fs != null) { using (BinaryWriter writer = new BinaryWriter(fs, Encoding.ASCII)) { writer.Write(_NumCommands); writer.Write(_NumOrder); for (int i = 0; i < _NumCommands; i++) { writer.Write(_Commands[i]); } for (int i = 0; i < _NumOrder; i++) { writer.Write(_VertexOrder[i]); } } } } // // save the data out // _AliasHdr.poseverts = _NumOrder; int[] cmds = new int[_NumCommands]; //Hunk_Alloc (numcommands * 4); _AliasHdr.commands = cmds; // in bytes??? // (byte*)cmds - (byte*)paliashdr; Buffer.BlockCopy(_Commands, 0, cmds, 0, _NumCommands * 4); //memcpy (cmds, commands, numcommands * 4); trivertx_t[][] poseverts = Mod.PoseVerts; trivertx_t[] verts = new trivertx_t[_AliasHdr.numposes * _AliasHdr.poseverts]; // Hunk_Alloc (paliashdr->numposes * paliashdr->poseverts * sizeof(trivertx_t) ); _AliasHdr.posedata = verts; // (byte*)verts - (byte*)paliashdr; int offset = 0; for (int i = 0; i < _AliasHdr.numposes; i++) { for (int j = 0; j < _NumOrder; j++) { verts[offset++] = poseverts[i][_VertexOrder[j]]; // *verts++ = poseverts[i][vertexorder[j]]; } } }
/// <summary> /// CL_ParseUpdate /// /// Parse an entity update message from the server /// If an entities model or origin changes from frame to frame, it must be /// relinked. Other attributes can change without relinking. /// </summary> static void ParseUpdate(int bits) { int i; if (cls.signon == SIGNONS - 1) { // first update is the final signon stage cls.signon = SIGNONS; SignonReply(); } if ((bits & Protocol.U_MOREBITS) != 0) { i = Net.Reader.ReadByte(); bits |= (i << 8); } int num; if ((bits & Protocol.U_LONGENTITY) != 0) { num = Net.Reader.ReadShort(); } else { num = Net.Reader.ReadByte(); } entity_t ent = EntityNum(num); for (i = 0; i < 16; i++) { if ((bits & (1 << i)) != 0) { _BitCounts[i]++; } } bool forcelink = false; if (ent.msgtime != cl.mtime[1]) { forcelink = true; // no previous frame to lerp from } ent.msgtime = cl.mtime[0]; int modnum; if ((bits & Protocol.U_MODEL) != 0) { modnum = Net.Reader.ReadByte(); if (modnum >= QDef.MAX_MODELS) { Host.Error("CL_ParseModel: bad modnum"); } } else { modnum = ent.baseline.modelindex; } model_t model = cl.model_precache[modnum]; if (model != ent.model) { ent.model = model; // automatic animation (torches, etc) can be either all together // or randomized if (model != null) { if (model.synctype == synctype_t.ST_RAND) { ent.syncbase = (float)(Sys.Random() & 0x7fff) / 0x7fff; } else { ent.syncbase = 0; } if (model.numframes < ent.Pose1) { ent.Pose1 = 0; ent.Pose2 = 0; } } else { forcelink = true; // hack to make null model players work ent.Pose1 = 0; } if (num > 0 && num <= cl.maxclients) { Render.TranslatePlayerSkin(num - 1); } } if ((bits & Protocol.U_FRAME) != 0) { ent.frame = Net.Reader.ReadByte(); } else { ent.frame = ent.baseline.frame; } if ((bits & Protocol.U_COLORMAP) != 0) { i = Net.Reader.ReadByte(); } else { i = ent.baseline.colormap; } if (i == 0) { ent.colormap = Scr.vid.colormap; } else { if (i > cl.maxclients) { Sys.Error("i >= cl.maxclients"); } ent.colormap = cl.scores[i - 1].translations; } int skin; if ((bits & Protocol.U_SKIN) != 0) { skin = Net.Reader.ReadByte(); } else { skin = ent.baseline.skin; } if (skin != ent.skinnum) { ent.skinnum = skin; if (num > 0 && num <= cl.maxclients) { Render.TranslatePlayerSkin(num - 1); } } if ((bits & Protocol.U_EFFECTS) != 0) { ent.effects = Net.Reader.ReadByte(); } else { ent.effects = ent.baseline.effects; } // shift the known values for interpolation ent.msg_origins[1] = ent.msg_origins[0]; ent.msg_angles[1] = ent.msg_angles[0]; if ((bits & Protocol.U_ORIGIN1) != 0) { ent.msg_origins[0].X = Net.Reader.ReadCoord(); } else { ent.msg_origins[0].X = ent.baseline.origin.x; } if ((bits & Protocol.U_ANGLE1) != 0) { ent.msg_angles[0].X = Net.Reader.ReadAngle(); } else { ent.msg_angles[0].X = ent.baseline.angles.x; } if ((bits & Protocol.U_ORIGIN2) != 0) { ent.msg_origins[0].Y = Net.Reader.ReadCoord(); } else { ent.msg_origins[0].Y = ent.baseline.origin.y; } if ((bits & Protocol.U_ANGLE2) != 0) { ent.msg_angles[0].Y = Net.Reader.ReadAngle(); } else { ent.msg_angles[0].Y = ent.baseline.angles.y; } if ((bits & Protocol.U_ORIGIN3) != 0) { ent.msg_origins[0].Z = Net.Reader.ReadCoord(); } else { ent.msg_origins[0].Z = ent.baseline.origin.z; } if ((bits & Protocol.U_ANGLE3) != 0) { ent.msg_angles[0].Z = Net.Reader.ReadAngle(); } else { ent.msg_angles[0].Z = ent.baseline.angles.z; } if ((bits & Protocol.U_NOLERP) != 0) { ent.forcelink = true; } if (forcelink) { // didn't have an update last message ent.msg_origins[1] = ent.msg_origins[0]; ent.origin = ent.msg_origins[0]; ent.msg_angles[1] = ent.msg_angles[0]; ent.angles = ent.msg_angles[0]; ent.forcelink = true; } }
public void CopyFrom(model_t src) { this.name = src.name; this.needload = src.needload; this.type = src.type; this.numframes = src.numframes; this.synctype = src.synctype; this.flags = src.flags; this.mins = src.mins; this.maxs = src.maxs; this.radius = src.radius; this.clipbox = src.clipbox; this.clipmins = src.clipmins; this.clipmaxs = src.clipmaxs; this.firstmodelsurface = src.firstmodelsurface; this.nummodelsurfaces = src.nummodelsurfaces; this.numsubmodels = src.numsubmodels; this.submodels = src.submodels; this.numplanes = src.numplanes; this.planes = src.planes; this.numleafs = src.numleafs; this.leafs = src.leafs; this.numvertexes = src.numvertexes; this.vertexes = src.vertexes; this.numedges = src.numedges; this.edges = src.edges; this.numnodes = src.numnodes; this.nodes = src.nodes; this.numtexinfo = src.numtexinfo; this.texinfo = src.texinfo; this.numsurfaces = src.numsurfaces; this.surfaces = src.surfaces; this.numsurfedges = src.numsurfedges; this.surfedges = src.surfedges; this.numclipnodes = src.numclipnodes; this.clipnodes = src.clipnodes; this.nummarksurfaces = src.nummarksurfaces; this.marksurfaces = src.marksurfaces; for (int i = 0; i < src.hulls.Length; i++) { this.hulls[i].CopyFrom(src.hulls[i]); } this.numtextures = src.numtextures; this.textures = src.textures; this.visdata = src.visdata; this.lightdata = src.lightdata; this.entities = src.entities; this.cache = src.cache; }