/* * ================= * = * = P_LoadSegs * = * ================= */ public static void P_LoadSegs(int lump) { w_wad.CacheInfo data; int i, j; DoomData.mapseg_t ml; r_local.seg_t li, lj; r_local.line_t ldef; int linedef, side; numsegs = w_wad.W_LumpLength(lump) / 12; segs = new r_local.seg_t[numsegs]; data = w_wad.W_CacheLumpNum(lump, DoomDef.PU_STATIC); BinaryReader br = new BinaryReader(new MemoryStream(data.data)); for (i = 0; i < numsegs; i++) { ml = new DoomData.mapseg_t(); ml.v1 = br.ReadInt16(); ml.v2 = br.ReadInt16(); ml.angle = br.ReadInt16(); ml.linedef = br.ReadInt16(); ml.side = br.ReadInt16(); ml.offset = br.ReadInt16(); li = new r_local.seg_t(); li.v1 = vertexes[ml.v1]; li.v2 = vertexes[ml.v2]; li.angle = (uint)ml.angle << 16; li.offset = ml.offset << 16; linedef = ml.linedef; ldef = lines[linedef]; li.linedef = ldef; side = ml.side; li.sidedef = sides[ldef.sidenum[side]]; li.frontsector = sides[ldef.sidenum[side]].sector; if ((ldef.flags & DoomData.ML_TWOSIDED) != 0) { li.backsector = sides[ldef.sidenum[side ^ 1]].sector; } else { li.backsector = null; } Vector2 dir = new Vector2(li.v2.x >> DoomDef.FRACBITS, li.v2.y >> DoomDef.FRACBITS) - new Vector2(li.v1.x >> DoomDef.FRACBITS, li.v1.y >> DoomDef.FRACBITS); dir.Normalize(); li.normal.X = dir.Y; li.normal.Y = -dir.X; li.dir = dir; segs[i] = li; } // [dsl] Search for segment neighbors. We do this for the ambient occlusion parts for (i = 0; i < numsegs; i++) { li = segs[i]; if (li.frontsector == li.backsector) { continue; } for (j = 0; j < numsegs; j++) { if (i == j) { continue; } lj = segs[j]; if (lj.frontsector == lj.backsector) { continue; } if (Vector2.Dot(li.normal, lj.normal) < 0) { continue; } if (lj.v2.x == li.v1.x && lj.v2.y == li.v1.y) { if (Vector2.Dot(lj.normal, li.dir) > 0) { li.left.Add(lj); } } if (lj.v1.x == li.v2.x && lj.v1.y == li.v2.y) { if (Vector2.Dot(li.normal, lj.dir) > 0) { li.right.Add(lj); } } } } }
//============================================================================= /* * ====================== * = * = R_AddLine * = * = Clips the given segment and adds any visible pieces to the line list * = * ====================== */ public static void R_AddLine(r_local.seg_t line) { int x1, x2; uint angle1, angle2, span, tspan; curline = line; // OPTIMIZE: quickly reject orthogonal back sides angle1 = r_main.R_PointToAngle(line.v1.x, line.v1.y); angle2 = r_main.R_PointToAngle(line.v2.x, line.v2.y); // // clip to view edges // OPTIMIZE: make constant out of 2*clipangle (FIELDOFVIEW) span = angle1 - angle2; if (span >= DoomDef.ANG180) { return; // back side } r_segs.rw_angle1 = (int)angle1; // global angle needed by segcalc angle1 -= r_main.viewangle; angle2 -= r_main.viewangle; tspan = angle1 + r_main.clipangle; if (tspan > 2 * r_main.clipangle) { tspan -= 2 * r_main.clipangle; if (tspan >= span) { return; // totally off the left edge } angle1 = r_main.clipangle; } tspan = r_main.clipangle - angle2; if (tspan > 2 * r_main.clipangle) { tspan -= 2 * r_main.clipangle; if (tspan >= span) { return; // totally off the left edge } angle2 = (uint)(-r_main.clipangle); } // // the seg is in the view range, but not necessarily visible // angle1 = (uint)((int)(angle1 + DoomDef.ANG90) >> (int)DoomDef.ANGLETOFINESHIFT); angle2 = (uint)((int)(angle2 + DoomDef.ANG90) >> (int)DoomDef.ANGLETOFINESHIFT); x1 = r_main.viewangletox[angle1]; x2 = r_main.viewangletox[angle2]; if (x1 == x2) { return; // does not cross a pixel } backsector = line.backsector; // [dsl] There were gotos here. Yup if (backsector == null) { R_ClipSolidWallSegment(x1, x2 - 1); // single sided line return; } if (backsector.ceilingheight <= frontsector.floorheight || backsector.floorheight >= frontsector.ceilingheight) { R_ClipSolidWallSegment(x1, x2 - 1); // closed door return; } if (backsector.ceilingheight != frontsector.ceilingheight || backsector.floorheight != frontsector.floorheight) { R_ClipPassWallSegment(x1, x2 - 1); // window return; } // reject empty lines used for triggers and special events if (backsector.ceilingpic == frontsector.ceilingpic && backsector.floorpic == frontsector.floorpic && backsector.lightlevel == frontsector.lightlevel && curline.sidedef. midtexture == 0) { return; } R_ClipPassWallSegment(x1, x2 - 1); }
private static void testLine(r_local.sector_t sector, r_local.seg_t li, ref Vector4 in_prevScreenBB) { #if DEBUG ++portalChecked; #endif r_local.sector_t nextSector; if (li.frontsector == sector) { if (li.backsector == null) { return; } nextSector = li.backsector; } else { return; } Vector3 v1, v2, screenSpace; v1.X = li.v1.x >> DoomDef.FRACBITS; v1.Y = li.v1.y >> DoomDef.FRACBITS; v2.X = li.v2.x >> DoomDef.FRACBITS; v2.Y = li.v2.y >> DoomDef.FRACBITS; v1.Z = Math.Max(li.frontsector.floorheight >> DoomDef.FRACBITS, li.backsector.floorheight >> DoomDef.FRACBITS); v2.Z = Math.Min(li.frontsector.ceilingheight >> DoomDef.FRACBITS, li.backsector.ceilingheight >> DoomDef.FRACBITS); if (v1.Z >= v2.Z) { return; } // if (frustum.Contains(liBB) == ContainmentType.Disjoint) return; Vector4 screenBB; Vector2 originalBB; screenBB.X = screenSize.X + 10000; screenBB.Y = screenSize.Y + 10000; screenBB.Z = -10000; screenBB.W = -10000; bool allBehind = true; screenSpace = v1; Project(ref screenSpace); screenBB.X = screenSpace.X < screenBB.X ? screenSpace.X : screenBB.X; screenBB.W = screenSpace.Y > screenBB.W ? screenSpace.Y : screenBB.W; if (screenSpace.Z < camLimit) { allBehind = false; } screenSpace = v1; screenSpace.Z = v2.Z; Project(ref screenSpace); screenBB.X = screenSpace.X < screenBB.X ? screenSpace.X : screenBB.X; screenBB.Y = screenSpace.Y < screenBB.Y ? screenSpace.Y : screenBB.Y; if (screenSpace.Z < camLimit) { allBehind = false; } screenSpace = v2; screenSpace.Z = v1.Z; Project(ref screenSpace); screenBB.Z = screenSpace.X > screenBB.Z ? screenSpace.X : screenBB.Z; screenBB.W = screenSpace.Y > screenBB.W ? screenSpace.Y : screenBB.W; if (screenSpace.Z < camLimit) { allBehind = false; } screenSpace = v2; screenSpace.Z = v2.Z; Project(ref screenSpace); screenBB.Y = screenSpace.Y < screenBB.Y ? screenSpace.Y : screenBB.Y; screenBB.Z = screenSpace.X > screenBB.Z ? screenSpace.X : screenBB.Z; if (screenBB.X >= screenBB.Z) { return; } if (screenBB.Y >= screenBB.W) { return; } if (screenSpace.Z < camLimit) { allBehind = false; } if (allBehind) { return; } if (screenBB.X < 0) { screenBB.X = 0; } if (screenBB.Y < 0) { screenBB.Y = 0; } if (screenBB.Z > screenSize.X) { screenBB.Z = screenSize.X; } if (screenBB.W > screenSize.Y) { screenBB.W = screenSize.Y; } originalBB.X = screenBB.X; originalBB.Y = screenBB.Z; // Merge with previous bounding screenBB.X = screenBB.X > in_prevScreenBB.X ? screenBB.X : in_prevScreenBB.X; screenBB.Y = screenBB.Y > in_prevScreenBB.Y ? screenBB.Y : in_prevScreenBB.Y; screenBB.Z = screenBB.Z < in_prevScreenBB.Z ? screenBB.Z : in_prevScreenBB.Z; screenBB.W = screenBB.W < in_prevScreenBB.W ? screenBB.W : in_prevScreenBB.W; if (screenBB.X >= screenBB.Z) { return; } if (screenBB.Y >= screenBB.W) { return; } if (screenBB.Z < 0 || screenBB.X > screenSize.X) { return; } if (screenBB.W < 0 || screenBB.Y > screenSize.Y) { return; } if (originalBB.X == screenBB.X && originalBB.Y == screenBB.Z) { li.culling_alreadyFullyIncluded = checkId; } debugRects.Add(screenBB); #if DEBUG ++portalTraversed; #endif li.culling_checkId = checkId; addSector(nextSector, ref screenBB); li.culling_checkId = 0; }