// Disposer public override void Dispose() { // Not already disposed? if (!IsDisposed) { // Clean up sides = null; floor = null; ceiling = null; // Dispose base base.Dispose(); } }
//mxd protected void AlignTextureToClosestLine(bool alignx, bool aligny) { if (!(mode.HighlightedObject is BaseVisualSector)) { return; } // Do we need to align this? (and also grab texture scale while we are at it) float scaleX, scaleY; bool isFloor = (geometrytype == VisualGeometryType.FLOOR); if (mode.HighlightedTarget is VisualFloor) { VisualFloor target = (VisualFloor)mode.HighlightedTarget; // Check texture if (target.Sector.Sector.FloorTexture != (isFloor ? Sector.Sector.FloorTexture : Sector.Sector.CeilTexture)) { return; } scaleX = target.Sector.Sector.Fields.GetValue("xscalefloor", 1.0f); scaleY = target.Sector.Sector.Fields.GetValue("yscalefloor", 1.0f); } else { VisualCeiling target = (VisualCeiling)mode.HighlightedTarget; // Check texture if (target.Sector.Sector.CeilTexture != (isFloor ? Sector.Sector.FloorTexture : Sector.Sector.CeilTexture)) { return; } scaleX = target.Sector.Sector.Fields.GetValue("xscaleceiling", 1.0f); scaleY = target.Sector.Sector.Fields.GetValue("yscaleceiling", 1.0f); } //find a linedef to align to Vector2D hitpos = mode.GetHitPosition(); if (!hitpos.IsFinite()) { return; } //align to line of highlighted sector, which is closest to hitpos Sector highlightedSector = ((BaseVisualSector)mode.HighlightedObject).Sector; List <Linedef> lines = new List <Linedef>(); foreach (Sidedef side in highlightedSector.Sidedefs) { lines.Add(side.Line); } Linedef targetLine = MapSet.NearestLinedef(lines, hitpos); if (targetLine == null) { return; } bool isFront = targetLine.SideOfLine(hitpos) > 0; Sector.Sector.Fields.BeforeFieldsChange(); //find an angle to rotate texture float sourceAngle = (float)Math.Round(General.ClampAngle(isFront ? -Angle2D.RadToDeg(targetLine.Angle) + 90 : -Angle2D.RadToDeg(targetLine.Angle) - 90), 1); if (!isFront) { sourceAngle = General.ClampAngle(sourceAngle + 180); } //update angle UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "rotationfloor" : "rotationceiling"), sourceAngle, 0f); //set scale UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "xscalefloor" : "xscaleceiling"), scaleX, 1.0f); UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "yscalefloor" : "yscaleceiling"), scaleY, 1.0f); //update offset float distToStart = Vector2D.Distance(hitpos, targetLine.Start.Position); float distToEnd = Vector2D.Distance(hitpos, targetLine.End.Position); Vector2D offset = (distToStart < distToEnd ? targetLine.Start.Position : targetLine.End.Position).GetRotated(Angle2D.DegToRad(sourceAngle)); if (alignx) { if (Texture != null && Texture.IsImageLoaded) { offset.x %= Texture.Width / scaleX; } UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "xpanningfloor" : "xpanningceiling"), (float)Math.Round(-offset.x), 0f); } if (aligny) { if (Texture != null && Texture.IsImageLoaded) { offset.y %= Texture.Height / scaleY; } UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "ypanningfloor" : "ypanningceiling"), (float)Math.Round(offset.y), 0f); } //update geometry Sector.UpdateSectorGeometry(false); }
//mxd protected void AlignTextureToClosestLine(bool alignx, bool aligny) { if (!(mode.HighlightedObject is BaseVisualSector)) { return; } // Do we need to align this? (and also grab texture scale while we are at it) float scaleX, scaleY; bool isFloor = (geometrytype == VisualGeometryType.FLOOR); if (mode.HighlightedTarget is VisualFloor) { Sector target; VisualFloor vf = (VisualFloor)mode.HighlightedTarget; // Use the control sector if the floor belongs to a 3D floor if (vf.ExtraFloor == null) { target = vf.Sector.Sector; } else { target = vf.GetControlSector(); } // Check texture if (target.FloorTexture != (isFloor ? Sector.Sector.FloorTexture : Sector.Sector.CeilTexture)) { return; } scaleX = target.Fields.GetValue("xscalefloor", 1.0f); scaleY = target.Fields.GetValue("yscalefloor", 1.0f); } else { Sector target; VisualCeiling vc = (VisualCeiling)mode.HighlightedTarget; // Use the control sector if the ceiling belongs to a 3D floor if (vc.ExtraFloor == null) { target = vc.Sector.Sector; } else { target = vc.GetControlSector(); } // Check texture if (target.CeilTexture != (isFloor ? Sector.Sector.FloorTexture : Sector.Sector.CeilTexture)) { return; } scaleX = target.Fields.GetValue("xscaleceiling", 1.0f); scaleY = target.Fields.GetValue("yscaleceiling", 1.0f); } //find a linedef to align to Vector2D hitpos = mode.GetHitPosition(); if (!hitpos.IsFinite()) { return; } //align to line of highlighted sector, which is closest to hitpos Sector highlightedSector = ((BaseVisualSector)mode.HighlightedObject).Sector; List <Linedef> lines = new List <Linedef>(); foreach (Sidedef side in highlightedSector.Sidedefs) { lines.Add(side.Line); } Linedef targetLine = MapSet.NearestLinedef(lines, hitpos); if (targetLine == null) { return; } bool isFront = targetLine.SideOfLine(hitpos) > 0; Sector.Sector.Fields.BeforeFieldsChange(); //find an angle to rotate texture float sourceAngle = (float)Math.Round(General.ClampAngle(isFront ? -Angle2D.RadToDeg(targetLine.Angle) + 90 : -Angle2D.RadToDeg(targetLine.Angle) - 90), 1); if (!isFront) { sourceAngle = General.ClampAngle(sourceAngle + 180); } //update angle UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "rotationfloor" : "rotationceiling"), sourceAngle, 0f); // Scale texture if it's a slope and the appropriate option is set if (level.plane.Normal.z != 1.0f && BuilderPlug.Me.ScaleTexturesOnSlopes != 2) { Vector2D basescale = new Vector2D(1.0f, 1.0f); // User wants to use the current scale as a base? if (BuilderPlug.Me.ScaleTexturesOnSlopes == 1) { basescale.x = scaleX; basescale.y = scaleY; } // Create a unit vector of the direction of the target line in 3D space Vector3D targetlinevector = new Line3D(new Vector3D(targetLine.Start.Position, level.plane.GetZ(targetLine.Start.Position)), new Vector3D(targetLine.End.Position, level.plane.GetZ(targetLine.End.Position))).GetDelta().GetNormal(); // Get a perpendicular vector of the target line in 3D space. This is used to get the slope angle relative to the target line Vector3D targetlineperpendicular = Vector3D.CrossProduct(targetlinevector, level.plane.Normal); if (alignx) { scaleX = Math.Abs(basescale.x * (1.0f / (float)Math.Cos(targetlinevector.GetAngleZ()))); } if (aligny) { scaleY = Math.Abs(basescale.y * (1.0f / (float)Math.Cos(targetlineperpendicular.GetAngleZ()))); } } //set scale UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "xscalefloor" : "xscaleceiling"), scaleX, 1.0f); UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "yscalefloor" : "yscaleceiling"), scaleY, 1.0f); //update offset float distToStart = Vector2D.Distance(hitpos, targetLine.Start.Position); float distToEnd = Vector2D.Distance(hitpos, targetLine.End.Position); Vector2D offset = (distToStart < distToEnd ? targetLine.Start.Position : targetLine.End.Position).GetRotated(Angle2D.DegToRad(sourceAngle)); if (alignx) { if (Texture != null && Texture.IsImageLoaded) { offset.x %= Texture.Width / scaleX; } UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "xpanningfloor" : "xpanningceiling"), (float)Math.Round(-offset.x), 0f); } if (aligny) { if (Texture != null && Texture.IsImageLoaded) { offset.y %= Texture.Height / scaleY; } UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "ypanningfloor" : "ypanningceiling"), (float)Math.Round(offset.y), 0f); } //update geometry Sector.UpdateSectorGeometry(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 (re)builds the visual sector, calculating all geometry from scratch public void Rebuild() { // Forget old geometry base.ClearGeometry(); // Create floor if (floor == null) { floor = new VisualFloor(mode, this); } floor.Setup(); base.AddGeometry(floor); // Create ceiling if (ceiling == null) { ceiling = new VisualCeiling(mode, this); } ceiling.Setup(); base.AddGeometry(ceiling); // 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) { // Create upper part VisualUpper vu = parts.upper ?? new VisualUpper(mode, this, sd); vu.Setup(); base.AddGeometry(vu); // Create lower part VisualLower vl = parts.lower ?? new VisualLower(mode, this, sd); vl.Setup(); base.AddGeometry(vl); // Create middle part VisualMiddleDouble vm = parts.middledouble ?? new VisualMiddleDouble(mode, this, sd); vm.Setup(); base.AddGeometry(vm); // Store sides.Add(sd, new VisualSidedefParts(vu, vl, vm)); } else { // Create middle part VisualMiddleSingle vm = parts.middlesingle ?? new VisualMiddleSingle(mode, this, sd); vm.Setup(); base.AddGeometry(vm); // Store sides.Add(sd, new VisualSidedefParts(vm)); } } // Done changed = false; }