From 67107d2c24e6358c57be13dee88cc0a1312cdc5d Mon Sep 17 00:00:00 2001 From: codeimp Date: Wed, 8 Sep 2010 15:05:32 +0000 Subject: [PATCH] @ work on (G)ZDoom Editing plugin --- Source/Core/Geometry/Plane.cs | 6 +- .../VisualModes/VisualMiddleSingle.cs | 111 +++++++++++++----- Tests/UDMF/udmfexample.wad | Bin 45262 -> 47716 bytes 3 files changed, 83 insertions(+), 34 deletions(-) diff --git a/Source/Core/Geometry/Plane.cs b/Source/Core/Geometry/Plane.cs index 7928d174..8344067e 100644 --- a/Source/Core/Geometry/Plane.cs +++ b/Source/Core/Geometry/Plane.cs @@ -86,7 +86,7 @@ namespace CodeImp.DoomBuilder.Geometry { this.normal = Vector3D.CrossProduct(p1 - p2, p3 - p2).GetNormal(); this.offset = -Vector3D.DotProduct(normal, p2); - + if((up && (this.normal.z < 0.0f)) || (!up && (this.normal.z > 0.0f))) this.normal.z = -this.normal.z; } @@ -103,8 +103,8 @@ namespace CodeImp.DoomBuilder.Geometry float w = Vector3D.DotProduct(normal, from - to); if(w != 0.0f) { - float v = Vector3D.DotProduct(normal, from); - u_ray = (v + offset) / w; + float v = (normal.x * from.x) - (normal.y * from.y) - (normal.z * from.z); + u_ray = (offset + v) / -w; return true; } else diff --git a/Source/Plugins/GZDoomEditing/VisualModes/VisualMiddleSingle.cs b/Source/Plugins/GZDoomEditing/VisualModes/VisualMiddleSingle.cs index e2b4eea3..24e6af33 100644 --- a/Source/Plugins/GZDoomEditing/VisualModes/VisualMiddleSingle.cs +++ b/Source/Plugins/GZDoomEditing/VisualModes/VisualMiddleSingle.cs @@ -44,30 +44,30 @@ namespace CodeImp.DoomBuilder.GZDoomEditing #region ================== Constants #endregion - + #region ================== Variables #endregion - + #region ================== Properties #endregion - + #region ================== Constructor / Setup - + // Constructor public VisualMiddleSingle(BaseVisualMode mode, VisualSector vs, Sidedef s) : base(mode, vs, s) { // We have no destructor GC.SuppressFinalize(this); } - + // This builds the geometry. Returns false when no geometry created. public override bool Setup() { SectorData sd = mode.GetSectorData(Sidedef.Sector); int brightness = mode.CalculateBrightness(Sidedef.Sector.Brightness); - + // Texture given? if((Sidedef.MiddleTexture.Length > 0) && (Sidedef.MiddleTexture[0] != '-')) { @@ -90,7 +90,7 @@ namespace CodeImp.DoomBuilder.GZDoomEditing base.Texture = General.Map.Data.MissingTexture3D; setuponloadedtexture = 0; } - + // Get texture scaled size Vector2D tsz = new Vector2D(base.Texture.ScaledWidth, base.Texture.ScaledHeight); @@ -106,7 +106,7 @@ namespace CodeImp.DoomBuilder.GZDoomEditing } tp.trb.x = tp.tlt.x + Sidedef.Line.Length; tp.trb.y = tp.tlt.y + (Sidedef.Sector.CeilHeight - Sidedef.Sector.FloorHeight); - + // Apply texture offset if (General.Map.Config.ScaledTextureOffsets && !base.Texture.WorldPanning) { @@ -118,11 +118,11 @@ namespace CodeImp.DoomBuilder.GZDoomEditing tp.tlt += new Vector2D(Sidedef.OffsetX, Sidedef.OffsetY); tp.trb += new Vector2D(Sidedef.OffsetX, Sidedef.OffsetY); } - + // Transform pixel coordinates to texture coordinates tp.tlt /= tsz; tp.trb /= tsz; - + // Left top and right bottom of the geometry that if(Sidedef.IsFront) { @@ -134,11 +134,20 @@ namespace CodeImp.DoomBuilder.GZDoomEditing tp.vlt = new Vector3D(Sidedef.Line.End.Position.x, Sidedef.Line.End.Position.y, Sidedef.Sector.CeilHeight); tp.vrb = new Vector3D(Sidedef.Line.Start.Position.x, Sidedef.Line.Start.Position.y, Sidedef.Sector.FloorHeight); } - + // 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); - + + // + // - Geometry is horizontally split and ranges from one layer down to the next layer. + // This is repeated for all layers. + // + // - When the two layers intersect over Z, the geometry should not span the entire + // width, but only up to the split position. The back side will handle the other + // side of the split, if needed. + // + // Go for all levels to build geometry List verts = new List(); for(int i = 0; i < (sd.Levels.Count - 1); i++) @@ -150,25 +159,65 @@ namespace CodeImp.DoomBuilder.GZDoomEditing PixelColor wallbrightness = PixelColor.FromInt(mode.CalculateBrightness(lt.brightnessbelow)); PixelColor wallcolor = PixelColor.Modulate(lt.colorbelow, wallbrightness); int c = wallcolor.WithAlpha(255).ToInt(); - - Vector3D vlb = new Vector3D(tp.vlt.x, tp.vlt.y, lb.plane.GetZ(tp.vlt)); - Vector3D vlt = new Vector3D(tp.vlt.x, tp.vlt.y, lt.plane.GetZ(tp.vlt)); - Vector3D vrb = new Vector3D(tp.vrb.x, tp.vrb.y, lb.plane.GetZ(tp.vrb)); - Vector3D vrt = new Vector3D(tp.vrt.x, tp.vrt.y, lt.plane.GetZ(tp.vrt)); - Vector2D tlb = tp.GetTextureCoordsAt(vlb); - Vector2D tlt = tp.GetTextureCoordsAt(vlt); - Vector2D trb = tp.GetTextureCoordsAt(vrb); - Vector2D trt = tp.GetTextureCoordsAt(vrt); - - verts.Add(new WorldVertex(vlb.x, vlb.y, vlb.z, c, tlb.x, tlb.y)); - verts.Add(new WorldVertex(vlt.x, vlt.y, vlt.z, c, tlt.x, tlt.y)); - verts.Add(new WorldVertex(vrt.x, vrt.y, vrt.z, c, trt.x, trt.y)); - verts.Add(new WorldVertex(vlb.x, vlb.y, vlb.z, c, tlb.x, tlb.y)); - verts.Add(new WorldVertex(vrt.x, vrt.y, vrt.z, c, trt.x, trt.y)); - verts.Add(new WorldVertex(vrb.x, vrb.y, vrb.z, c, trb.x, trb.y)); + + // Get corner heights on the two planes + float lbl = lb.plane.GetZ(tp.vlt); + float lbr = lb.plane.GetZ(tp.vrt); + float ltl = lt.plane.GetZ(tp.vlt); + float ltr = lt.plane.GetZ(tp.vrt); + + // Make coordinates for the corners + Vector3D vlb = new Vector3D(tp.vlt.x, tp.vlt.y, lbl); + Vector3D vlt = new Vector3D(tp.vlt.x, tp.vlt.y, ltl); + Vector3D vrb = new Vector3D(tp.vrb.x, tp.vrb.y, lbr); + Vector3D vrt = new Vector3D(tp.vrt.x, tp.vrt.y, ltr); + + /* + // Compare corner heights to see if we should split + if((lbl < ltl) && (lbr >= ltr)) + { + // Split vertically with geometry on the left + float u_ray = 1.0f; + lb.plane.GetIntersection(vlt, vrt, ref u_ray); + Vector3D vs = vlt + (vrt - vlt) * u_ray; + Vector2D tlb = tp.GetTextureCoordsAt(vlb); + Vector2D tlt = tp.GetTextureCoordsAt(vlt); + Vector2D ts = tp.GetTextureCoordsAt(vs); + verts.Add(new WorldVertex(vlb.x, vlb.y, vlb.z, c, tlb.x, tlb.y)); + verts.Add(new WorldVertex(vlt.x, vlt.y, vlt.z, c, tlt.x, tlt.y)); + verts.Add(new WorldVertex(vs.x, vs.y, vs.z, c, ts.x, ts.y)); + } + else if((lbl >= ltl) && (lbr < ltr)) + { + // Split vertically with geometry on the right + float u_ray = 0.0f; + lb.plane.GetIntersection(vlt, vrt, ref u_ray); + Vector3D vs = vlt + (vrt - vlt) * u_ray; + Vector2D trb = tp.GetTextureCoordsAt(vrb); + Vector2D trt = tp.GetTextureCoordsAt(vrt); + Vector2D ts = tp.GetTextureCoordsAt(vs); + verts.Add(new WorldVertex(vs.x, vs.y, vs.z, c, ts.x, ts.y)); + verts.Add(new WorldVertex(vrt.x, vrt.y, vrt.z, c, trt.x, trt.y)); + verts.Add(new WorldVertex(vrb.x, vrb.y, vrb.z, c, trb.x, trb.y)); + } + else if((lbl < ltl) && (lbr < ltr)) + */ + { + // Span entire width + Vector2D tlb = tp.GetTextureCoordsAt(vlb); + Vector2D tlt = tp.GetTextureCoordsAt(vlt); + Vector2D trb = tp.GetTextureCoordsAt(vrb); + Vector2D trt = tp.GetTextureCoordsAt(vrt); + verts.Add(new WorldVertex(vlb.x, vlb.y, vlb.z, c, tlb.x, tlb.y)); + verts.Add(new WorldVertex(vlt.x, vlt.y, vlt.z, c, tlt.x, tlt.y)); + verts.Add(new WorldVertex(vrt.x, vrt.y, vrt.z, c, trt.x, trt.y)); + verts.Add(new WorldVertex(vlb.x, vlb.y, vlb.z, c, tlb.x, tlb.y)); + verts.Add(new WorldVertex(vrt.x, vrt.y, vrt.z, c, trt.x, trt.y)); + verts.Add(new WorldVertex(vrb.x, vrb.y, vrb.z, c, trb.x, trb.y)); + } } } - + if(verts.Count > 0) { base.SetVertices(verts); @@ -179,9 +228,9 @@ namespace CodeImp.DoomBuilder.GZDoomEditing return false; } } - + #endregion - + #region ================== Methods // Return texture name diff --git a/Tests/UDMF/udmfexample.wad b/Tests/UDMF/udmfexample.wad index 6852837d93a94e95ed811c5e28ea1e821a2f3d33..d222c323cebf0ba70480098b3ea223647e211a95 100644 GIT binary patch literal 47716 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 literal 45262 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 b{}=-O%{y+qX8T)lazt_CpY1!YVYB%^)%=