public static int BoxOnPlaneSide(ref Vector3 emins, ref Vector3 emaxs, mplane_t p) { float mindist, maxdist; switch (p.type) { case 0: mindist = emins.X; maxdist = emaxs.X; break; case 1: mindist = emins.Y; maxdist = emaxs.Y; break; case 2: mindist = emins.Z; maxdist = emaxs.Z; break; default: return(_BoxOnPlaneSide(ref emins, ref emaxs, p)); } return(p.dist <= mindist ? 1 : (p.dist >= maxdist ? 2 : 3)); }
public static void SV_Init() { for (int i = 0; i < _BoxClipNodes.Length; i++) { _BoxClipNodes[i].children = new short[2]; } for (int i = 0; i < _BoxPlanes.Length; i++) { _BoxPlanes[i] = new mplane_t(); } for (int i = 0; i < sv_areanodes.Length; i++) { sv_areanodes[i] = new areanode_t(); } sv_friction = new cvar_t("sv_friction", "4", false, true); edgefriction = new cvar_t("edgefriction", "2"); sv_stopspeed = new cvar_t("sv_stopspeed", "100"); sv_gravity = new cvar_t("sv_gravity", "800", false, true); sv_maxvelocity = new cvar_t("sv_maxvelocity", "2000"); sv_nostep = new cvar_t("sv_nostep", "0"); sv_maxspeed = new cvar_t("sv_maxspeed", "320", false, true); sv_accelerate = new cvar_t("sv_accelerate", "10"); sv_aim = new cvar_t("sv_aim", "0.93"); sv_idealpitchscale = new cvar_t("sv_idealpitchscale", "0.8"); for (int i = 0; i < q_shared.MAX_MODELS; i++) { localmodels[i] = "*" + i.ToString(); } }
public static int SV_HullPointContents(hull_t hull, int num, ref Vector3 p) { while (num >= 0) { if (num < hull.firstclipnode || num > hull.lastclipnode) { Sys_Error("SV_HullPointContents: bad node number"); } short[] node_children = hull.clipnodes[num].children; mplane_t plane = hull.planes[hull.clipnodes[num].planenum]; float d; if (plane.type < 3) { d = Mathlib.Comp(ref p, plane.type) - plane.dist; } else { d = Vector3.Dot(plane.normal, p) - plane.dist; } if (d < 0) { num = node_children[1]; } else { num = node_children[0]; } } return(num); }
public static int BoxOnPlaneSide(ref v3f emins, ref v3f emaxs, mplane_t p) { float mindist, maxdist; switch (p.type) { case 0: mindist = emins.x; maxdist = emaxs.x; break; case 1: mindist = emins.y; maxdist = emaxs.y; break; case 2: mindist = emins.z; maxdist = emaxs.z; break; default: Vector3 mins, maxs; Copy(ref emins, out mins); Copy(ref emaxs, out maxs); return(_BoxOnPlaneSide(ref mins, ref maxs, p)); } return(p.dist <= mindist ? 1 : (p.dist >= maxdist ? 2 : 3)); }
public static void R_Init() { for (int i = 0; i < frustum.Length; i++) { frustum[i] = new mplane_t(); } Cmd_AddCommand("timerefresh", R_TimeRefresh_f); //Cmd.Add("envmap", Envmap_f); //Cmd.Add("pointfile", ReadPointFile_f); r_norefresh = new cvar_t("r_norefresh", "0"); r_drawentities = new cvar_t("r_drawentities", "1"); r_drawviewmodel = new cvar_t("r_drawviewmodel", "1"); r_speeds = new cvar_t("r_speeds", "0"); r_fullbright = new cvar_t("r_fullbright", "0"); r_lightmap = new cvar_t("r_lightmap", "0"); r_shadows = new cvar_t("r_shadows", "0"); r_mirroralpha = new cvar_t("r_mirroralpha", "1"); r_wateralpha = new cvar_t("r_wateralpha", "1"); r_dynamic = new cvar_t("r_dynamic", "1"); r_novis = new cvar_t("r_novis", "0"); gl_finish = new cvar_t("gl_finish", "0"); gl_clear = new cvar_t("gl_clear", "0"); gl_cull = new cvar_t("gl_cull", "1"); gl_texsort = new cvar_t("gl_texsort", "1"); gl_smoothmodels = new cvar_t("gl_smoothmodels", "1"); gl_affinemodels = new cvar_t("gl_affinemodels", "0"); gl_polyblend = new cvar_t("gl_polyblend", "1"); gl_flashblend = new cvar_t("gl_flashblend", "1"); gl_playermip = new cvar_t("gl_playermip", "0"); gl_nocolors = new cvar_t("gl_nocolors", "0"); gl_keeptjunctions = new cvar_t("gl_keeptjunctions", "0"); gl_reporttjunctions = new cvar_t("gl_reporttjunctions", "0"); gl_doubleeys = new cvar_t("gl_doubleeys", "1"); if (gl_mtexable) { Cvar.Cvar_SetValue("gl_texsort", 0.0f); } R_InitParticles(); R_InitParticleTexture(); // reserve 16 textures playertextures = GenerateTextureNumberRange(16); }
public static int SignbitsForPlane(mplane_t p) { // for fast box on planeside test int bits = 0; if (p.normal.X < 0) { bits |= 1 << 0; } if (p.normal.Y < 0) { bits |= 1 << 1; } if (p.normal.Z < 0) { bits |= 1 << 2; } return(bits); }
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]; } } }
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]); }
public static void R_DrawBrushModel(entity_t e) { currententity = e; 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 (R_CullBox(ref mins, ref maxs)) { return; } GL.Color3(1f, 1, 1); Array.Clear(lightmap_polys, 0, lightmap_polys.Length); modelorg = r_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 && gl_flashblend.value == 0) { for (int k = 0; k < q_shared.MAX_DLIGHTS; k++) { if ((cl_dlights[k].die < cl.time) || (cl_dlights[k].radius == 0)) { continue; } R_MarkLights(cl_dlights[k], 1 << k, clmodel.nodes[clmodel.hulls[0].firstclipnode]); } } GL.PushMatrix(); e.angles.X = -e.angles.X; // stupid quake bug R_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 & q_shared.SURF_PLANEBACK) != 0; if ((planeBack && (dot < -q_shared.BACKFACE_EPSILON)) || (!planeBack && (dot > q_shared.BACKFACE_EPSILON))) { if (gl_texsort.value != 0) { R_RenderBrushPoly(psurf[surfOffset]); } else { R_DrawSequentialPoly(psurf[surfOffset]); } } } R_BlendLightmaps(); GL.PopMatrix(); }
/* ================= Mod_LoadPlanes ================= */ static void Mod_LoadPlanes(bspfile.lump_t l) { int i, j; mplane_t[] @out; bspfile.dplane_t[] @in; int count; int bits; if ((l.filelen % bspfile.sizeof_dplane_t) != 0) sys_linux.Sys_Error ("MOD_LoadBmodel: funny lump size in " + loadmodel.name); count = l.filelen / bspfile.sizeof_dplane_t; bspfile.ByteBuffer buf = new bspfile.ByteBuffer(mod_base, l.fileofs); @in = new bspfile.dplane_t[count]; @out = new mplane_t[count]; for (int kk = 0; kk < count; kk++) { @in[kk] = (bspfile.dplane_t)buf; buf.ofs += bspfile.sizeof_dplane_t; @out[kk] = new mplane_t(); } loadmodel.planes = @out; loadmodel.numplanes = count; for ( i=0 ; i<count ; i++) { bits = 0; for (j=0 ; j<3 ; j++) { @out[i].normal[j] = @in[i].normal[j]; if (@out[i].normal[j] < 0) bits |= 1<<j; } @out[i].dist = @in[i].dist; @out[i].type = (byte)@in[i].type; @out[i].signbits = (byte)bits; } }
public static bool SV_RecursiveHullCheck(hull_t hull, int num, float p1f, float p2f, ref Vector3 p1, ref Vector3 p2, trace_t trace) { // check for empty if (num < 0) { if (num != q_shared.CONTENTS_SOLID) { trace.allsolid = false; if (num == q_shared.CONTENTS_EMPTY) { trace.inopen = true; } else { trace.inwater = true; } } else { trace.startsolid = true; } return(true); // empty } if (num < hull.firstclipnode || num > hull.lastclipnode) { Sys_Error("SV_RecursiveHullCheck: bad node number"); } // // find the point distances // short[] node_children = hull.clipnodes[num].children; mplane_t plane = hull.planes[hull.clipnodes[num].planenum]; float t1, t2; if (plane.type < 3) { t1 = Mathlib.Comp(ref p1, plane.type) - plane.dist; t2 = Mathlib.Comp(ref p2, plane.type) - plane.dist; } else { t1 = Vector3.Dot(plane.normal, p1) - plane.dist; t2 = Vector3.Dot(plane.normal, p2) - plane.dist; } if (t1 >= 0 && t2 >= 0) { return(SV_RecursiveHullCheck(hull, node_children[0], p1f, p2f, ref p1, ref p2, trace)); } if (t1 < 0 && t2 < 0) { return(SV_RecursiveHullCheck(hull, node_children[1], p1f, p2f, ref p1, ref p2, trace)); } // put the crosspoint DIST_EPSILON pixels on the near side float frac; if (t1 < 0) { frac = (t1 + q_shared.DIST_EPSILON) / (t1 - t2); } else { frac = (t1 - q_shared.DIST_EPSILON) / (t1 - t2); } if (frac < 0) { frac = 0; } if (frac > 1) { frac = 1; } float midf = p1f + (p2f - p1f) * frac; Vector3 mid = p1 + (p2 - p1) * frac; int side = (t1 < 0) ? 1 : 0; // move up to the node if (!SV_RecursiveHullCheck(hull, node_children[side], p1f, midf, ref p1, ref mid, trace)) { return(false); } if (SV_HullPointContents(hull, node_children[side ^ 1], ref mid) != q_shared.CONTENTS_SOLID) { // go past the node return(SV_RecursiveHullCheck(hull, node_children[side ^ 1], midf, p2f, ref mid, ref p2, trace)); } if (trace.allsolid) { return(false); // never got out of the solid area } //================== // the other side of the node is solid, this is the impact point //================== if (side == 0) { trace.plane.normal = plane.normal; trace.plane.dist = plane.dist; } else { trace.plane.normal = -plane.normal; trace.plane.dist = -plane.dist; } while (SV_HullPointContents(hull, hull.firstclipnode, ref mid) == q_shared.CONTENTS_SOLID) { // shouldn't really happen, but does occasionally frac -= 0.1f; if (frac < 0) { trace.fraction = midf; trace.endpos = mid; Con_DPrintf("backup past 0\n"); return(false); } midf = p1f + (p2f - p1f) * frac; mid = p1 + (p2 - p1) * frac; } trace.fraction = midf; trace.endpos = mid; return(false); }
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]); } }
public static int _BoxOnPlaneSide(ref Vector3 emins, ref Vector3 emaxs, mplane_t p) { // general case float dist1, dist2; switch (p.signbits) { case 0: dist1 = p.normal.X * emaxs.X + p.normal.Y * emaxs.Y + p.normal.Z * emaxs.Z; dist2 = p.normal.X * emins.X + p.normal.Y * emins.Y + p.normal.Z * emins.Z; break; case 1: dist1 = p.normal.X * emins.X + p.normal.Y * emaxs.Y + p.normal.Z * emaxs.Z; dist2 = p.normal.X * emaxs.X + p.normal.Y * emins.Y + p.normal.Z * emins.Z; break; case 2: dist1 = p.normal.X * emaxs.X + p.normal.Y * emins.Y + p.normal.Z * emaxs.Z; dist2 = p.normal.X * emins.X + p.normal.Y * emaxs.Y + p.normal.Z * emins.Z; break; case 3: dist1 = p.normal.X * emins.X + p.normal.Y * emins.Y + p.normal.Z * emaxs.Z; dist2 = p.normal.X * emaxs.X + p.normal.Y * emaxs.Y + p.normal.Z * emins.Z; break; case 4: dist1 = p.normal.X * emaxs.X + p.normal.Y * emaxs.Y + p.normal.Z * emins.Z; dist2 = p.normal.X * emins.X + p.normal.Y * emins.Y + p.normal.Z * emaxs.Z; break; case 5: dist1 = p.normal.X * emins.X + p.normal.Y * emaxs.Y + p.normal.Z * emins.Z; dist2 = p.normal.X * emaxs.X + p.normal.Y * emins.Y + p.normal.Z * emaxs.Z; break; case 6: dist1 = p.normal.X * emaxs.X + p.normal.Y * emins.Y + p.normal.Z * emins.Z; dist2 = p.normal.X * emins.X + p.normal.Y * emaxs.Y + p.normal.Z * emaxs.Z; break; case 7: dist1 = p.normal.X * emins.X + p.normal.Y * emins.Y + p.normal.Z * emins.Z; dist2 = p.normal.X * emaxs.X + p.normal.Y * emaxs.Y + p.normal.Z * emaxs.Z; break; default: dist1 = dist2 = 0; // shut up compiler game_engine.Sys_Error("BoxOnPlaneSide: Bad signbits"); break; } int sides = 0; if (dist1 >= p.dist) { sides = 1; } if (dist2 < p.dist) { sides |= 2; } #if PARANOID if (sides == 0) { Sys.Error("BoxOnPlaneSide: sides==0"); } #endif return(sides); }