public virtual 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); }
/* * ============================================================================= * * DYNAMIC LIGHTS * * ============================================================================= */ /* * ============= R_MarkLights ============= */ protected void R_MarkLights(dlight_t light, int bit, mnode_t node) { cplane_t splitplane; float dist; msurface_t surf; int i; int sidebit; if (node.contents != -1) { return; } splitplane = node.plane; dist = Math3D.DotProduct(light.origin, splitplane.normal) - splitplane.dist; if (dist > light.intensity - OpenGLRenderApi.DLIGHT_CUTOFF) { this.R_MarkLights(light, bit, node.children[0]); return; } if (dist < -light.intensity + OpenGLRenderApi.DLIGHT_CUTOFF) { this.R_MarkLights(light, bit, node.children[1]); return; } // mark the polygons for (i = 0; i < node.numsurfaces; i++) { surf = this.r_worldmodel.surfaces[node.firstsurface + i]; dist = Math3D.DotProduct(light.origin, surf.plane.normal) - surf.plane.dist; sidebit = dist >= 0 ? 0 : Defines.SURF_PLANEBACK; if ((surf.flags & Defines.SURF_PLANEBACK) != sidebit) { continue; } if (surf.dlightframe != this.r_dlightframecount) { surf.dlightbits = 0; surf.dlightframe = this.r_dlightframecount; } surf.dlightbits |= bit; } this.R_MarkLights(light, bit, node.children[0]); this.R_MarkLights(light, bit, node.children[1]); }
public virtual void Mod_LoadNodes(lump_t l) { Int32 i, j, count, p; qfiles.dnode_t in_renamed; mnode_t[] out_renamed; if ((l.filelen % qfiles.dnode_t.SIZE) != 0) { Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size in " + loadmodel.name); } count = l.filelen / qfiles.dnode_t.SIZE; out_renamed = new mnode_t[count]; loadmodel.nodes = out_renamed; loadmodel.numnodes = count; ByteBuffer bb = ByteBuffer.Wrap(mod_base, l.fileofs, l.filelen); bb.Order = ByteOrder.LittleEndian; for (i = 0; i < count; i++) { out_renamed[i] = new mnode_t(); } for (i = 0; i < count; i++) { in_renamed = new dnode_t(bb); for (j = 0; j < 3; j++) { out_renamed[i].mins[j] = in_renamed.mins[j]; out_renamed[i].maxs[j] = in_renamed.maxs[j]; } p = in_renamed.planenum; out_renamed[i].plane = loadmodel.planes[p]; out_renamed[i].firstsurface = in_renamed.firstface; out_renamed[i].numsurfaces = in_renamed.numfaces; out_renamed[i].contents = -1; for (j = 0; j < 2; j++) { p = in_renamed.children[j]; if (p >= 0) { out_renamed[i].children[j] = loadmodel.nodes[p]; } else { out_renamed[i].children[j] = loadmodel.leafs[-1 - p]; } } } Mod_SetParent(loadmodel.nodes[0], null); }
public override void R_MarkLights(dlight_t light, Int32 bit, mnode_t node) { cplane_t splitplane; Single dist; msurface_t surf; Int32 i; Int32 sidebit; if (node.contents != -1) { return; } splitplane = node.plane; dist = Math3D.DotProduct(light.origin, splitplane.normal) - splitplane.dist; if (dist > light.intensity - DLIGHT_CUTOFF) { R_MarkLights(light, bit, node.children[0]); return; } if (dist < -light.intensity + DLIGHT_CUTOFF) { R_MarkLights(light, bit, node.children[1]); return; } for (i = 0; i < node.numsurfaces; i++) { surf = r_worldmodel.surfaces[node.firstsurface + i]; dist = Math3D.DotProduct(light.origin, surf.plane.normal) - surf.plane.dist; sidebit = (dist >= 0) ? 0 : Defines.SURF_PLANEBACK; if ((surf.flags & Defines.SURF_PLANEBACK) != sidebit) { continue; } if (surf.dlightframe != r_dlightframecount) { surf.dlightbits = 0; surf.dlightframe = r_dlightframecount; } surf.dlightbits |= bit; } R_MarkLights(light, bit, node.children[0]); R_MarkLights(light, bit, node.children[1]); }
public static void R_AddEfrags(entity_t ent) { if (ent.model == null) { return; } r_addent = ent; _LastObj = ent; // lastlink = &ent->efrag; r_pefragtopnode = null; model_t entmodel = ent.model; r_emins = ent.origin + entmodel.mins; r_emaxs = ent.origin + entmodel.maxs; R_SplitEntityOnNode(cl.worldmodel.nodes[0]); ent.topnode = r_pefragtopnode; }
public static void SV_FindTouchedLeafs(edict_t ent, mnodebase_t node) { if (node.contents == q_shared.CONTENTS_SOLID) { return; } // add an efrag if the node is a leaf if (node.contents < 0) { if (ent.num_leafs == q_shared.MAX_ENT_LEAFS) { return; } mleaf_t leaf = (mleaf_t)node; int leafnum = Array.IndexOf(sv.worldmodel.leafs, leaf) - 1; ent.leafnums[ent.num_leafs] = (short)leafnum; ent.num_leafs++; return; } // NODE_MIXED mnode_t n = (mnode_t)node; mplane_t splitplane = n.plane; int sides = Mathlib.BoxOnPlaneSide(ref ent.v.absmin, ref ent.v.absmax, splitplane); // recurse down the contacted sides if ((sides & 1) != 0) { SV_FindTouchedLeafs(ent, n.children[0]); } if ((sides & 2) != 0) { SV_FindTouchedLeafs(ent, n.children[1]); } }
public static void R_MarkLights(dlight_t light, int bit, mnodebase_t node) { if (node.contents < 0) { return; } mnode_t n = (mnode_t)node; mplane_t splitplane = n.plane; float dist = Vector3.Dot(light.origin, splitplane.normal) - splitplane.dist; if (dist > light.radius) { R_MarkLights(light, bit, n.children[0]); return; } if (dist < -light.radius) { R_MarkLights(light, bit, n.children[1]); return; } // mark the polygons for (int i = 0; i < n.numsurfaces; i++) { msurface_t surf = cl.worldmodel.surfaces[n.firstsurface + i]; if (surf.dlightframe != r_dlightframecount) { surf.dlightbits = 0; surf.dlightframe = r_dlightframecount; } surf.dlightbits |= bit; } R_MarkLights(light, bit, n.children[0]); R_MarkLights(light, bit, n.children[1]); }
public static void SV_AddToFatPVS(ref Vector3 org, mnodebase_t node) { while (true) { // if this is a leaf, accumulate the pvs bits if (node.contents < 0) { if (node.contents != q_shared.CONTENTS_SOLID) { byte[] pvs = Mod_LeafPVS((mleaf_t)node, sv.worldmodel); for (int i = 0; i < fatbytes; i++) { fatpvs[i] |= pvs[i]; } } return; } mnode_t n = (mnode_t)node; mplane_t plane = n.plane; float d = Vector3.Dot(org, plane.normal) - plane.dist; if (d > 8) { node = n.children[0]; } else if (d < -8) { node = n.children[1]; } else { // go down both SV_AddToFatPVS(ref org, n.children[0]); node = n.children[1]; } } }
protected float[] lightspot = { 0, 0, 0 }; // vec3_t private int RecursiveLightPoint(mnode_t node, float[] start, float[] end) { if (node.contents != -1) { return(-1); // didn't hit anything } msurface_t surf; int s, t, ds, dt; int i; mtexinfo_t tex; int maps; float[] mid = { 0, 0, 0 }; // calculate mid point // FIXME: optimize for axial var plane = node.plane; var front = Math3D.DotProduct(start, plane.normal) - plane.dist; var back = Math3D.DotProduct(end, plane.normal) - plane.dist; var side = front < 0; var sideIndex = side ? 1 : 0; if (back < 0 == side) { return(this.RecursiveLightPoint(node.children[sideIndex], start, end)); } var frac = front / (front - back); mid[0] = start[0] + (end[0] - start[0]) * frac; mid[1] = start[1] + (end[1] - start[1]) * frac; mid[2] = start[2] + (end[2] - start[2]) * frac; // go down front side var r = this.RecursiveLightPoint(node.children[sideIndex], start, mid); if (r >= 0) { return(r); // hit something } if (back < 0 == side) { return(-1); // didn't hit anuthing } // check for impact on this node Math3D.VectorCopy(mid, this.lightspot); this.lightplane = plane; var surfIndex = node.firstsurface; float[] scale = { 0, 0, 0 }; for (i = 0; i < node.numsurfaces; i++, surfIndex++) { surf = this.r_worldmodel.surfaces[surfIndex]; if ((surf.flags & (Defines.SURF_DRAWTURB | Defines.SURF_DRAWSKY)) != 0) { continue; // no lightmaps } tex = surf.texinfo; s = (int)(Math3D.DotProduct(mid, tex.vecs[0]) + tex.vecs[0][3]); t = (int)(Math3D.DotProduct(mid, tex.vecs[1]) + tex.vecs[1][3]); if (s < surf.texturemins[0] || t < surf.texturemins[1]) { continue; } ds = s - surf.texturemins[0]; dt = t - surf.texturemins[1]; if (ds > surf.extents[0] || dt > surf.extents[1]) { continue; } if (surf.samples == null) { return(0); } ds >>= 4; dt >>= 4; var lightmapIndex = 0; Math3D.VectorCopy(Globals.vec3_origin, this.pointcolor); if (surf.samples != null) { //float[] scale = {0, 0, 0}; float[] rgb; lightmapIndex += 3 * (dt * ((surf.extents[0] >> 4) + 1) + ds); for (maps = 0; maps < Defines.MAXLIGHTMAPS && surf.styles[maps] != (byte)255; maps++) { rgb = this.r_newrefdef.lightstyles[surf.styles[maps] & 0xFF].rgb; scale[0] = this.gl_modulate.value * rgb[0]; scale[1] = this.gl_modulate.value * rgb[1]; scale[2] = this.gl_modulate.value * rgb[2]; this.pointcolor[0] += surf.samples[surf.samplesOffset + lightmapIndex + 0] * scale[0] * (1.0f / 255); this.pointcolor[1] += surf.samples[surf.samplesOffset + lightmapIndex + 1] * scale[1] * (1.0f / 255); this.pointcolor[2] += surf.samples[surf.samplesOffset + lightmapIndex + 2] * scale[2] * (1.0f / 255); lightmapIndex += 3 * ((surf.extents[0] >> 4) + 1) * ((surf.extents[1] >> 4) + 1); } } return(1); } // go down back side return(this.RecursiveLightPoint(node.children[1 - sideIndex], mid, end)); }
public static int RecursiveLightPoint(mnodebase_t node, ref Vector3 start, ref Vector3 end) { if (node.contents < 0) { return(-1); // didn't hit anything } mnode_t n = (mnode_t)node; // calculate mid point // FIXME: optimize for axial mplane_t plane = n.plane; float front = Vector3.Dot(start, plane.normal) - plane.dist; float back = Vector3.Dot(end, plane.normal) - plane.dist; int side = front < 0 ? 1 : 0; if ((back < 0 ? 1 : 0) == side) { return(RecursiveLightPoint(n.children[side], ref start, ref end)); } float frac = front / (front - back); Vector3 mid = start + (end - start) * frac; // go down front side int r = RecursiveLightPoint(n.children[side], ref start, ref mid); if (r >= 0) { return(r); // hit something } if ((back < 0 ? 1 : 0) == side) { return(-1); // didn't hit anuthing } // check for impact on this node lightspot = mid; lightplane = plane; msurface_t[] surf = cl.worldmodel.surfaces; int offset = n.firstsurface; for (int i = 0; i < n.numsurfaces; i++, offset++) { if ((surf[offset].flags & q_shared.SURF_DRAWTILED) != 0) { continue; // no lightmaps } mtexinfo_t tex = surf[offset].texinfo; int s = (int)(Vector3.Dot(mid, tex.vecs[0].Xyz) + tex.vecs[0].W); int t = (int)(Vector3.Dot(mid, tex.vecs[1].Xyz) + tex.vecs[1].W); if (s < surf[offset].texturemins[0] || t < surf[offset].texturemins[1]) { continue; } int ds = s - surf[offset].texturemins[0]; int dt = t - surf[offset].texturemins[1]; if (ds > surf[offset].extents[0] || dt > surf[offset].extents[1]) { continue; } if (surf[offset].sample_base == null) { return(0); } ds >>= 4; dt >>= 4; byte[] lightmap = surf[offset].sample_base; int lmOffset = surf[offset].sampleofs; short[] extents = surf[offset].extents; r = 0; if (lightmap != null) { lmOffset += dt * ((extents[0] >> 4) + 1) + ds; for (int maps = 0; maps < q_shared.MAXLIGHTMAPS && surf[offset].styles[maps] != 255; maps++) { int scale = d_lightstylevalue[surf[offset].styles[maps]]; r += lightmap[lmOffset] * scale; lmOffset += ((extents[0] >> 4) + 1) * ((extents[1] >> 4) + 1); } r >>= 8; } return(r); } // go down back side return(RecursiveLightPoint(n.children[side == 0 ? 1 : 0], ref mid, ref end)); }
public static void R_RecursiveWorldNode(mnodebase_t node) { if (node.contents == q_shared.CONTENTS_SOLID) { return; // solid } if (node.visframe != r_visframecount) { return; } if (R_CullBox(ref node.mins, ref node.maxs)) { return; } int c; // if a leaf node, draw stuff if (node.contents < 0) { mleaf_t pleaf = (mleaf_t)node; msurface_t[] marks = pleaf.marksurfaces; int mark = pleaf.firstmarksurface; c = pleaf.nummarksurfaces; if (c != 0) { do { marks[mark].visframe = r_framecount; mark++; } while (--c != 0); } // deal with model fragments in this leaf if (pleaf.efrags != null) { R_StoreEfrags(pleaf.efrags); } return; } // node is just a decision point, so go down the apropriate sides mnode_t n = (mnode_t)node; // find which side of the node we are on mplane_t plane = n.plane; double dot; switch (plane.type) { case q_shared.PLANE_X: dot = modelorg.X - plane.dist; break; case q_shared.PLANE_Y: dot = modelorg.Y - plane.dist; break; case q_shared.PLANE_Z: dot = modelorg.Z - plane.dist; break; default: dot = Vector3.Dot(modelorg, plane.normal) - plane.dist; break; } int side = (dot >= 0 ? 0 : 1); // recurse down the children, front side first R_RecursiveWorldNode(n.children[side]); // draw stuff c = n.numsurfaces; if (c != 0) { msurface_t[] surf = cl.worldmodel.surfaces; int offset = n.firstsurface; if (dot < 0 - q_shared.BACKFACE_EPSILON) { side = q_shared.SURF_PLANEBACK; } else if (dot > q_shared.BACKFACE_EPSILON) { side = 0; } for (; c != 0; c--, offset++) { if (surf[offset].visframe != r_framecount) { continue; } // don't backface underwater surfaces, because they warp if ((surf[offset].flags & q_shared.SURF_UNDERWATER) == 0 && ((dot < 0) ^ ((surf[offset].flags & q_shared.SURF_PLANEBACK) != 0))) { continue; // wrong side } // if sorting by texture, just store it out if (gl_texsort.value != 0) { if (!mirror || surf[offset].texinfo.texture != cl.worldmodel.textures[mirrortexturenum]) { surf[offset].texturechain = surf[offset].texinfo.texture.texturechain; surf[offset].texinfo.texture.texturechain = surf[offset]; } } else if ((surf[offset].flags & q_shared.SURF_DRAWSKY) != 0) { surf[offset].texturechain = skychain; skychain = surf[offset]; } else if ((surf[offset].flags & q_shared.SURF_DRAWTURB) != 0) { surf[offset].texturechain = waterchain; waterchain = surf[offset]; } else { R_DrawSequentialPoly(surf[offset]); } } } // recurse down the back side R_RecursiveWorldNode(n.children[side == 0 ? 1 : 0]); }
/* ================= Mod_SetParent ================= */ static void Mod_SetParent(node_or_leaf_t node, mnode_t parent) { node.parent = parent; if (node.contents < 0) return; mnode_t _node = (mnode_t)node; Mod_SetParent((node_or_leaf_t)_node.children[0], _node); Mod_SetParent((node_or_leaf_t)_node.children[1], _node); }
/* ================= Mod_LoadNodes ================= */ static void Mod_LoadNodes(bspfile.lump_t l) { int i, j, count, p; bspfile.dnode_t[] @in; mnode_t[] @out; if ((l.filelen % bspfile.sizeof_dnode_t) != 0) sys_linux.Sys_Error ("MOD_LoadBmodel: funny lump size in " + loadmodel.name); count = l.filelen / bspfile.sizeof_dnode_t; bspfile.ByteBuffer buf = new bspfile.ByteBuffer(mod_base, l.fileofs); @in = new bspfile.dnode_t[count]; @out = new mnode_t[count]; for (int kk = 0; kk < count; kk++) { @in[kk] = (bspfile.dnode_t)buf; buf.ofs += bspfile.sizeof_dnode_t; @out[kk] = new mnode_t(); } loadmodel.nodes = @out; loadmodel.numnodes = count; for ( i=0 ; i<count ; i++) { for (j=0 ; j<3 ; j++) { @out[i].minmaxs[j] = @in[i].mins[j]; @out[i].minmaxs[3+j] = @in[i].maxs[j]; } p = @in[i].planenum; @out[i].plane = loadmodel.planes[p]; @out[i].firstsurface = @in[i].firstface; @out[i].numsurfaces = @in[i].numfaces; for (j=0 ; j<2 ; j++) { p = @in[i].children[j]; if (p >= 0) @out[i].children[j] = loadmodel.nodes[p]; else @out[i].children[j] = loadmodel.leafs[-1 - p]; } } Mod_SetParent (loadmodel.nodes[0], null); // sets nodes and leafs }
public virtual Int32 RecursiveLightPoint(mnode_t node, Single[] start, Single[] end) { if (node.contents != -1) { return(-1); } cplane_t plane = node.plane; var front = Math3D.DotProduct(start, plane.normal) - plane.dist; var back = Math3D.DotProduct(end, plane.normal) - plane.dist; var side = (front < 0); var sideIndex = (side) ? 1 : 0; if ((back < 0) == side) { return(RecursiveLightPoint(node.children[sideIndex], start, end)); } var frac = front / (front - back); Single[] mid = Vec3Cache.Get(); mid[0] = start[0] + (end[0] - start[0]) * frac; mid[1] = start[1] + (end[1] - start[1]) * frac; mid[2] = start[2] + (end[2] - start[2]) * frac; var r = RecursiveLightPoint(node.children[sideIndex], start, mid); if (r >= 0) { Vec3Cache.Release(); return(r); } if ((back < 0) == side) { Vec3Cache.Release(); return(-1); } Math3D.VectorCopy(mid, lightspot); lightplane = plane; var surfIndex = node.firstsurface; msurface_t surf; Int32 s, t, ds, dt; mtexinfo_t tex; ByteBuffer lightmap; Int32 maps; for (var i = 0; i < node.numsurfaces; i++, surfIndex++) { surf = r_worldmodel.surfaces[surfIndex]; if ((surf.flags & (Defines.SURF_DRAWTURB | Defines.SURF_DRAWSKY)) != 0) { continue; } tex = surf.texinfo; s = ( Int32 )(Math3D.DotProduct(mid, tex.vecs[0]) + tex.vecs[0][3]); t = ( Int32 )(Math3D.DotProduct(mid, tex.vecs[1]) + tex.vecs[1][3]); if (s < surf.texturemins[0] || t < surf.texturemins[1]) { continue; } ds = s - surf.texturemins[0]; dt = t - surf.texturemins[1]; if (ds > surf.extents[0] || dt > surf.extents[1]) { continue; } if (surf.samples == null) { return(0); } ds >>= 4; dt >>= 4; lightmap = surf.samples; var lightmapIndex = 0; Math3D.VectorCopy(Globals.vec3_origin, pointcolor); if (lightmap != null) { Single[] rgb; lightmapIndex += 3 * (dt * ((surf.extents[0] >> 4) + 1) + ds); Single scale0, scale1, scale2; for (maps = 0; maps < Defines.MAXLIGHTMAPS && surf.styles[maps] != ( Byte )255; maps++) { rgb = r_newrefdef.lightstyles[surf.styles[maps] & 0xFF].rgb; scale0 = gl_modulate.value * rgb[0]; scale1 = gl_modulate.value * rgb[1]; scale2 = gl_modulate.value * rgb[2]; pointcolor[0] += (lightmap.Get(lightmapIndex + 0) & 0xFF) * scale0 * (1F / 255); pointcolor[1] += (lightmap.Get(lightmapIndex + 1) & 0xFF) * scale1 * (1F / 255); pointcolor[2] += (lightmap.Get(lightmapIndex + 2) & 0xFF) * scale2 * (1F / 255); lightmapIndex += 3 * ((surf.extents[0] >> 4) + 1) * ((surf.extents[1] >> 4) + 1); } } Vec3Cache.Release(); return(1); } r = RecursiveLightPoint(node.children[1 - sideIndex], mid, end); Vec3Cache.Release(); return(r); }
public virtual void R_RecursiveWorldNode(mnode_t node) { if (node.contents == Defines.CONTENTS_SOLID) { return; } if (node.visframe != r_visframecount) { return; } if (R_CullBox(node.mins, node.maxs)) { return; } Int32 c; msurface_t mark; if (node.contents != -1) { mleaf_t pleaf = ( mleaf_t )node; if (r_newrefdef.areabits != null) { if (((r_newrefdef.areabits[pleaf.area >> 3] & 0xFF) & (1 << (pleaf.area & 7))) == 0) { return; } } var markp = 0; mark = pleaf.GetMarkSurface(markp); c = pleaf.nummarksurfaces; if (c != 0) { do { mark.visframe = r_framecount; mark = pleaf.GetMarkSurface(++markp); }while (--c != 0); } return; } cplane_t plane = node.plane; Single dot; switch (plane.type) { case Defines.PLANE_X: dot = modelorg[0] - plane.dist; break; case Defines.PLANE_Y: dot = modelorg[1] - plane.dist; break; case Defines.PLANE_Z: dot = modelorg[2] - plane.dist; break; default: dot = Math3D.DotProduct(modelorg, plane.normal) - plane.dist; break; } Int32 side, sidebit; if (dot >= 0F) { side = 0; sidebit = 0; } else { side = 1; sidebit = Defines.SURF_PLANEBACK; } R_RecursiveWorldNode(node.children[side]); msurface_t surf; image_t image; for (c = 0; c < node.numsurfaces; c++) { surf = r_worldmodel.surfaces[node.firstsurface + c]; if (surf.visframe != r_framecount) { continue; } if ((surf.flags & Defines.SURF_PLANEBACK) != sidebit) { continue; } if ((surf.texinfo.flags & Defines.SURF_SKY) != 0) { R_AddSkySurface(surf); } else if ((surf.texinfo.flags & (Defines.SURF_TRANS33 | Defines.SURF_TRANS66)) != 0) { surf.texturechain = r_alpha_surfaces; r_alpha_surfaces = surf; } else { if ((surf.flags & Defines.SURF_DRAWTURB) == 0) { GL_RenderLightmappedPoly(surf); } else { image = R_TextureAnimation(surf.texinfo); surf.texturechain = image.texturechain; image.texturechain = surf; } } } R_RecursiveWorldNode(node.children[1 - side]); }
public abstract void R_MarkLights(dlight_t light, Int32 bit, mnode_t node);
public static void R_SplitEntityOnNode(mnodebase_t node) { if (node.contents == q_shared.CONTENTS_SOLID) { return; } // add an efrag if the node is a leaf if (node.contents < 0) { if (r_pefragtopnode == null) { r_pefragtopnode = node as mnode_t; } mleaf_t leaf = (mleaf_t)(object)node; // grab an efrag off the free list efrag_t ef = cl.free_efrags; if (ef == null) { Con_Printf("Too many efrags!\n"); return; // no free fragments... } cl.free_efrags = cl.free_efrags.entnext; ef.entity = r_addent; // add the entity link // *lastlink = ef; if (_LastObj is entity_t) { ((entity_t)_LastObj).efrag = ef; } else { ((efrag_t)_LastObj).entnext = ef; } _LastObj = ef; // lastlink = &ef->entnext; ef.entnext = null; // set the leaf links ef.leaf = leaf; ef.leafnext = leaf.efrags; leaf.efrags = ef; return; } // NODE_MIXED mnode_t n = node as mnode_t; if (n == null) { return; } mplane_t splitplane = n.plane; int sides = Mathlib.BoxOnPlaneSide(ref r_emins, ref r_emaxs, splitplane); if (sides == 3) { // split on this plane // if this is the first splitter of this bmodel, remember it if (r_pefragtopnode == null) { r_pefragtopnode = n; } } // recurse down the contacted sides if ((sides & 1) != 0) { R_SplitEntityOnNode(n.children[0]); } if ((sides & 2) != 0) { R_SplitEntityOnNode(n.children[1]); } }