// This makes sure we are updated with the source linedef information public override void Update() { SectorData sd = data.Mode.GetSectorData(linedef.Front.Sector); if (!sd.Updated) { sd.Update(); } sd.AddUpdateSector(data.Sector, false); // Transfer ceiling brightness, keep sector color PixelColor lightcolor = PixelColor.FromInt(data.Sector.Fields.GetValue("lightcolor", -1)); PixelColor brightness = PixelColor.FromInt(General.Map.Renderer3D.CalculateBrightness(sd.Sector.Brightness)); data.Ceiling.color = PixelColor.Modulate(lightcolor, brightness).WithAlpha(255).ToInt(); }
// This makes sure we are updated with the source linedef information public override void Update() { //mxd. Skip if arg0 is 0. if (thing.Args[0] == 0) { return; } ThingData td = data.Mode.GetThingData(thing); Thing t = thing; Linedef ld = sidedef.Line; if (ld != null) { if (t.Type == 9500) { SectorData sd = data.Mode.GetSectorData(sidedef.Sector); Vector3D v1 = new Vector3D(ld.Start.Position.x, ld.Start.Position.y, sd.Floor.plane.GetZ(ld.Start.Position)); Vector3D v2 = new Vector3D(ld.End.Position.x, ld.End.Position.y, sd.Floor.plane.GetZ(ld.End.Position)); Vector3D v3 = new Vector3D(t.Position.x, t.Position.y, t.Position.z + sd.Floor.plane.GetZ(t.Position)); sd.AddUpdateSector(data.Sector, true); if (!sd.Updated) { sd.Update(); } td.AddUpdateSector(sidedef.Sector, true); sd.Floor.plane = new Plane(v1, v2, v3, true); } else if (t.Type == 9501) { SectorData sd = data.Mode.GetSectorData(sidedef.Sector); Vector3D v1 = new Vector3D(ld.Start.Position.x, ld.Start.Position.y, sd.Ceiling.plane.GetZ(ld.Start.Position)); Vector3D v2 = new Vector3D(ld.End.Position.x, ld.End.Position.y, sd.Ceiling.plane.GetZ(ld.End.Position)); Vector3D v3 = new Vector3D(t.Position.x, t.Position.y, t.Position.z + sd.Ceiling.plane.GetZ(t.Position)); sd.AddUpdateSector(data.Sector, true); if (!sd.Updated) { sd.Update(); } td.AddUpdateSector(sidedef.Sector, true); sd.Ceiling.plane = new Plane(v1, v2, v3, false); } } }
// This makes sure we are updated with the source linedef information public override void Update() { SectorData sd = data.Mode.GetSectorData(linedef.Front.Sector); if (!sd.Updated) { sd.Update(); } sd.AddUpdateSector(data.Sector, false); // Create top level? if (toplevel == null) { toplevel = new SectorLevel(sd.Ceiling); data.AddSectorLevel(toplevel); } // Update top level sd.Ceiling.CopyProperties(toplevel); toplevel.lighttype = (LightLevelType)General.Clamp(linedef.Args[1], 0, 2); //mxd toplevel.type = SectorLevelType.Light; //mxd. Create bottom level? if (toplevel.lighttype == LightLevelType.TYPE1) { // Create bottom level? Skip this step if there's a different light level between toplevel and bottomlevel if (bottomlevel == null) { bottomlevel = new SectorLevel(data.Ceiling); data.AddSectorLevel(bottomlevel); } // Update bottom level data.Ceiling.CopyProperties(bottomlevel); bottomlevel.type = SectorLevelType.Light; bottomlevel.lighttype = LightLevelType.TYPE1_BOTTOM; bottomlevel.plane = sd.Floor.plane.GetInverted(); } }
// This makes sure we are updated with the source linedef information public override void Update() { // Find tagged sector Sector sourcesector = null; foreach (Sector s in General.Map.Map.Sectors) { if (s.Tags.Contains(thing.Args[0])) { sourcesector = s; break; } } if (sourcesector != null) { SectorData sourcesectordata = data.Mode.GetSectorData(sourcesector); if (!sourcesectordata.Updated) { sourcesectordata.Update(); } switch (thing.Type) { case 9510: data.Floor.plane = sourcesectordata.Floor.plane; break; case 9511: data.Ceiling.plane = sourcesectordata.Ceiling.plane; break; } sourcesectordata.AddUpdateSector(data.Sector, true); } }
// This builds the geometry. Returns false when no geometry created. public override bool Setup() { //mxd if (Sidedef.LongMiddleTexture == MapSet.EmptyLongName) { base.SetVertices(null); return(false); } Vector2D vl, vr; //mxd. lightfog flag support int lightvalue; bool lightabsolute; GetLightValue(out lightvalue, out lightabsolute); Vector2D tscale = new Vector2D(Sidedef.Fields.GetValue("scalex_mid", 1.0f), Sidedef.Fields.GetValue("scaley_mid", 1.0f)); Vector2D tscaleAbs = new Vector2D(Math.Abs(tscale.x), Math.Abs(tscale.y)); Vector2D toffset = new Vector2D(Sidedef.Fields.GetValue("offsetx_mid", 0.0f), Sidedef.Fields.GetValue("offsety_mid", 0.0f)); // Left and right vertices for this sidedef if (Sidedef.IsFront) { vl = new Vector2D(Sidedef.Line.Start.Position.x, Sidedef.Line.Start.Position.y); vr = new Vector2D(Sidedef.Line.End.Position.x, Sidedef.Line.End.Position.y); } else { vl = new Vector2D(Sidedef.Line.End.Position.x, Sidedef.Line.End.Position.y); vr = new Vector2D(Sidedef.Line.Start.Position.x, Sidedef.Line.Start.Position.y); } // Load sector data SectorData sd = mode.GetSectorData(Sidedef.Sector); SectorData osd = mode.GetSectorData(Sidedef.Other.Sector); if (!osd.Updated) { osd.Update(); } // Load texture if (Sidedef.LongMiddleTexture != MapSet.EmptyLongName) { base.Texture = General.Map.Data.GetTextureImage(Sidedef.LongMiddleTexture); if (base.Texture == null || base.Texture is UnknownImage) { base.Texture = General.Map.Data.UnknownTexture3D; setuponloadedtexture = Sidedef.LongMiddleTexture; } else if (!base.Texture.IsImageLoaded) { setuponloadedtexture = Sidedef.LongMiddleTexture; } } else { // Use missing texture base.Texture = General.Map.Data.MissingTexture3D; setuponloadedtexture = 0; } // Get texture scaled size Vector2D tsz = new Vector2D(base.Texture.ScaledWidth, base.Texture.ScaledHeight); tsz = tsz / tscale; // Get texture offsets Vector2D tof = new Vector2D(Sidedef.OffsetX, Sidedef.OffsetY); tof = tof + toffset; tof = tof / tscaleAbs; if (General.Map.Config.ScaledTextureOffsets && !base.Texture.WorldPanning) { tof = tof * base.Texture.Scale; } // Determine texture coordinates plane as they would be in normal circumstances. // We can then use this plane to find any texture coordinate we need. // The logic here is the same as in the original VisualMiddleSingle (except that // the values are stored in a TexturePlane) // NOTE: I use a small bias for the floor height, because if the difference in // height is 0 then the TexturePlane doesn't work! TexturePlane tp = new TexturePlane(); float floorbias = (Sidedef.Sector.CeilHeight == Sidedef.Sector.FloorHeight) ? 1.0f : 0.0f; float geotop = Math.Min(Sidedef.Sector.CeilHeight, Sidedef.Other.Sector.CeilHeight); float geobottom = Math.Max(Sidedef.Sector.FloorHeight, Sidedef.Other.Sector.FloorHeight); float zoffset = Sidedef.Sector.CeilHeight - Sidedef.Other.Sector.CeilHeight; //mxd // When lower unpegged is set, the middle texture is bound to the bottom if (Sidedef.Line.IsFlagSet(General.Map.Config.LowerUnpeggedFlag)) { tp.tlt.y = tsz.y - (geotop - geobottom); } if (zoffset > 0) { tp.tlt.y -= zoffset; //mxd } tp.trb.x = tp.tlt.x + (float)Math.Round(Sidedef.Line.Length); //mxd. (G)ZDoom snaps texture coordinates to integral linedef length tp.trb.y = tp.tlt.y + (Sidedef.Sector.CeilHeight - (Sidedef.Sector.FloorHeight + floorbias)); // Apply texture offset tp.tlt += tof; tp.trb += tof; // Transform pixel coordinates to texture coordinates tp.tlt /= tsz; tp.trb /= tsz; // Left top and right bottom of the geometry that tp.vlt = new Vector3D(vl.x, vl.y, Sidedef.Sector.CeilHeight); tp.vrb = new Vector3D(vr.x, vr.y, Sidedef.Sector.FloorHeight + floorbias); // Make the right-top coordinates tp.trt = new Vector2D(tp.trb.x, tp.tlt.y); tp.vrt = new Vector3D(tp.vrb.x, tp.vrb.y, tp.vlt.z); // Keep top and bottom planes for intersection testing top = sd.Ceiling.plane; bottom = sd.Floor.plane; // Create initial polygon, which is just a quad between floor and ceiling WallPolygon poly = new WallPolygon(); poly.Add(new Vector3D(vl.x, vl.y, sd.Floor.plane.GetZ(vl))); poly.Add(new Vector3D(vl.x, vl.y, sd.Ceiling.plane.GetZ(vl))); poly.Add(new Vector3D(vr.x, vr.y, sd.Ceiling.plane.GetZ(vr))); poly.Add(new Vector3D(vr.x, vr.y, sd.Floor.plane.GetZ(vr))); // Determine initial color int lightlevel = lightabsolute ? lightvalue : sd.Ceiling.brightnessbelow + lightvalue; //mxd. This calculates light with doom-style wall shading PixelColor wallbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightlevel, Sidedef)); PixelColor wallcolor = PixelColor.Modulate(sd.Ceiling.colorbelow, wallbrightness); fogfactor = CalculateFogFactor(lightlevel); poly.color = wallcolor.WithAlpha(255).ToInt(); // Cut off the part below the other floor and above the other ceiling CropPoly(ref poly, osd.Ceiling.plane, true); CropPoly(ref poly, osd.Floor.plane, true); // Determine if we should repeat the middle texture repeatmidtex = Sidedef.IsFlagSet("wrapmidtex") || Sidedef.Line.IsFlagSet("wrapmidtex"); //mxd if (!repeatmidtex) { // First determine the visible portion of the texture float textop; // Determine top portion height if (Sidedef.Line.IsFlagSet(General.Map.Config.LowerUnpeggedFlag)) { textop = geobottom + tof.y + Math.Abs(tsz.y); } else { textop = geotop + tof.y; } // Calculate bottom portion height float texbottom = textop - Math.Abs(tsz.y); // Create crop planes (we also need these for intersection testing) topclipplane = new Plane(new Vector3D(0, 0, -1), textop); bottomclipplane = new Plane(new Vector3D(0, 0, 1), -texbottom); // Crop polygon by these heights CropPoly(ref poly, topclipplane, true); CropPoly(ref poly, bottomclipplane, true); } //mxd. In(G)ZDoom, middle sidedef parts are not clipped by extrafloors of any type... List <WallPolygon> polygons = new List <WallPolygon> { poly }; //ClipExtraFloors(polygons, sd.ExtraFloors, true); //mxd //ClipExtraFloors(polygons, osd.ExtraFloors, true); //mxd //if(polygons.Count > 0) //{ // Keep top and bottom planes for intersection testing top = osd.Ceiling.plane; bottom = osd.Floor.plane; // Process the polygon and create vertices List <WorldVertex> verts = CreatePolygonVertices(polygons, tp, sd, lightvalue, lightabsolute); if (verts.Count > 2) { // Apply alpha to vertices byte alpha = SetLinedefRenderstyle(true); if (alpha < 255) { for (int i = 0; i < verts.Count; i++) { WorldVertex v = verts[i]; v.c = PixelColor.FromInt(v.c).WithAlpha(alpha).ToInt(); verts[i] = v; } } base.SetVertices(verts); return(true); } //} base.SetVertices(null); //mxd return(false); }
// This builds the geometry. Returns false when no geometry created. public override bool Setup() { if (!IsFogBoundary()) { return(false); } //mxd. lightfog flag support int lightvalue; bool lightabsolute; GetLightValue(out lightvalue, out lightabsolute); // Left and right vertices for this sidedef Vector2D vl, vr; if (Sidedef.IsFront) { vl = new Vector2D(Sidedef.Line.Start.Position.x, Sidedef.Line.Start.Position.y); vr = new Vector2D(Sidedef.Line.End.Position.x, Sidedef.Line.End.Position.y); } else { vl = new Vector2D(Sidedef.Line.End.Position.x, Sidedef.Line.End.Position.y); vr = new Vector2D(Sidedef.Line.Start.Position.x, Sidedef.Line.Start.Position.y); } // Load sector data SectorData sd = mode.GetSectorData(Sidedef.Sector); SectorData osd = mode.GetSectorData(Sidedef.Other.Sector); if (!osd.Updated) { osd.Update(); } // Set texture base.Texture = General.Map.Data.BlackTexture; // Determine texture coordinates plane as they would be in normal circumstances. TexturePlane tp = new TexturePlane(); float floorbias = (Sidedef.Sector.CeilHeight == Sidedef.Sector.FloorHeight) ? 1.0f : 0.0f; float zoffset = Sidedef.Sector.CeilHeight - Sidedef.Other.Sector.CeilHeight; //mxd if (zoffset > 0) { tp.tlt.y -= zoffset; //mxd } tp.trb.x = tp.tlt.x + Sidedef.Line.Length; tp.trb.y = tp.tlt.y + (Sidedef.Sector.CeilHeight - (Sidedef.Sector.FloorHeight + floorbias)); // Left top and right bottom of the geometry that tp.vlt = new Vector3D(vl.x, vl.y, Sidedef.Sector.CeilHeight); tp.vrb = new Vector3D(vr.x, vr.y, Sidedef.Sector.FloorHeight + floorbias); // Make the right-top coordinates tp.trt = new Vector2D(tp.trb.x, tp.tlt.y); tp.vrt = new Vector3D(tp.vrb.x, tp.vrb.y, tp.vlt.z); // Keep top and bottom planes for intersection testing top = sd.Ceiling.plane; bottom = sd.Floor.plane; // Create initial polygon, which is just a quad between floor and ceiling WallPolygon poly = new WallPolygon(); poly.Add(new Vector3D(vl.x, vl.y, sd.Floor.plane.GetZ(vl))); poly.Add(new Vector3D(vl.x, vl.y, sd.Ceiling.plane.GetZ(vl))); poly.Add(new Vector3D(vr.x, vr.y, sd.Ceiling.plane.GetZ(vr))); poly.Add(new Vector3D(vr.x, vr.y, sd.Floor.plane.GetZ(vr))); // Determine initial color int lightlevel = sd.Ceiling.brightnessbelow + lightvalue; // Calculate fog density fogfactor = CalculateFogFactor(lightlevel); poly.color = PixelColor.INT_WHITE; // Cut off the part below the other floor and above the other ceiling CropPoly(ref poly, osd.Ceiling.plane, true); CropPoly(ref poly, osd.Floor.plane, true); List <WallPolygon> polygons = new List <WallPolygon> { poly }; // Keep top and bottom planes for intersection testing top = osd.Ceiling.plane; bottom = osd.Floor.plane; // Process the polygon and create vertices List <WorldVertex> verts = CreatePolygonVertices(polygons, tp, sd, lightvalue, lightabsolute); if (verts.Count > 2) { base.SetVertices(verts); return(true); } base.SetVertices(null); return(false); }
// This builds the geometry. Returns false when no geometry created. public override bool Setup() { Vector2D vl, vr; // Left and right vertices for this sidedef if (Sidedef.IsFront) { vl = new Vector2D(Sidedef.Line.Start.Position.x, Sidedef.Line.Start.Position.y); vr = new Vector2D(Sidedef.Line.End.Position.x, Sidedef.Line.End.Position.y); } else { vl = new Vector2D(Sidedef.Line.End.Position.x, Sidedef.Line.End.Position.y); vr = new Vector2D(Sidedef.Line.Start.Position.x, Sidedef.Line.Start.Position.y); } // Load sector data SectorData sd = Sector.GetSectorData(); SectorData osd = mode.GetSectorData(Sidedef.Other.Sector); if (!osd.Updated) { osd.Update(); } //mxd float vlzc = sd.Ceiling.plane.GetZ(vl); float vrzc = sd.Ceiling.plane.GetZ(vr); //mxd. Side is visible when our sector's ceiling is higher than the other's at any vertex if (!(vlzc > osd.Ceiling.plane.GetZ(vl) || vrzc > osd.Ceiling.plane.GetZ(vr))) { base.SetVertices(null); return(false); } //mxd. Apply sky hack? UpdateSkyRenderFlag(); //mxd. lightfog flag support int lightvalue; bool lightabsolute; GetLightValue(out lightvalue, out lightabsolute); Vector2D tscale = new Vector2D(Sidedef.Fields.GetValue("scalex_top", 1.0f), Sidedef.Fields.GetValue("scaley_top", 1.0f)); Vector2D tscaleAbs = new Vector2D(Math.Abs(tscale.x), Math.Abs(tscale.y)); Vector2D toffset = new Vector2D(Sidedef.Fields.GetValue("offsetx_top", 0.0f), Sidedef.Fields.GetValue("offsety_top", 0.0f)); // Texture given? if ((Sidedef.LongHighTexture != MapSet.EmptyLongName)) { // Load texture base.Texture = General.Map.Data.GetTextureImage(Sidedef.LongHighTexture); if (base.Texture == null || base.Texture is UnknownImage) { base.Texture = General.Map.Data.UnknownTexture3D; setuponloadedtexture = Sidedef.LongHighTexture; } else if (!base.Texture.IsImageLoaded) { setuponloadedtexture = Sidedef.LongHighTexture; } } else { // Use missing texture base.Texture = General.Map.Data.MissingTexture3D; setuponloadedtexture = 0; } // Get texture scaled size Vector2D tsz = new Vector2D(base.Texture.ScaledWidth, base.Texture.ScaledHeight); tsz = tsz / tscale; // Get texture offsets Vector2D tof = new Vector2D(Sidedef.OffsetX, Sidedef.OffsetY); tof = tof + toffset; // biwa. Also take the ForceWorldPanning MAPINFO entry into account if (General.Map.Config.ScaledTextureOffsets && (!base.Texture.WorldPanning && !General.Map.Data.MapInfo.ForceWorldPanning)) { tof = tof / tscaleAbs; tof = tof * base.Texture.Scale; } // Determine texture coordinates plane as they would be in normal circumstances. // We can then use this plane to find any texture coordinate we need. // The logic here is the same as in the original VisualMiddleSingle (except that // the values are stored in a TexturePlane) // NOTE: I use a small bias for the floor height, because if the difference in // height is 0 then the TexturePlane doesn't work! TexturePlane tp = new TexturePlane(); float ceilbias = (Sidedef.Other.Sector.CeilHeight == Sidedef.Sector.CeilHeight) ? 1.0f : 0.0f; if (!Sidedef.Line.IsFlagSet(General.Map.Config.UpperUnpeggedFlag)) { // When lower unpegged is set, the lower texture is bound to the bottom tp.tlt.y = tsz.y - ((float)Sidedef.Sector.CeilHeight - Sidedef.Other.Sector.CeilHeight); } tp.trb.x = tp.tlt.x + (float)Math.Round(Sidedef.Line.Length); //mxd. (G)ZDoom snaps texture coordinates to integral linedef length tp.trb.y = tp.tlt.y + (Sidedef.Sector.CeilHeight - (Sidedef.Other.Sector.CeilHeight + ceilbias)); // Apply texture offset tp.tlt += tof; tp.trb += tof; // Transform pixel coordinates to texture coordinates tp.tlt /= tsz; tp.trb /= tsz; // Left top and right bottom of the geometry that tp.vlt = new Vector3D(vl.x, vl.y, Sidedef.Sector.CeilHeight); tp.vrb = new Vector3D(vr.x, vr.y, Sidedef.Other.Sector.CeilHeight + ceilbias); // Make the right-top coordinates tp.trt = new Vector2D(tp.trb.x, tp.tlt.y); tp.vrt = new Vector3D(tp.vrb.x, tp.vrb.y, tp.vlt.z); // Create initial polygon, which is just a quad between floor and ceiling WallPolygon poly = new WallPolygon(); poly.Add(new Vector3D(vl.x, vl.y, sd.Floor.plane.GetZ(vl))); poly.Add(new Vector3D(vl.x, vl.y, vlzc)); poly.Add(new Vector3D(vr.x, vr.y, vrzc)); poly.Add(new Vector3D(vr.x, vr.y, sd.Floor.plane.GetZ(vr))); // Determine initial color int lightlevel = lightabsolute ? lightvalue : sd.Ceiling.brightnessbelow + lightvalue; //mxd. This calculates light with doom-style wall shading PixelColor wallbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightlevel, Sidedef)); PixelColor wallcolor = PixelColor.Modulate(sd.Ceiling.colorbelow, wallbrightness); fogfactor = CalculateFogFactor(lightlevel); poly.color = wallcolor.WithAlpha(255).ToInt(); // Cut off the part below the other ceiling CropPoly(ref poly, osd.Ceiling.plane, false); // Cut out pieces that overlap 3D floors in this sector List <WallPolygon> polygons = new List <WallPolygon> { poly }; ClipExtraFloors(polygons, sd.ExtraFloors, false); //mxd if (polygons.Count > 0) { // Keep top and bottom planes for intersection testing Vector2D linecenter = Sidedef.Line.GetCenterPoint(); //mxd. Our sector's floor can be higher than the other sector's ceiling! top = sd.Ceiling.plane; bottom = (osd.Ceiling.plane.GetZ(linecenter) > sd.Floor.plane.GetZ(linecenter) ? osd.Ceiling.plane : sd.Floor.plane); // Process the polygon and create vertices List <WorldVertex> verts = CreatePolygonVertices(polygons, tp, sd, lightvalue, lightabsolute); if (verts.Count > 2) { base.SetVertices(verts); return(true); } } base.SetVertices(null); //mxd return(false); }
// This makes sure we are updated with the source linedef information public override void Update() { ThingData td = data.Mode.GetThingData(thing); Thing t = thing; // Floor slope thing if (t.Type == 9502) { t.DetermineSector(data.Mode.BlockMap); if (t.Sector != null) { //mxd. Vertex zheight overrides this effect if (General.Map.UDMF && t.Sector.Sidedefs.Count == 3) { foreach (Sidedef side in t.Sector.Sidedefs) { if (!double.IsNaN(side.Line.Start.ZFloor) || !double.IsNaN(side.Line.End.ZFloor)) { return; } } } double angle = Angle2D.DoomToReal((int)Angle2D.RadToDeg(t.Angle)); double vangle = Angle2D.DegToRad(General.Clamp(t.Args[0], 0, 180)); //mxd. Don't underestimate user stupidity (or curiosity)! Vector2D point = new Vector2D(t.Position.x + Math.Cos(angle) * Math.Sin(vangle), t.Position.y + Math.Sin(angle) * Math.Sin(vangle)); Vector2D perpendicular = new Line2D(t.Position, point).GetPerpendicular(); Vector3D v1 = new Vector3D(t.Position.x, t.Position.y, t.Position.z + t.Sector.FloorHeight); Vector3D v2 = new Vector3D( point.x + perpendicular.x, point.y + perpendicular.y, t.Position.z + t.Sector.FloorHeight + Math.Cos(vangle) ); Vector3D v3 = new Vector3D( point.x - perpendicular.x, point.y - perpendicular.y, t.Position.z + t.Sector.FloorHeight + Math.Cos(vangle) ); SectorData sd = data.Mode.GetSectorData(t.Sector); sd.AddUpdateSector(data.Sector, true); if (!sd.Updated) { sd.Update(); } td.AddUpdateSector(t.Sector, true); sd.Floor.plane = new Plane(v1, v2, v3, true); } } // Ceiling slope thing else if (t.Type == 9503) { t.DetermineSector(data.Mode.BlockMap); if (t.Sector != null) { //mxd. Vertex zheight overrides this effect if (General.Map.UDMF && t.Sector.Sidedefs.Count == 3) { foreach (Sidedef side in t.Sector.Sidedefs) { if (!double.IsNaN(side.Line.Start.ZCeiling) || !double.IsNaN(side.Line.End.ZCeiling)) { return; } } } double angle = Angle2D.DoomToReal((int)Angle2D.RadToDeg(t.Angle)); double vangle = Angle2D.DegToRad(General.Clamp(t.Args[0], 0, 180)); //mxd. Don't underestimate user stupidity (or curiosity)! Vector2D point = new Vector2D(t.Position.x + Math.Cos(angle) * Math.Sin(vangle), t.Position.y + Math.Sin(angle) * Math.Sin(vangle)); Vector2D perpendicular = new Line2D(t.Position, point).GetPerpendicular(); Vector3D v1 = new Vector3D(t.Position.x, t.Position.y, t.Position.z + t.Sector.CeilHeight); Vector3D v2 = new Vector3D( point.x + perpendicular.x, point.y + perpendicular.y, t.Position.z + t.Sector.CeilHeight + Math.Cos(vangle) ); Vector3D v3 = new Vector3D( point.x - perpendicular.x, point.y - perpendicular.y, t.Position.z + t.Sector.CeilHeight + Math.Cos(vangle) ); SectorData sd = data.Mode.GetSectorData(t.Sector); sd.AddUpdateSector(data.Sector, true); if (!sd.Updated) { sd.Update(); } td.AddUpdateSector(t.Sector, true); sd.Ceiling.plane = new Plane(v1, v2, v3, false); } } }
// This makes sure we are updated with the source linedef information public override void Update() { Sector sourcesector = null; SectorData sourcesectordata = null; bool updatesides = false; // Copy slopes from tagged sectors //check which arguments we must use int floorArg = (front ? 0 : 2); int ceilingArg = (front ? 1 : 3); //find sector to align floor to if (linedef.Args[floorArg] > 0) { foreach (Sector s in General.Map.Map.Sectors) { if (s.Tags.Contains(linedef.Args[floorArg])) { sourcesector = s; break; } } if (sourcesector != null) { sourcesectordata = data.Mode.GetSectorData(sourcesector); if (!sourcesectordata.Updated) { sourcesectordata.Update(); } data.Floor.plane = sourcesectordata.Floor.plane; sourcesectordata.AddUpdateSector(data.Sector, true); updatesides = true; } } if (linedef.Args[ceilingArg] > 0) { //find sector to align ceiling to if (linedef.Args[ceilingArg] != linedef.Args[floorArg]) { sourcesector = null; foreach (Sector s in General.Map.Map.Sectors) { if (s.Tags.Contains(linedef.Args[ceilingArg])) { sourcesector = s; break; } } if (sourcesector != null) { sourcesectordata = data.Mode.GetSectorData(sourcesector); if (!sourcesectordata.Updated) { sourcesectordata.Update(); } data.Ceiling.plane = sourcesectordata.Ceiling.plane; sourcesectordata.AddUpdateSector(data.Sector, true); updatesides = true; } } else if (sourcesector != null) //ceiling uses the same sector as floor { data.Ceiling.plane = sourcesectordata.Ceiling.plane; } } //check the flags... bool copyFloor = false; bool copyCeiling = false; if (linedef.Args[4] > 0 && linedef.Args[4] != 3 && linedef.Args[4] != 12) { if (front) { copyFloor = (linedef.Args[4] & 2) == 2; copyCeiling = (linedef.Args[4] & 8) == 8; } else { copyFloor = (linedef.Args[4] & 1) == 1; copyCeiling = (linedef.Args[4] & 4) == 4; } } // Copy slope across the line if ((copyFloor || copyCeiling) && linedef.Front != null && linedef.Back != null) { // Get appropriate source sector data sourcesectordata = data.Mode.GetSectorData(front ? linedef.Back.Sector : linedef.Front.Sector); if (!sourcesectordata.Updated) { sourcesectordata.Update(); } //copy floor slope? if (copyFloor) { data.Floor.plane = sourcesectordata.Floor.plane; sourcesectordata.AddUpdateSector(data.Sector, true); } //copy ceiling slope? if (copyCeiling) { data.Ceiling.plane = sourcesectordata.Ceiling.plane; sourcesectordata.AddUpdateSector(data.Sector, true); } updatesides = true; } // Update outer sidedef geometry if (updatesides) { UpdateSectorSides(data.Sector); // Update sectors with PlaneCopySlope Effect... List <SectorData> toupdate = new List <SectorData>(); foreach (Sector s in data.UpdateAlso.Keys) { SectorData osd = data.Mode.GetSectorDataEx(s); if (osd == null) { continue; } foreach (SectorEffect e in osd.Effects) { if (e is EffectPlaneCopySlope) { toupdate.Add(osd); break; } } } // Do it in 2 steps, because SectorData.Reset() may change SectorData.UpdateAlso collection... foreach (SectorData sd in toupdate) { // Update PlaneCopySlope Effect... sd.Reset(false); // Update outer sides... UpdateSectorSides(sd.Sector); } } }
// This makes sure we are updated with the source linedef information public override void Update() { //mxd. Skip if arg0 is 0. if (thing.Args[0] == 0) { return; } ThingData td = data.Mode.GetThingData(thing); Thing t = thing; // Find the tagged line Linedef ld = null; foreach (Linedef l in General.Map.Map.Linedefs) { if (l.Tags.Contains(t.Args[0])) { ld = l; break; } } if (ld != null) { if (t.Type == 9500) { // Slope the floor from the linedef to thing t.DetermineSector(data.Mode.BlockMap); if (t.Sector != null) { Vector3D v3 = new Vector3D(t.Position.x, t.Position.y, t.Position.z + t.Sector.FloorHeight); if (ld.SideOfLine(t.Position) < 0.0f) { Vector3D v1 = new Vector3D(ld.Start.Position.x, ld.Start.Position.y, ld.Front.Sector.FloorHeight); Vector3D v2 = new Vector3D(ld.End.Position.x, ld.End.Position.y, ld.Front.Sector.FloorHeight); SectorData sd = data.Mode.GetSectorData(ld.Front.Sector); sd.AddUpdateSector(data.Sector, true); if (!sd.Updated) { sd.Update(); } td.AddUpdateSector(ld.Front.Sector, true); sd.Floor.plane = new Plane(v1, v2, v3, true); } else { Vector3D v1 = new Vector3D(ld.Start.Position.x, ld.Start.Position.y, ld.Back.Sector.FloorHeight); Vector3D v2 = new Vector3D(ld.End.Position.x, ld.End.Position.y, ld.Back.Sector.FloorHeight); SectorData sd = data.Mode.GetSectorData(ld.Back.Sector); sd.AddUpdateSector(data.Sector, true); if (!sd.Updated) { sd.Update(); } td.AddUpdateSector(ld.Back.Sector, true); sd.Floor.plane = new Plane(v2, v1, v3, true); } } } else if (t.Type == 9501) { // Slope the ceiling from the linedef to thing t.DetermineSector(data.Mode.BlockMap); if (t.Sector != null) { td.AddUpdateSector(t.Sector, true); Vector3D v3 = new Vector3D(t.Position.x, t.Position.y, t.Position.z + t.Sector.CeilHeight); if (ld.SideOfLine(t.Position) < 0.0f) { Vector3D v1 = new Vector3D(ld.Start.Position.x, ld.Start.Position.y, ld.Front.Sector.CeilHeight); Vector3D v2 = new Vector3D(ld.End.Position.x, ld.End.Position.y, ld.Front.Sector.CeilHeight); SectorData sd = data.Mode.GetSectorData(ld.Front.Sector); sd.AddUpdateSector(data.Sector, true); td.AddUpdateSector(ld.Front.Sector, true); if (!sd.Updated) { sd.Update(); } sd.Ceiling.plane = new Plane(v1, v2, v3, false); } else { Vector3D v1 = new Vector3D(ld.Start.Position.x, ld.Start.Position.y, ld.Back.Sector.CeilHeight); Vector3D v2 = new Vector3D(ld.End.Position.x, ld.End.Position.y, ld.Back.Sector.CeilHeight); SectorData sd = data.Mode.GetSectorData(ld.Back.Sector); sd.AddUpdateSector(data.Sector, true); td.AddUpdateSector(ld.Back.Sector, true); if (!sd.Updated) { sd.Update(); } sd.Ceiling.plane = new Plane(v2, v1, v3, false); } } } } }
// This (re)builds the visual sector, calculating all geometry from scratch public void Rebuild() { // Forget old geometry base.ClearGeometry(); // Get sector data SectorData data = GetSectorData(); if (!data.Updated) { data.Update(); } // Create floor floor = (floor ?? new VisualFloor(mode, this)); if (floor.Setup(data.Floor, null)) { AddGeometry(floor); } // Create ceiling ceiling = (ceiling ?? new VisualCeiling(mode, this)); if (ceiling.Setup(data.Ceiling, null)) { AddGeometry(ceiling); } // Create 3D floors for (int i = 0; i < data.ExtraFloors.Count; i++) { Effect3DFloor ef = data.ExtraFloors[i]; bool floorRequired = ef.VavoomType; //mxd bool ceilingRequired = ef.VavoomType; //mxd if (ef.VavoomType || !ef.IgnoreBottomHeight) { //mxd. check if 3d floor is between real floor and ceiling if (!ef.VavoomType) { if (ef.Ceiling.plane.GetInverted().Normal != floor.Level.plane.Normal || ef.Ceiling.plane.Normal != ceiling.Level.plane.Normal) { //mxd. check if at least one vertex of 3d floor is between floor and ceiling floorRequired = Check3dFloorPlane(floor.Vertices, ceiling.Vertices, ef.Ceiling.plane); } //if floor, ceiling and 3d floor are not sloped, compare offsets else if (-floor.Level.plane.Offset < ef.Ceiling.plane.Offset && ceiling.Level.plane.Offset > ef.Ceiling.plane.Offset) { floorRequired = true; } } //mxd. Create a floor if (floorRequired && ef.Ceiling.sector.IsDisposed == false) { VisualFloor vf = (i < extrafloors.Count) ? extrafloors[i] : new VisualFloor(mode, this); if (vf.Setup(ef.Ceiling, ef)) { base.AddGeometry(vf); //mxd. add backside as well if (!ef.VavoomType && ef.RenderInside) { VisualFloor vfb = (i < extrabackfloors.Count) ? extrabackfloors[i] : new VisualFloor(mode, this); if (vfb.Setup(ef.Ceiling, ef, true)) { base.AddGeometry(vfb); } if (i >= extrabackfloors.Count) { extrabackfloors.Add(vfb); } } } if (i >= extrafloors.Count) { extrafloors.Add(vf); } } } //mxd. check if 3d ceiling is between real floor and ceiling if (!ef.VavoomType) { if (ef.Floor.plane.GetInverted().Normal != ceiling.Level.plane.Normal || ef.Floor.plane.Normal != floor.Level.plane.Normal) { //mxd. check if at least one vertex of 3d ceiling is between floor and ceiling ceilingRequired = Check3dFloorPlane(floor.Vertices, ceiling.Vertices, ef.Floor.plane); } //if floor, ceiling and 3d ceiling are not sloped, compare offsets else if (ceiling.Level.plane.Offset > -ef.Floor.plane.Offset && floor.Level.plane.Offset > ef.Floor.plane.Offset) { ceilingRequired = true; } } //mxd. Create a ceiling if (ceilingRequired && ef.Floor.sector.IsDisposed == false) { VisualCeiling vc = (i < extraceilings.Count) ? extraceilings[i] : new VisualCeiling(mode, this); if (vc.Setup(ef.Floor, ef)) { base.AddGeometry(vc); //mxd. add backside as well if (!ef.VavoomType && (ef.RenderInside || ef.IgnoreBottomHeight)) { VisualCeiling vcb = (i < extrabackceilings.Count) ? extrabackceilings[i] : new VisualCeiling(mode, this); if (vcb.Setup(ef.Floor, ef, true)) { base.AddGeometry(vcb); } if (i >= extrabackceilings.Count) { extrabackceilings.Add(vcb); } } } if (i >= extraceilings.Count) { extraceilings.Add(vc); } } } // Go for all sidedefs Dictionary <Sidedef, VisualSidedefParts> oldsides = sides ?? new Dictionary <Sidedef, VisualSidedefParts>(1); sides = new Dictionary <Sidedef, VisualSidedefParts>(base.Sector.Sidedefs.Count); foreach (Sidedef sd in base.Sector.Sidedefs) { // VisualSidedef already exists? VisualSidedefParts parts = oldsides.ContainsKey(sd) ? oldsides[sd] : new VisualSidedefParts(); // Doublesided or singlesided? if (sd.Other != null && sd.Line.IsFlagSet(General.Map.Config.DoubleSidedFlag)) { // Create upper part VisualUpper vu = parts.upper ?? new VisualUpper(mode, this, sd); if (vu.Setup()) { base.AddGeometry(vu); } // Create lower part VisualLower vl = parts.lower ?? new VisualLower(mode, this, sd); if (vl.Setup()) { base.AddGeometry(vl); } // Create middle part VisualMiddleDouble vm = parts.middledouble ?? new VisualMiddleDouble(mode, this, sd); if (vm.Setup()) { base.AddGeometry(vm); } //mxd. Create fog boundary VisualFogBoundary vb = parts.fogboundary ?? new VisualFogBoundary(mode, this, sd); if (vb.Setup()) { vm.FogFactor = 0; // Avoid double-fogging the middle part base.AddGeometry(vb); } // Create 3D wall parts SectorData osd = mode.GetSectorData(sd.Other.Sector); if (!osd.Updated) { osd.Update(); } List <VisualMiddle3D> middles = parts.middle3d ?? new List <VisualMiddle3D>(osd.ExtraFloors.Count); for (int i = 0; i < osd.ExtraFloors.Count; i++) { Effect3DFloor ef = osd.ExtraFloors[i]; if (!ef.VavoomType && ef.IgnoreBottomHeight) { continue; //mxd } VisualMiddle3D vm3 = (i < middles.Count) ? middles[i] : new VisualMiddle3D(mode, this, sd); if (vm3.Setup(ef)) { base.AddGeometry(vm3); } if (i >= middles.Count) { middles.Add(vm3); } } //mxd. Create backsides List <VisualMiddleBack> middlebacks = new List <VisualMiddleBack>(); for (int i = 0; i < data.ExtraFloors.Count; i++) { Effect3DFloor ef = data.ExtraFloors[i]; if (!ef.VavoomType && ef.RenderInside && !ef.IgnoreBottomHeight) { VisualMiddleBack vms = new VisualMiddleBack(mode, this, sd); if (vms.Setup(ef)) { base.AddGeometry(vms); } middlebacks.Add(vms); } } // Store sides.Add(sd, new VisualSidedefParts(vu, vl, vm, vb, middles, middlebacks)); } else { // Create middle part VisualMiddleSingle vm = parts.middlesingle ?? new VisualMiddleSingle(mode, this, sd); if (vm.Setup()) { base.AddGeometry(vm); } // Store sides.Add(sd, new VisualSidedefParts(vm)); } } // Done changed = false; }
// This makes sure we are updated with the source linedef information public override void Update() { SectorData sd = data.Mode.GetSectorData(linedef.Front.Sector); if (!sd.Updated) { sd.Update(); } sd.AddUpdateSector(data.Sector, true); if (floor == null) { floor = new SectorLevel(sd.Floor); data.AddSectorLevel(floor); } if (ceiling == null) { ceiling = new SectorLevel(sd.Ceiling); data.AddSectorLevel(ceiling); } // For non-vavoom types, we must switch the level types if (linedef.Args[1] != (int)FloorTypes.VavoomStyle) { //mxd. check for Swimmable/RenderInside/RenderAdditive flags renderadditive = (linedef.Args[2] & (int)Flags.RenderAdditive) == (int)Flags.RenderAdditive; renderinside = ((((linedef.Args[1] & (int)FloorTypes.Swimmable) == (int)FloorTypes.Swimmable) && (linedef.Args[1] & (int)FloorTypes.NonSolid) != (int)FloorTypes.NonSolid)) || ((linedef.Args[1] & (int)FloorTypes.RenderInside) == (int)FloorTypes.RenderInside); ignorebottomheight = ((linedef.Args[2] & (int)Flags.IgnoreBottomHeight) == (int)Flags.IgnoreBottomHeight); vavoomtype = false; alpha = General.Clamp(linedef.Args[3], 0, 255); sd.Ceiling.CopyProperties(floor); sd.Floor.CopyProperties(ceiling); floor.type = SectorLevelType.Floor; floor.plane = sd.Ceiling.plane.GetInverted(); ceiling.type = SectorLevelType.Ceiling; ceiling.plane = (ignorebottomheight ? sd.Ceiling.plane : sd.Floor.plane.GetInverted()); //mxd. Use upper plane when "ignorebottomheight" flag is set //mxd clipsides = (!renderinside && !renderadditive && alpha > 254 && !ignorebottomheight); // A 3D floor's color is always that of the sector it is placed in // (unless it's affected by glow) - mxd if (sd.CeilingGlow == null || !sd.CeilingGlow.Fullbright) { floor.color = 0; } } else { vavoomtype = true; renderadditive = false; //mxd clipsides = true; //mxd floor.type = SectorLevelType.Ceiling; floor.plane = sd.Ceiling.plane; ceiling.type = SectorLevelType.Floor; ceiling.plane = sd.Floor.plane; alpha = 255; // A 3D floor's color is always that of the sector it is placed in // (unless it's affected by glow) - mxd if (sd.FloorGlow == null || !sd.FloorGlow.Fullbright) { ceiling.color = 0; } } // Apply alpha floor.alpha = alpha; ceiling.alpha = alpha; //mxd floor.extrafloor = true; ceiling.extrafloor = true; floor.splitsides = !clipsides; ceiling.splitsides = (!clipsides && !ignorebottomheight); // if "ignorebottomheight" flag is set, both ceiling and floor will be at the same level and sidedef clipping with floor level will fail resulting in incorrect light props transfer in some cases //mxd. Check slopes, cause GZDoom can't handle sloped translucent 3d floors... sloped3dfloor = ((alpha < 255 || renderadditive) && (Angle2D.RadToDeg(ceiling.plane.Normal.GetAngleZ()) != 270 || Angle2D.RadToDeg(floor.plane.Normal.GetAngleZ()) != 90)); // Do not adjust light? (works only for non-vavoom types) if (!vavoomtype) { bool disablelighting = ((linedef.Args[2] & (int)Flags.DisableLighting) == (int)Flags.DisableLighting); //mxd bool restrictlighting = ((linedef.Args[2] & (int)Flags.RestrictLighting) == (int)Flags.RestrictLighting); //mxd floor.resetlighting = ((linedef.Args[2] & (int)Flags.ResetLighting) == (int)Flags.ResetLighting); //mxd if (disablelighting || restrictlighting) { floor.restrictlighting = restrictlighting; //mxd floor.disablelighting = disablelighting; //mxd if (disablelighting) //mxd { floor.color = 0; floor.brightnessbelow = -1; floor.colorbelow = PixelColor.FromInt(0); } ceiling.disablelighting = disablelighting; //mxd ceiling.restrictlighting = restrictlighting; //mxd ceiling.color = 0; ceiling.brightnessbelow = -1; ceiling.colorbelow = PixelColor.FromInt(0); } } }