diff --git a/Source/Core/Builder.csproj b/Source/Core/Builder.csproj index 8ceb3ead..6cf6e8e6 100644 --- a/Source/Core/Builder.csproj +++ b/Source/Core/Builder.csproj @@ -1085,6 +1085,7 @@ + diff --git a/Source/Core/Data/DataManager.cs b/Source/Core/Data/DataManager.cs index 22501990..19d439fd 100644 --- a/Source/Core/Data/DataManager.cs +++ b/Source/Core/Data/DataManager.cs @@ -91,6 +91,7 @@ namespace CodeImp.DoomBuilder.Data private ImageData crosshairbusy; private Dictionary internalsprites; private ImageData whitetexture; + private ImageData blacktexture; //mxd //mxd. Comment icons private ImageData[] commenttextures; @@ -137,6 +138,7 @@ namespace CodeImp.DoomBuilder.Data public ImageData Crosshair3D { get { return crosshair; } } public ImageData CrosshairBusy3D { get { return crosshairbusy; } } public ImageData WhiteTexture { get { return whitetexture; } } + public ImageData BlackTexture { get { return blacktexture; } } //mxd public ImageData[] CommentTextures { get { return commenttextures; } } //mxd public List ThingCategories { get { return thingcategories; } } public ICollection ThingTypes { get { return thingtypes.Values; } } @@ -183,10 +185,12 @@ namespace CodeImp.DoomBuilder.Data crosshair.LoadImage(); crosshairbusy = new ResourceImage("CodeImp.DoomBuilder.Resources.CrosshairBusy.png"); crosshairbusy.LoadImage(); - whitetexture = new ResourceImage("CodeImp.DoomBuilder.Resources.White.png"); - whitetexture.UseColorCorrection = false; + whitetexture = new ResourceImage("CodeImp.DoomBuilder.Resources.White.png") { UseColorCorrection = false }; whitetexture.LoadImage(); whitetexture.CreateTexture(); + blacktexture = new ResourceImage("CodeImp.DoomBuilder.Resources.Black.png") { UseColorCorrection = false }; //mxd + blacktexture.LoadImage(); //mxd + blacktexture.CreateTexture(); //mxd unknownimage = new UnknownImage(Properties.Resources.UnknownImage); //mxd. There should be only one! //mxd. Create comment icons @@ -227,6 +231,8 @@ namespace CodeImp.DoomBuilder.Data crosshairbusy = null; whitetexture.Dispose(); whitetexture = null; + blacktexture.Dispose(); //mxd + blacktexture = null; //mxd unknownimage.Dispose(); //mxd unknownimage = null; //mxd foreach(ImageData i in commenttextures) i.Dispose(); //mxd diff --git a/Source/Core/Data/TexturePatch.cs b/Source/Core/Data/TexturePatch.cs index dbc0c9e9..cded1586 100644 --- a/Source/Core/Data/TexturePatch.cs +++ b/Source/Core/Data/TexturePatch.cs @@ -97,11 +97,15 @@ namespace CodeImp.DoomBuilder.Data //mxd. Check data so we don't perform unneeded operations later on if(this.alpha == 1.0f) { - if(this.style == TexturePathRenderStyle.Blend - || this.style == TexturePathRenderStyle.CopyAlpha - || this.style == TexturePathRenderStyle.CopyNewAlpha - || this.style == TexturePathRenderStyle.Overlay) - this.style = TexturePathRenderStyle.Copy; + switch(this.style) + { + case TexturePathRenderStyle.Blend: + case TexturePathRenderStyle.CopyAlpha: + case TexturePathRenderStyle.CopyNewAlpha: + case TexturePathRenderStyle.Overlay: + this.style = TexturePathRenderStyle.Copy; + break; + } } //mxd. and get rid of render styles we don't support diff --git a/Source/Core/Geometry/LinedefSide.cs b/Source/Core/Geometry/LinedefSide.cs index 8d797b4f..8999123f 100644 --- a/Source/Core/Geometry/LinedefSide.cs +++ b/Source/Core/Geometry/LinedefSide.cs @@ -90,7 +90,7 @@ namespace CodeImp.DoomBuilder.Geometry { if((object.Equals(a, null)) && (object.Equals(b, null))) return true; if((!object.Equals(a, null)) && (object.Equals(b, null))) return false; - if((object.Equals(a, null)) && (!object.Equals(b, null))) return false; + if(object.Equals(a, null)) return false; return (a.line == b.line) && (a.front == b.front); } @@ -99,7 +99,7 @@ namespace CodeImp.DoomBuilder.Geometry { if((object.Equals(a, null)) && (object.Equals(b, null))) return false; if((!object.Equals(a, null)) && (object.Equals(b, null))) return true; - if((object.Equals(a, null)) && (!object.Equals(b, null))) return true; + if(object.Equals(a, null)) return true; return (a.line != b.line) || (a.front != b.front); } diff --git a/Source/Core/Resources/Black.png b/Source/Core/Resources/Black.png new file mode 100644 index 00000000..66af9b21 Binary files /dev/null and b/Source/Core/Resources/Black.png differ diff --git a/Source/Core/VisualModes/VisualGeometry.cs b/Source/Core/VisualModes/VisualGeometry.cs index d9b95d6d..7bd2e2e2 100644 --- a/Source/Core/VisualModes/VisualGeometry.cs +++ b/Source/Core/VisualModes/VisualGeometry.cs @@ -88,7 +88,7 @@ namespace CodeImp.DoomBuilder.VisualModes //mxd public Vector3D[] BoundingBox { get { return boundingBox; } } public VisualGeometryType GeometryType { get { return geometrytype; } } - public float FogFactor { get { return fogfactor; } } + public float FogFactor { get { return fogfactor; } set { fogfactor = value; } } /// /// Render pass in which this geometry must be rendered. Default is Solid. @@ -165,9 +165,9 @@ namespace CodeImp.DoomBuilder.VisualModes } //mxd. Normals calculation algorithm taken from OpenGl wiki - protected void CalculateNormals() + private void CalculateNormals() { - if (triangles == 0) return; + if(triangles == 0) return; int startIndex; Vector3 U, V; @@ -281,6 +281,7 @@ namespace CodeImp.DoomBuilder.VisualModes WALL_MIDDLE, WALL_MIDDLE_3D, WALL_LOWER, + FOG_BOUNDARY, UNKNOWN, } } diff --git a/Source/Plugins/BuilderModes/BuilderModes.csproj b/Source/Plugins/BuilderModes/BuilderModes.csproj index 526fc3bd..44598956 100644 --- a/Source/Plugins/BuilderModes/BuilderModes.csproj +++ b/Source/Plugins/BuilderModes/BuilderModes.csproj @@ -416,6 +416,7 @@ + diff --git a/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs b/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs index b6c67b1d..8ec4eb67 100644 --- a/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs +++ b/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs @@ -391,7 +391,7 @@ namespace CodeImp.DoomBuilder.BuilderModes internal BaseVisualSector CreateBaseVisualSector(Sector s) { BaseVisualSector vs = new BaseVisualSector(this, s); - if(vs != null) allsectors.Add(s, vs); + allsectors.Add(s, vs); return vs; } @@ -399,7 +399,7 @@ namespace CodeImp.DoomBuilder.BuilderModes protected override VisualSector CreateVisualSector(Sector s) { BaseVisualSector vs = new BaseVisualSector(this, s); - if (vs != null) allsectors.Add(s, vs); //mxd + allsectors.Add(s, vs); //mxd return vs; } @@ -824,7 +824,8 @@ namespace CodeImp.DoomBuilder.BuilderModes // Find all sector who's tag is not 0 and hash them so that we can find them quicly foreach(Sector s in General.Map.Map.Sectors) { - foreach (int tag in s.Tags) + s.UpdateFogColor(); //mxd. Also update fog color + foreach(int tag in s.Tags) { if(tag == 0) continue; if(!sectortags.ContainsKey(tag)) sectortags[tag] = new List(); diff --git a/Source/Plugins/BuilderModes/VisualModes/BaseVisualSector.cs b/Source/Plugins/BuilderModes/VisualModes/BaseVisualSector.cs index 3e54568b..902ca971 100644 --- a/Source/Plugins/BuilderModes/VisualModes/BaseVisualSector.cs +++ b/Source/Plugins/BuilderModes/VisualModes/BaseVisualSector.cs @@ -74,9 +74,8 @@ namespace CodeImp.DoomBuilder.BuilderModes this.mode = mode; this.extrafloors = new List(2); this.extraceilings = new List(2); - //mxd - this.extrabackfloors = new List(2); - this.extrabackceilings = new List(2); + this.extrabackfloors = new List(2); //mxd + this.extrabackceilings = new List(2); //mxd // Initialize Rebuild(); @@ -319,6 +318,14 @@ namespace CodeImp.DoomBuilder.BuilderModes // 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); @@ -336,20 +343,20 @@ namespace CodeImp.DoomBuilder.BuilderModes //mxd. Create backsides List middlebacks = new List(); - for (int i = 0; i < data.ExtraFloors.Count; i++) + for(int i = 0; i < data.ExtraFloors.Count; i++) { Effect3DFloor ef = data.ExtraFloors[i]; - if (!ef.VavoomType && ef.RenderInside && !ef.IgnoreBottomHeight) + if(!ef.VavoomType && ef.RenderInside && !ef.IgnoreBottomHeight) { VisualMiddleBack vms = new VisualMiddleBack(mode, this, sd); - if (vms.Setup(ef)) base.AddGeometry(vms); + if(vms.Setup(ef)) base.AddGeometry(vms); middlebacks.Add(vms); } } // Store - sides.Add(sd, new VisualSidedefParts(vu, vl, vm, middles, middlebacks)); + sides.Add(sd, new VisualSidedefParts(vu, vl, vm, vb, middles, middlebacks)); } else { @@ -369,8 +376,7 @@ namespace CodeImp.DoomBuilder.BuilderModes // This returns the visual sidedef parts for a given sidedef public VisualSidedefParts GetSidedefParts(Sidedef sd) { - if(sides.ContainsKey(sd)) return sides[sd]; - return new VisualSidedefParts(); + return (sides.ContainsKey(sd) ? sides[sd] : new VisualSidedefParts()); } //mxd. Checks if given plane is between given floor and ceiling vertices @@ -381,14 +387,14 @@ namespace CodeImp.DoomBuilder.BuilderModes //check floor for(int c = 0; c < floorverts.Length; c++) { - if (plane.GetZ(new Vector2D(floorverts[c].x, floorverts[c].y)) > Math.Round(floorverts[c].z, 3)) + if(plane.GetZ(new Vector2D(floorverts[c].x, floorverts[c].y)) > Math.Round(floorverts[c].z, 3)) { show = true; break; } } - if (!show) return false; + if(!show) return false; //check ceiling for(int c = 0; c < ceilingverts.Length; c++) diff --git a/Source/Plugins/BuilderModes/VisualModes/Effect3DFloor.cs b/Source/Plugins/BuilderModes/VisualModes/Effect3DFloor.cs index c904f12e..26c00785 100644 --- a/Source/Plugins/BuilderModes/VisualModes/Effect3DFloor.cs +++ b/Source/Plugins/BuilderModes/VisualModes/Effect3DFloor.cs @@ -171,8 +171,8 @@ namespace CodeImp.DoomBuilder.BuilderModes // 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 = (alpha < 255 || renderadditive || renderinside) && ((linedef.Args[2] & (int)Flags.RestrictLighting) == (int)Flags.RestrictLighting); //mxd + bool disablelighting = ((linedef.Args[2] & (int)Flags.DisableLighting) == (int)Flags.DisableLighting); //mxd + bool restrictlighting = ((linedef.Args[2] & (int)Flags.RestrictLighting) == (int)Flags.RestrictLighting); //mxd if(disablelighting || restrictlighting) { diff --git a/Source/Plugins/BuilderModes/VisualModes/VisualCeiling.cs b/Source/Plugins/BuilderModes/VisualModes/VisualCeiling.cs index 7a50aae0..968bd60e 100644 --- a/Source/Plugins/BuilderModes/VisualModes/VisualCeiling.cs +++ b/Source/Plugins/BuilderModes/VisualModes/VisualCeiling.cs @@ -127,7 +127,29 @@ namespace CodeImp.DoomBuilder.BuilderModes else { color = PixelColor.FromInt(level.color).WithAlpha((byte)General.Clamp(level.alpha, 0, 255)).ToInt(); - fogfactor = CalculateFogDensity(level.brightnessbelow); + + //mxd. Top extrafloor level should calculate fogdensity + //from the brightness of the level above it + int targetbrightness; + if(extrafloor != null && !extrafloor.VavoomType && !level.disablelighting) + { + targetbrightness = 0; + SectorData sd = mode.GetSectorData(this.Sector.Sector); + for(int i = 0; i < sd.LightLevels.Count - 1; i++) + { + if(sd.LightLevels[i] == level) + { + targetbrightness = sd.LightLevels[i + 1].brightnessbelow; + break; + } + } + } + else + { + targetbrightness = level.brightnessbelow; + } + + fogfactor = CalculateFogDensity(targetbrightness); } // Make vertices diff --git a/Source/Plugins/BuilderModes/VisualModes/VisualFloor.cs b/Source/Plugins/BuilderModes/VisualModes/VisualFloor.cs index 84f0a7ac..9107948f 100644 --- a/Source/Plugins/BuilderModes/VisualModes/VisualFloor.cs +++ b/Source/Plugins/BuilderModes/VisualModes/VisualFloor.cs @@ -129,7 +129,29 @@ namespace CodeImp.DoomBuilder.BuilderModes else { color = PixelColor.FromInt(level.color).WithAlpha((byte)General.Clamp(level.alpha, 0, 255)).ToInt(); - fogfactor = CalculateFogDensity(level.brightnessbelow); + + //mxd. Top extrafloor level should calculate fogdensity + //from the brightness of the level above it + int targetbrightness; + if(extrafloor != null && extrafloor.VavoomType && !level.disablelighting) + { + targetbrightness = 0; + SectorData sd = mode.GetSectorData(this.Sector.Sector); + for(int i = 0; i < sd.LightLevels.Count - 1; i++) + { + if(sd.LightLevels[i] == level) + { + targetbrightness = sd.LightLevels[i + 1].brightnessbelow; + break; + } + } + } + else + { + targetbrightness = level.brightnessbelow; + } + + fogfactor = CalculateFogDensity(targetbrightness); } // Make vertices diff --git a/Source/Plugins/BuilderModes/VisualModes/VisualFogBoundary.cs b/Source/Plugins/BuilderModes/VisualModes/VisualFogBoundary.cs new file mode 100644 index 00000000..fc98d5ac --- /dev/null +++ b/Source/Plugins/BuilderModes/VisualModes/VisualFogBoundary.cs @@ -0,0 +1,161 @@ +#region ================== Namespaces + +using System; +using System.Collections.Generic; +using System.Drawing; +using CodeImp.DoomBuilder.Geometry; +using CodeImp.DoomBuilder.Map; +using CodeImp.DoomBuilder.Rendering; +using CodeImp.DoomBuilder.VisualModes; + +#endregion + +namespace CodeImp.DoomBuilder.BuilderModes +{ + internal sealed class VisualFogBoundary : BaseVisualGeometrySidedef + { + #region ================== Variables + + #endregion + + #region ================== Constructor / Setup + + // Constructor + public VisualFogBoundary(BaseVisualMode mode, VisualSector vs, Sidedef s) : base(mode, vs, s) + { + //mxd + geometrytype = VisualGeometryType.FOG_BOUNDARY; + + // Set render pass + this.RenderPass = RenderPass.Additive; + + // We have no destructor + GC.SuppressFinalize(this); + } + + // 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 = CalculateFogDensity(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 polygons = new List { poly }; + + // Keep top and bottom planes for intersection testing + top = osd.Ceiling.plane; + bottom = osd.Floor.plane; + + // Process the polygon and create vertices + List verts = CreatePolygonVertices(polygons, tp, sd, lightvalue, lightabsolute); + if(verts.Count > 2) + { + base.SetVertices(verts); + return true; + } + + base.SetVertices(null); + return false; + } + + #endregion + + #region ================== Methods + + //========================================================================== + // + // Check if the current linedef is a candidate for a fog boundary + // + // Requirements for a fog boundary: + // - front sector has no fog + // - back sector has fog + // - at least one of both does not have a sky ceiling. + // + //========================================================================== + private bool IsFogBoundary() + { + if(Sidedef.Sector.Index == Sidedef.Other.Sector.Index) return false; // There can't be a boundary if both sides are in the same sector. + if(Sidedef.Sector.HasFogColor == Sidedef.Other.Sector.HasFogColor) return false; + if(!Sidedef.Sector.HasFogColor && !Sidedef.Other.Sector.HasFogColor) return false; + if(Sidedef.Sector.CeilTexture == General.Map.Config.SkyFlatName && Sidedef.Other.Sector.CeilTexture == General.Map.Config.SkyFlatName) return false; + return true; + } + + // This performs a fast test in object picking + public override bool PickFastReject(Vector3D from, Vector3D to, Vector3D dir) { return false; } + + // This performs an accurate test for object picking + public override bool PickAccurate(Vector3D from, Vector3D to, Vector3D dir, ref float u_ray) { return false; } + + // Unused + protected override void SetTextureOffsetX(int x) { } + protected override void SetTextureOffsetY(int y) { } + protected override void MoveTextureOffset(Point xy) { } + protected override Point GetTextureOffset() { return Point.Empty; } + + #endregion + } +} diff --git a/Source/Plugins/BuilderModes/VisualModes/VisualSidedefParts.cs b/Source/Plugins/BuilderModes/VisualModes/VisualSidedefParts.cs index 5e48aa76..00934ba7 100644 --- a/Source/Plugins/BuilderModes/VisualModes/VisualSidedefParts.cs +++ b/Source/Plugins/BuilderModes/VisualModes/VisualSidedefParts.cs @@ -30,15 +30,17 @@ namespace CodeImp.DoomBuilder.BuilderModes public readonly VisualMiddleDouble middledouble; public readonly VisualMiddleSingle middlesingle; public readonly List middle3d; - public readonly List middleback;//mxd + public readonly List middleback; //mxd + public readonly VisualFogBoundary fogboundary; //mxd // Constructor - public VisualSidedefParts(VisualUpper u, VisualLower l, VisualMiddleDouble m, List e, List eb) + public VisualSidedefParts(VisualUpper u, VisualLower l, VisualMiddleDouble m, VisualFogBoundary f, List e, List eb) { this.upper = u; this.lower = l; this.middledouble = m; this.middlesingle = null; + this.fogboundary = f; this.middle3d = e; this.middleback = eb; //mxd } @@ -52,6 +54,7 @@ namespace CodeImp.DoomBuilder.BuilderModes this.middlesingle = m; this.middle3d = null; this.middleback = null; //mxd + this.fogboundary = null; //mxd } // This calls Setup() on all parts @@ -60,12 +63,13 @@ namespace CodeImp.DoomBuilder.BuilderModes if(lower != null) lower.Setup(); if(middledouble != null) middledouble.Setup(); if(middlesingle != null) middlesingle.Setup(); + if(fogboundary != null) fogboundary.Setup(); //mxd if(upper != null) upper.Setup(); if(middle3d != null) { foreach(VisualMiddle3D m in middle3d) m.Setup(); } - if(middleback != null) + if(middleback != null) //mxd { foreach(VisualMiddleBack m in middleback) m.Setup(); }