diff --git a/Build/Configurations/Includes/Eternity_common.cfg b/Build/Configurations/Includes/Eternity_common.cfg index 58a5e993c5c6b413dec58f51d0e482ea444ae1f8..bd636a084c8b3b690398c0e81db44400fd4df2ea 100755 --- a/Build/Configurations/Includes/Eternity_common.cfg +++ b/Build/Configurations/Includes/Eternity_common.cfg @@ -245,6 +245,9 @@ mapformat_udmf // Enabled setting brightness for upper, middle, and lower sidedef independently from each other distinctsidedefpartbrightness = true; + + // Enables support for skewing sidedef textures + sidedeftextureskewing = true; // Default nodebuilder configurations defaultsavecompiler = "zdbsp_udmf_normal"; diff --git a/Source/Core/Config/GameConfiguration.cs b/Source/Core/Config/GameConfiguration.cs index b16bc22edd429405dc581613c402a17ebf4df1df..0b6d391388f017c0e2d1cc0643708180fce1fa28 100755 --- a/Source/Core/Config/GameConfiguration.cs +++ b/Source/Core/Config/GameConfiguration.cs @@ -114,6 +114,7 @@ namespace CodeImp.DoomBuilder.Config private readonly bool distinctwallbrightness; private readonly bool distinctsidedefpartbrightness; private readonly bool sectormultitag; + private readonly bool sidedeftextureskewing; // Skills private readonly List<SkillInfo> skills; @@ -293,6 +294,7 @@ namespace CodeImp.DoomBuilder.Config public bool DistinctWallBrightness { get { return distinctwallbrightness; } } public bool DistinctSidedefPartBrightness { get { return distinctsidedefpartbrightness; } } public bool SectorMultiTag { get { return sectormultitag; } } + public bool SidedefTextureSkewing { get { return sidedeftextureskewing; } } // Texture/flat/voxel sources public IDictionary TextureRanges { get { return textureranges; } } @@ -470,6 +472,7 @@ namespace CodeImp.DoomBuilder.Config localsidedeftextureoffsets = (cfg.ReadSetting("localsidedeftextureoffsets", false)); //MaxW effect3dfloorsupport = cfg.ReadSetting("effect3dfloorsupport", false); planeequationsupport = cfg.ReadSetting("planeequationsupport", false); + sidedeftextureskewing = cfg.ReadSetting("sidedeftextureskewing", false); distinctfloorandceilingbrightness = cfg.ReadSetting("distinctfloorandceilingbrightness", false); distinctwallbrightness = cfg.ReadSetting("distinctwallbrightness", false); distinctsidedefpartbrightness = cfg.ReadSetting("distinctsidedefpartbrightness", false); diff --git a/Source/Core/Rendering/RenderDevice.cs b/Source/Core/Rendering/RenderDevice.cs index a781ce781c0d4c4f529db72e026c53d0af978a80..3042db8cb06385cdef0b8abe66f2b02511abab19 100755 --- a/Source/Core/Rendering/RenderDevice.cs +++ b/Source/Core/Rendering/RenderDevice.cs @@ -77,6 +77,8 @@ namespace CodeImp.DoomBuilder.Rendering DeclareUniform(UniformName.doomlightlevels, "doomlightlevels", UniformType.Int); DeclareUniform(UniformName.sectorLightLevel, "sectorLightLevel", UniformType.Int); + DeclareUniform(UniformName.skew, "skew", UniformType.Vec2f); + // 2d fsaa CompileShader(ShaderName.display2d_fsaa, "display2d.shader", "display2d_fsaa"); @@ -804,7 +806,8 @@ namespace CodeImp.DoomBuilder.Rendering drawPaletted, colormapSize, sectorLightLevel, - doomlightlevels + doomlightlevels, + skew } public enum VertexFormat : int { Flat, World } diff --git a/Source/Core/Rendering/Renderer3D.cs b/Source/Core/Rendering/Renderer3D.cs index 5c2bc27da291e3c093eaf0b6a7bd4596cb9a6e6a..d6ba50c703e874954d3875a6fcd660db6bafc7b3 100755 --- a/Source/Core/Rendering/Renderer3D.cs +++ b/Source/Core/Rendering/Renderer3D.cs @@ -974,6 +974,9 @@ namespace CodeImp.DoomBuilder.Rendering // [ZZ] include desaturation factor graphics.SetUniform(UniformName.desaturation, (float)sector.Sector.Desaturation); + // Skew + graphics.SetUniform(UniformName.skew, g.Skew); + // Render! graphics.Draw(PrimitiveType.TriangleList, g.VertexOffset, g.Triangles); } diff --git a/Source/Core/Resources/world3d.shader b/Source/Core/Resources/world3d.shader index 1ef9944ad474c618eb719dd7726a55d82ed739f9..25d5e23d51347c61fc117dfeca34dbc2a60ab1e9 100755 --- a/Source/Core/Resources/world3d.shader +++ b/Source/Core/Resources/world3d.shader @@ -36,6 +36,9 @@ uniforms // Slope handle length float slopeHandleLength; + // Skewing + vec2 skew; // the x component is used to negate the texture offset for the skew computation. There must be a better way + } functions @@ -223,7 +226,7 @@ shader world3d_main fragment { - vec4 tcolor = texture(texture1, v2f.UV); + vec4 tcolor = texture(texture1, v2f.UV + vec2(0.0, (v2f.UV.x - skew.x) * skew.y)); tcolor = mix(tcolor, vec4(stencilColor.rgb, tcolor.a), stencilColor.a); tcolor = getDynLightContribution(tcolor, v2f.Color, v2f.PosW, v2f.Normal); out.FragColor = desaturate(tcolor); @@ -240,7 +243,7 @@ shader world3d_fullbright extends world3d_main { fragment { - vec4 tcolor = texture(texture1, v2f.UV); + vec4 tcolor = texture(texture1, v2f.UV + vec2(0.0, (v2f.UV.x - skew.x) * skew.y)); tcolor = mix(tcolor, vec4(stencilColor.rgb, tcolor.a), stencilColor.a); tcolor.a *= v2f.Color.a; out.FragColor = tcolor; @@ -257,7 +260,7 @@ shader world3d_main_highlight extends world3d_main { fragment { - vec4 tcolor = texture(texture1, v2f.UV); + vec4 tcolor = texture(texture1, v2f.UV + vec2(0.0, (v2f.UV.x - skew.x) * skew.y)); tcolor = mix(tcolor, vec4(stencilColor.rgb, tcolor.a), stencilColor.a); tcolor = getDynLightContribution(tcolor, v2f.Color, v2f.PosW, v2f.Normal); if (tcolor.a == 0.0) @@ -284,7 +287,7 @@ shader world3d_fullbright_highlight extends world3d_fullbright { fragment { - vec4 tcolor = texture(texture1, v2f.UV); + vec4 tcolor = texture(texture1, v2f.UV + vec2(0.0, (v2f.UV.x - skew.x) * skew.y)); tcolor = mix(tcolor, vec4(stencilColor.rgb, tcolor.a), stencilColor.a); if(tcolor.a == 0.0) { @@ -362,7 +365,7 @@ shader world3d_main_fog extends world3d_main { fragment { - vec4 tcolor = texture(texture1, v2f.UV); + vec4 tcolor = texture(texture1, v2f.UV + vec2(0.0, (v2f.UV.x - skew.x) * skew.y)); tcolor = mix(tcolor, vec4(stencilColor.rgb, tcolor.a), stencilColor.a); tcolor = getDynLightContribution(tcolor, v2f.Color, v2f.PosW, v2f.Normal); if (tcolor.a == 0.0) @@ -386,7 +389,7 @@ shader world3d_main_highlight_fog extends world3d_main_fog { fragment { - vec4 tcolor = texture(texture1, v2f.UV); + vec4 tcolor = texture(texture1, v2f.UV + vec2(0.0, (v2f.UV.x - skew.x) * skew.y)); tcolor = mix(tcolor, vec4(stencilColor.rgb, tcolor.a), stencilColor.a); tcolor = vec4(getDynLightContribution(tcolor, v2f.Color, v2f.PosW, v2f.Normal).rgb, tcolor.a); if (tcolor.a == 0.0) @@ -458,7 +461,7 @@ shader world3d_classic extends world3d_main if (bool(drawPaletted)) { - vec4 color = texture(texture1, v2f.UV); + vec4 color = texture(texture1, v2f.UV + vec2(0.0, (v2f.UV.x - skew.x) * skew.y)); int entry = int(color.r * 255); float alpha = color.a; int lightLevel = lightLevelFromVertexColor(v2f.flatColor.rgb); @@ -487,7 +490,7 @@ shader world3d_classic_highlight extends world3d_main if (bool(drawPaletted)) { - vec4 color = texture(texture1, v2f.UV); + vec4 color = texture(texture1, v2f.UV + vec2(0.0, (v2f.UV.x - skew.x) * skew.y)); int entry = int(color.r * 255); float alpha = color.a; int lightLevel = lightLevelFromVertexColor(v2f.flatColor.rgb); diff --git a/Source/Core/VisualModes/VisualGeometry.cs b/Source/Core/VisualModes/VisualGeometry.cs index 3ba6977f9d45633848d49951f8c3435bd948e31e..c43f2be8bbc712a92db4567a6a7cbdd04b0456e3 100755 --- a/Source/Core/VisualModes/VisualGeometry.cs +++ b/Source/Core/VisualModes/VisualGeometry.cs @@ -76,6 +76,8 @@ namespace CodeImp.DoomBuilder.VisualModes protected VisualGeometryType geometrytype; protected string partname; //UDMF part name protected bool renderassky; + + protected Vector2f skew; #endregion @@ -117,6 +119,11 @@ namespace CodeImp.DoomBuilder.VisualModes /// </summary> public bool Selected { get { return selected; } set { selected = value; } } + /// <summary> + /// How much a texture is skewed. + /// </summary> + public Vector2f Skew { get { return skew; } } + #endregion #region ================== Constructor / Destructor @@ -128,6 +135,7 @@ namespace CodeImp.DoomBuilder.VisualModes { this.sector = vs; this.geometrytype = VisualGeometryType.UNKNOWN; //mxd + skew = new Vector2f(0.0f); } /// <summary> @@ -138,6 +146,7 @@ namespace CodeImp.DoomBuilder.VisualModes this.sector = vs; this.sidedef = sd; this.geometrytype = VisualGeometryType.UNKNOWN; //mxd + skew = new Vector2f(0.0f); } #endregion diff --git a/Source/Plugins/BuilderModes/VisualModes/VisualLower.cs b/Source/Plugins/BuilderModes/VisualModes/VisualLower.cs index 325d38549e77ec5c1c39814cb5f60dcb3f06cacc..2d4d93c320b11ee099eaea91cff0758a44772968 100755 --- a/Source/Plugins/BuilderModes/VisualModes/VisualLower.cs +++ b/Source/Plugins/BuilderModes/VisualModes/VisualLower.cs @@ -19,6 +19,7 @@ using System; using System.Collections.Generic; using System.Drawing; +using System.Linq; using CodeImp.DoomBuilder.Map; using CodeImp.DoomBuilder.Geometry; using CodeImp.DoomBuilder.Rendering; @@ -127,7 +128,7 @@ namespace CodeImp.DoomBuilder.BuilderModes base.Texture = General.Map.Data.MissingTexture3D; setuponloadedtexture = 0; } - + // Get texture scaled size. Round up, because that's apparently what GZDoom does Vector2D tsz = new Vector2D(Math.Ceiling(base.Texture.ScaledWidth / tscale.x), Math.Ceiling(base.Texture.ScaledHeight / tscale.y)); @@ -229,6 +230,10 @@ namespace CodeImp.DoomBuilder.BuilderModes if(verts.Count > 2) { base.SetVertices(verts); + + // Set skewing + UpdateSkew(); + return true; } } @@ -318,7 +323,63 @@ namespace CodeImp.DoomBuilder.BuilderModes FitTexture(options); Setup(); } - + + /// <summary> + /// Updates the value for texture skewing. Has to be done after the texture is set. + /// </summary> + public void UpdateSkew() + { + // Reset + skew = new Vector2f(0.0f); + + if (!General.Map.Config.SidedefTextureSkewing) + return; + + string skewtype = Sidedef.Fields.GetValue("skew_bottom_type", "none"); + + if ((skewtype == "front" || skewtype == "back") && Texture != null) + { + double leftz, rightz; + + if (skewtype == "front") + { + if (Sidedef.IsFront) + { + Plane plane = Sector.GetSectorData().Floor.plane; + leftz = plane.GetZ(Sidedef.Line.Start.Position); + rightz = plane.GetZ(Sidedef.Line.End.Position); + } + else + { + Plane plane = mode.GetSectorData(Sidedef.Other.Sector).Floor.plane; + leftz = plane.GetZ(Sidedef.Line.End.Position); + rightz = plane.GetZ(Sidedef.Line.Start.Position); + } + } + else // "back" + { + if (Sidedef.IsFront) + { + Plane plane = mode.GetSectorData(Sidedef.Other.Sector).Floor.plane; + leftz = plane.GetZ(Sidedef.Line.Start.Position); + rightz = plane.GetZ(Sidedef.Line.End.Position); + } + else + { + Plane plane = Sector.GetSectorData().Floor.plane; + leftz = plane.GetZ(Sidedef.Line.End.Position); + rightz = plane.GetZ(Sidedef.Line.Start.Position); + } + + } + + skew = new Vector2f( + Vertices.Min(v => v.u), // Get the lowest horizontal texture offset + (float)((rightz - leftz) / Sidedef.Line.Length * ((double)Texture.Width / Texture.Height)) + ); + } + } + #endregion } } diff --git a/Source/Plugins/BuilderModes/VisualModes/VisualMiddleDouble.cs b/Source/Plugins/BuilderModes/VisualModes/VisualMiddleDouble.cs index 7f3069462f93f7dac94e0971c97e115ec89737f0..9fbd32641468a7160c478d8c9f0334f70e9efab5 100755 --- a/Source/Plugins/BuilderModes/VisualModes/VisualMiddleDouble.cs +++ b/Source/Plugins/BuilderModes/VisualModes/VisualMiddleDouble.cs @@ -19,6 +19,7 @@ using System; using System.Collections.Generic; using System.Drawing; +using System.Linq; using CodeImp.DoomBuilder.Map; using CodeImp.DoomBuilder.Geometry; using CodeImp.DoomBuilder.Rendering; @@ -231,8 +232,15 @@ namespace CodeImp.DoomBuilder.BuilderModes double 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); + if (General.Map.Config.SidedefTextureSkewing) + { + (topclipplane, bottomclipplane) = CreateSkewClipPlanes(textop, texbottom, sd, osd); + } + else + { + 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); @@ -267,6 +275,10 @@ namespace CodeImp.DoomBuilder.BuilderModes } base.SetVertices(verts); + + // Set skewing + UpdateSkew(); + return true; } //} @@ -407,7 +419,216 @@ namespace CodeImp.DoomBuilder.BuilderModes FitTexture(options); Setup(); } - + + /// <summary> + /// Updates the value for texture skewing. Has to be done after the texture is set. + /// </summary> + public void UpdateSkew() + { + // Reset + skew = new Vector2f(0.0f); + + if (!General.Map.Config.SidedefTextureSkewing) + return; + + string skewtype = Sidedef.Fields.GetValue("skew_middle_type", "none"); + + if ((skewtype == "front_floor" || skewtype == "front_ceiling" || skewtype == "back_floor" || skewtype == "back_ceiling") && Texture != null) + { + double leftz, rightz; + + if(skewtype == "front_floor") + { + if (Sidedef.IsFront) + { + Plane plane = Sector.GetSectorData().Floor.plane; + leftz = plane.GetZ(Sidedef.Line.Start.Position); + rightz = plane.GetZ(Sidedef.Line.End.Position); + } + else + { + Plane plane = mode.GetSectorData(Sidedef.Other.Sector).Floor.plane; + leftz = plane.GetZ(Sidedef.Line.End.Position); + rightz = plane.GetZ(Sidedef.Line.Start.Position); + } + } + else if(skewtype == "front_ceiling") + { + if (Sidedef.IsFront) + { + Plane plane = Sector.GetSectorData().Ceiling.plane; + leftz = plane.GetZ(Sidedef.Line.Start.Position); + rightz = plane.GetZ(Sidedef.Line.End.Position); + } + else + { + Plane plane = mode.GetSectorData(Sidedef.Other.Sector).Ceiling.plane; + leftz = plane.GetZ(Sidedef.Line.End.Position); + rightz = plane.GetZ(Sidedef.Line.Start.Position); + } + } + else if (skewtype == "back_floor") + { + if (Sidedef.IsFront) + { + Plane plane = mode.GetSectorData(Sidedef.Other.Sector).Floor.plane; + leftz = plane.GetZ(Sidedef.Line.Start.Position); + rightz = plane.GetZ(Sidedef.Line.End.Position); + } + else + { + Plane plane = Sector.GetSectorData().Floor.plane; + leftz = plane.GetZ(Sidedef.Line.End.Position); + rightz = plane.GetZ(Sidedef.Line.Start.Position); + } + } + else // Back ceiling + { + if (Sidedef.IsFront) + { + Plane plane = mode.GetSectorData(Sidedef.Other.Sector).Ceiling.plane; + leftz = plane.GetZ(Sidedef.Line.Start.Position); + rightz = plane.GetZ(Sidedef.Line.End.Position); + } + else + { + Plane plane = Sector.GetSectorData().Ceiling.plane; + leftz = plane.GetZ(Sidedef.Line.End.Position); + rightz = plane.GetZ(Sidedef.Line.Start.Position); + } + } + + skew = new Vector2f( + Vertices.Min(v => v.u), // Get the lowest horizontal texture offset + (float)((rightz - leftz) / Sidedef.Line.Length * ((double)Texture.Width / Texture.Height)) + ); + } + } + + /// <summary> + /// Creates clipping planes for skewed sidedefs + /// </summary> + /// <param name="textop">The texture's top position</param> + /// <param name="texbottom">The texture's bottom position</param> + /// <param name="sd">This sidedef's sector data</param> + /// <param name="osd">The other sidedef's sector data</param> + /// <returns>The top and bottom clipping planes</returns> + private (Plane, Plane) CreateSkewClipPlanes(double textop, double texbottom, SectorData sd, SectorData osd) + { + string skewtype = Sidedef.Fields.GetValue("skew_middle_type", "none"); + if ((skewtype == "front_floor" || skewtype == "front_ceiling" || skewtype == "back_floor" || skewtype == "back_ceiling") && Texture != null) + { + double diff; + Line2D line; + + if (skewtype == "front_ceiling") + (diff, line) = GetZDiff(false, true); + else if(skewtype == "back_ceiling") + (diff, line) = GetZDiff(false, false); + else if(skewtype == "front_floor") + (diff, line) = GetZDiff(true, true); + else // back_floor + (diff, line) = GetZDiff(true, false); + + + Plane p1 = new Plane( + new Vector3D(line.v1, textop), + new Vector3D(line.v2, textop + diff), + new Vector3D(line.GetPerpendicular() * 10, textop), + false); + + Plane p2 = new Plane( + new Vector3D(line.v1, texbottom), + new Vector3D(line.v2, texbottom + diff), + new Vector3D(line.GetPerpendicular() * 10, texbottom), + true); + + return (p1, p2); + + } + else // Invalid skew type + { + return ( + new Plane(new Vector3D(0, 0, -1), textop), + new Plane(new Vector3D(0, 0, 1), -texbottom) + ); + } + + // Returns the z position at the start and end vertices of the line, and a line that always goes from left to right + (double, Line2D) GetZDiff(bool floor, bool front) + { + double leftz, rightz; + Vector2D ls, le; + + if (Sidedef.IsFront) + { + ls = Sidedef.Line.Start.Position; + le = Sidedef.Line.End.Position; + + if (floor) + { + if (front) + { + leftz = sd.Floor.plane.GetZ(Sidedef.Line.Start.Position); + rightz = sd.Floor.plane.GetZ(Sidedef.Line.End.Position); + } + else + { + leftz = osd.Floor.plane.GetZ(Sidedef.Line.Start.Position); + rightz = osd.Floor.plane.GetZ(Sidedef.Line.End.Position); + } + } + else + { + if (front) + { + leftz = sd.Ceiling.plane.GetZ(Sidedef.Line.Start.Position); + rightz = sd.Ceiling.plane.GetZ(Sidedef.Line.End.Position); + } + else + { + leftz = osd.Ceiling.plane.GetZ(Sidedef.Line.Start.Position); + rightz = osd.Ceiling.plane.GetZ(Sidedef.Line.End.Position); + } + } + } + else + { + ls = Sidedef.Line.End.Position; + le = Sidedef.Line.Start.Position; + + if (floor) + { + if (front) + { + leftz = osd.Floor.plane.GetZ(Sidedef.Line.End.Position); + rightz = osd.Floor.plane.GetZ(Sidedef.Line.Start.Position); + } + else + { + leftz = sd.Floor.plane.GetZ(Sidedef.Line.End.Position); + rightz = sd.Floor.plane.GetZ(Sidedef.Line.Start.Position); + } + } + else + { + if (front) + { + leftz = osd.Ceiling.plane.GetZ(Sidedef.Line.End.Position); + rightz = osd.Ceiling.plane.GetZ(Sidedef.Line.Start.Position); + } + else + { + leftz = sd.Ceiling.plane.GetZ(Sidedef.Line.End.Position); + rightz = sd.Ceiling.plane.GetZ(Sidedef.Line.Start.Position); + } + } + } + + return (rightz - leftz, new Line2D(ls, le)); + } + } + #endregion } } diff --git a/Source/Plugins/BuilderModes/VisualModes/VisualMiddleSingle.cs b/Source/Plugins/BuilderModes/VisualModes/VisualMiddleSingle.cs index 9af2c2dbbfefc6c21cc11bdb255ac25ca87791ad..5e59d41b84f8e648fb4c573669f42b0f52916ee1 100755 --- a/Source/Plugins/BuilderModes/VisualModes/VisualMiddleSingle.cs +++ b/Source/Plugins/BuilderModes/VisualModes/VisualMiddleSingle.cs @@ -19,6 +19,7 @@ using System; using System.Collections.Generic; using System.Drawing; +using System.Linq; using CodeImp.DoomBuilder.Map; using CodeImp.DoomBuilder.Geometry; using CodeImp.DoomBuilder.Rendering; @@ -56,7 +57,7 @@ namespace CodeImp.DoomBuilder.BuilderModes // We have no destructor GC.SuppressFinalize(this); } - + // This builds the geometry. Returns false when no geometry created. public override bool Setup() { @@ -69,12 +70,12 @@ namespace CodeImp.DoomBuilder.BuilderModes Vector2D tscale = new Vector2D(Sidedef.Fields.GetValue("scalex_mid", 1.0), Sidedef.Fields.GetValue("scaley_mid", 1.0)); - Vector2D tscaleAbs = new Vector2D(Math.Abs(tscale.x), Math.Abs(tscale.y)); + Vector2D tscaleAbs = new Vector2D(Math.Abs(tscale.x), Math.Abs(tscale.y)); Vector2D toffset = new Vector2D(Sidedef.Fields.GetValue("offsetx_mid", 0.0), Sidedef.Fields.GetValue("offsety_mid", 0.0)); - + // Left and right vertices for this sidedef - if(Sidedef.IsFront) + 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); @@ -87,20 +88,20 @@ namespace CodeImp.DoomBuilder.BuilderModes // Load sector data SectorData sd = mode.GetSectorData(Sidedef.Sector); - + // Texture given? - if(Sidedef.LongMiddleTexture != MapSet.EmptyLongName) + if (Sidedef.LongMiddleTexture != MapSet.EmptyLongName) { // Load texture base.Texture = General.Map.Data.GetTextureImage(Sidedef.LongMiddleTexture); - if(base.Texture == null || base.Texture is UnknownImage) + if (base.Texture == null || base.Texture is UnknownImage) { base.Texture = General.Map.Data.UnknownTexture3D; setuponloadedtexture = Sidedef.LongMiddleTexture; } else { - if(!base.Texture.IsImageLoaded) + if (!base.Texture.IsImageLoaded) setuponloadedtexture = Sidedef.LongMiddleTexture; } } @@ -141,26 +142,26 @@ namespace CodeImp.DoomBuilder.BuilderModes // height is 0 then the TexturePlane doesn't work! TexturePlane tp = new TexturePlane(); double floorbias = (Sidedef.Sector.CeilHeight == Sidedef.Sector.FloorHeight) ? 1.0 : 0.0; - if(Sidedef.Line.IsFlagSet(General.Map.Config.LowerUnpeggedFlag)) + if (Sidedef.Line.IsFlagSet(General.Map.Config.LowerUnpeggedFlag)) { // When lower unpegged is set, the middle texture is bound to the bottom tp.tlt.y = tsz.y - (Sidedef.Sector.CeilHeight - Sidedef.Sector.FloorHeight); } tp.trb.x = tp.tlt.x + 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); @@ -170,21 +171,21 @@ namespace CodeImp.DoomBuilder.BuilderModes double fr = sd.Floor.plane.GetZ(vr); double cl = sd.Ceiling.plane.GetZ(vl); double cr = sd.Ceiling.plane.GetZ(vr); - + // Anything to see? - if(((cl - fl) > 0.01f) || ((cr - fr) > 0.01f)) + if (((cl - fl) > 0.01f) || ((cr - fr) > 0.01f)) { // 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, fl)); poly.Add(new Vector3D(vl.x, vl.y, cl)); poly.Add(new Vector3D(vr.x, vr.y, cr)); poly.Add(new Vector3D(vr.x, vr.y, fr)); - + // Determine initial color int lightlevel = lightabsolute ? lightvalue : sd.Ceiling.brightnessbelow + lightvalue; @@ -198,18 +199,22 @@ namespace CodeImp.DoomBuilder.BuilderModes List<WallPolygon> polygons = new List<WallPolygon> { poly }; ClipExtraFloors(polygons, sd.ExtraFloors, false); //mxd - if(polygons.Count > 0) + if (polygons.Count > 0) { // Process the polygon and create vertices List<WorldVertex> verts = CreatePolygonVertices(polygons, tp, sd, lightvalue, lightabsolute); - if(verts.Count > 2) + if (verts.Count > 2) { base.SetVertices(verts); + + // Set skewing + UpdateSkew(); + return true; } } } - + base.SetVertices(null); //mxd return false; } @@ -287,7 +292,36 @@ namespace CodeImp.DoomBuilder.BuilderModes SectorData sd = mode.GetSectorDataEx(Sector.Sector); if(sd != null) sd.Reset(true); } - + + /// <summary> + /// Updates the value for texture skewing. Has to be done after the texture and vertices are set. + /// </summary> + public void UpdateSkew() + { + // Reset + skew = new Vector2f(0.0f); + + if (!General.Map.Config.SidedefTextureSkewing) + return; + + string skewtype = Sidedef.Fields.GetValue("skew_middle_type", "none"); + + // We don't have to check for back because this it's single-sided + if ((skewtype == "front_floor" || skewtype == "front_ceiling") && Texture != null) + { + double leftz, rightz; + Plane plane = skewtype == "front_floor" ? Sector.GetSectorData().Floor.plane : Sector.GetSectorData().Ceiling.plane; + + leftz = plane.GetZ(Sidedef.Line.Start.Position); + rightz = plane.GetZ(Sidedef.Line.End.Position); + + skew = new Vector2f( + Vertices.Min(v => v.u), // Get the lowest horizontal texture offset + (float)((rightz - leftz) / Sidedef.Line.Length * ((double)Texture.Width / Texture.Height)) + ); + } + } + #endregion } } diff --git a/Source/Plugins/BuilderModes/VisualModes/VisualUpper.cs b/Source/Plugins/BuilderModes/VisualModes/VisualUpper.cs index 3e09a375ccbcd13b7046018d5fb03cc4e1b9ae79..dccfe4fc0e382cd49c31d64a1b91227f9ac57654 100755 --- a/Source/Plugins/BuilderModes/VisualModes/VisualUpper.cs +++ b/Source/Plugins/BuilderModes/VisualModes/VisualUpper.cs @@ -19,6 +19,7 @@ using System; using System.Collections.Generic; using System.Drawing; +using System.Linq; using CodeImp.DoomBuilder.Map; using CodeImp.DoomBuilder.Geometry; using CodeImp.DoomBuilder.Rendering; @@ -84,7 +85,7 @@ namespace CodeImp.DoomBuilder.BuilderModes double 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))) + if (!(vlzc > osd.Ceiling.plane.GetZ(vl) || vrzc > osd.Ceiling.plane.GetZ(vr))) { base.SetVertices(null); return false; @@ -215,6 +216,10 @@ namespace CodeImp.DoomBuilder.BuilderModes if(verts.Count > 2) { base.SetVertices(verts); + + // Set skewing + UpdateSkew(); + return true; } } @@ -306,6 +311,62 @@ namespace CodeImp.DoomBuilder.BuilderModes FitTexture(options); Setup(); } + + /// <summary> + /// Updates the value for texture skewing. Has to be done after the texture is set. + /// </summary> + public void UpdateSkew() + { + // Reset + skew = new Vector2f(0.0f); + + if (!General.Map.Config.SidedefTextureSkewing) + return; + + string skewtype = Sidedef.Fields.GetValue("skew_top_type", "none"); + + if ((skewtype == "front" || skewtype == "back") && Texture != null) + { + double leftz, rightz; + + if (skewtype == "front") + { + if (Sidedef.IsFront) + { + Plane plane = Sector.GetSectorData().Ceiling.plane; + leftz = plane.GetZ(Sidedef.Line.Start.Position); + rightz = plane.GetZ(Sidedef.Line.End.Position); + } + else + { + Plane plane = mode.GetSectorData(Sidedef.Other.Sector).Ceiling.plane; + leftz = plane.GetZ(Sidedef.Line.End.Position); + rightz = plane.GetZ(Sidedef.Line.Start.Position); + } + } + else // "back" + { + if (Sidedef.IsFront) + { + Plane plane = mode.GetSectorData(Sidedef.Other.Sector).Ceiling.plane; + leftz = plane.GetZ(Sidedef.Line.Start.Position); + rightz = plane.GetZ(Sidedef.Line.End.Position); + } + else + { + Plane plane = Sector.GetSectorData().Ceiling.plane; + leftz = plane.GetZ(Sidedef.Line.End.Position); + rightz = plane.GetZ(Sidedef.Line.Start.Position); + } + + } + + skew = new Vector2f( + Vertices.Min(v => v.u), // Get the lowest horizontal texture offset + (float)((rightz - leftz) / Sidedef.Line.Length * ((double)Texture.Width / Texture.Height)) + ); + } + } #endregion }