2019-10-23 18:55:41 +00:00
|
|
|
|
#region ================== Copyright (c) 2014 Boris Iwanski
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Copyright (c) 2014 Boris Iwanski
|
|
|
|
|
* This program is released under GNU General Public License
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Drawing;
|
|
|
|
|
using System.Windows.Forms;
|
|
|
|
|
using CodeImp.DoomBuilder.Windows;
|
|
|
|
|
using CodeImp.DoomBuilder.IO;
|
|
|
|
|
using CodeImp.DoomBuilder.Map;
|
|
|
|
|
using CodeImp.DoomBuilder.Rendering;
|
|
|
|
|
using CodeImp.DoomBuilder.Geometry;
|
|
|
|
|
using CodeImp.DoomBuilder.Editing;
|
|
|
|
|
using CodeImp.DoomBuilder.Plugins;
|
|
|
|
|
using CodeImp.DoomBuilder.Actions;
|
|
|
|
|
using CodeImp.DoomBuilder.Types;
|
|
|
|
|
using CodeImp.DoomBuilder.Config;
|
|
|
|
|
using CodeImp.DoomBuilder.Data;
|
|
|
|
|
|
|
|
|
|
namespace CodeImp.DoomBuilder.ThreeDFloorMode
|
|
|
|
|
{
|
|
|
|
|
public class ThreeDFloor
|
|
|
|
|
{
|
|
|
|
|
private Sector sector;
|
|
|
|
|
private List<Sector> taggedsectors;
|
|
|
|
|
private List<Sector> sectorstotag;
|
|
|
|
|
private List<Sector> sectorstountag;
|
|
|
|
|
private string bordertexture;
|
|
|
|
|
private string topflat;
|
|
|
|
|
private string bottomflat;
|
2020-03-14 20:31:24 +00:00
|
|
|
|
private Vector3D floorslope;
|
2020-05-21 12:20:02 +00:00
|
|
|
|
private double floorslopeoffset;
|
2020-03-14 20:31:24 +00:00
|
|
|
|
private Vector3D ceilingslope;
|
2020-05-21 12:20:02 +00:00
|
|
|
|
private double ceilingslopeoffset;
|
2019-10-23 18:55:41 +00:00
|
|
|
|
private int type;
|
|
|
|
|
private int flags;
|
|
|
|
|
private int alpha;
|
|
|
|
|
private int brightness;
|
|
|
|
|
private int topheight;
|
|
|
|
|
private int bottomheight;
|
|
|
|
|
private bool isnew;
|
|
|
|
|
private bool rebuild;
|
|
|
|
|
private int udmftag;
|
|
|
|
|
private List<int> tags;
|
|
|
|
|
|
|
|
|
|
public static Rectangle controlsectorarea = new Rectangle(-512, 512, 512, -512);
|
|
|
|
|
|
|
|
|
|
public Sector Sector { get { return sector; } }
|
|
|
|
|
public List<Sector> TaggedSectors { get { return taggedsectors; } set { taggedsectors = value; } }
|
|
|
|
|
public List<Sector> SectorsToTag { get { return sectorstotag; } set { sectorstotag = value; } }
|
|
|
|
|
public List<Sector> SectorsToUntag { get { return sectorstountag; } set { sectorstountag = value; } }
|
|
|
|
|
public string BorderTexture { get { return bordertexture; } set { bordertexture = value; } }
|
|
|
|
|
public string TopFlat { get { return topflat; } set { topflat = value; } }
|
|
|
|
|
public string BottomFlat { get { return bottomflat; } set { bottomflat = value; } }
|
|
|
|
|
public int Type { get { return type; } set { type = value; } }
|
|
|
|
|
public int Flags { get { return flags; } set { flags = value; } }
|
|
|
|
|
public int Alpha { get { return alpha; } set { alpha = value; } }
|
|
|
|
|
public int Brightness { get { return brightness; }set { brightness = value; } }
|
|
|
|
|
public int TopHeight { get { return topheight; } set { topheight = value; } }
|
|
|
|
|
public int BottomHeight { get { return bottomheight; } set { bottomheight = value; } }
|
|
|
|
|
public bool IsNew { get { return isnew; } set { isnew = value; } }
|
|
|
|
|
public bool Rebuild { get { return rebuild; } set { rebuild = value; } }
|
|
|
|
|
public int UDMFTag { get { return udmftag; } set { udmftag = value; } }
|
|
|
|
|
public List<int> Tags { get { return tags; } set { tags = value; } }
|
2020-03-14 20:31:24 +00:00
|
|
|
|
public Vector3D FloorSlope { get { return floorslope; } set { floorslope = value; } }
|
2020-05-21 12:20:02 +00:00
|
|
|
|
public double FloorSlopeOffset { get { return floorslopeoffset; } set { floorslopeoffset = value; } }
|
2020-03-14 20:31:24 +00:00
|
|
|
|
public Vector3D CeilingSlope { get { return ceilingslope; } set { ceilingslope = value; } }
|
2020-05-21 12:20:02 +00:00
|
|
|
|
public double CeilingSlopeOffset { get { return ceilingslopeoffset; } set { ceilingslopeoffset = value; } }
|
2019-10-23 18:55:41 +00:00
|
|
|
|
|
|
|
|
|
public ThreeDFloor()
|
|
|
|
|
{
|
|
|
|
|
sector = null;
|
|
|
|
|
taggedsectors = new List<Sector>();
|
|
|
|
|
topflat = General.Settings.DefaultCeilingTexture;
|
|
|
|
|
bottomflat = General.Settings.DefaultFloorTexture;
|
|
|
|
|
topheight = General.Settings.DefaultCeilingHeight;
|
|
|
|
|
bottomheight = General.Settings.DefaultFloorHeight;
|
|
|
|
|
bordertexture = General.Settings.DefaultTexture;
|
|
|
|
|
type = 1;
|
|
|
|
|
flags = 0;
|
|
|
|
|
tags = new List<int>();
|
2020-03-15 09:39:26 +00:00
|
|
|
|
floorslope = new Vector3D(0.0f, 0.0f, 0.0f);
|
2020-03-14 20:31:24 +00:00
|
|
|
|
floorslopeoffset = 0.0f;
|
2020-03-15 09:39:26 +00:00
|
|
|
|
ceilingslope = new Vector3D(0.0f, 0.0f, 0.0f);
|
2020-03-14 20:31:24 +00:00
|
|
|
|
ceilingslopeoffset = 0.0f;
|
|
|
|
|
|
2019-10-23 18:55:41 +00:00
|
|
|
|
alpha = 255;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ThreeDFloor(Sector sector)
|
|
|
|
|
{
|
|
|
|
|
if (sector == null)
|
|
|
|
|
throw new Exception("Sector can't be null");
|
|
|
|
|
|
|
|
|
|
this.sector = sector;
|
|
|
|
|
taggedsectors = new List<Sector>();
|
|
|
|
|
topflat = sector.CeilTexture;
|
|
|
|
|
bottomflat = sector.FloorTexture;
|
|
|
|
|
topheight = sector.CeilHeight;
|
|
|
|
|
bottomheight = sector.FloorHeight;
|
|
|
|
|
brightness = sector.Brightness;
|
|
|
|
|
tags = new List<int>();
|
2020-03-14 20:31:24 +00:00
|
|
|
|
floorslope = sector.FloorSlope;
|
|
|
|
|
floorslopeoffset = sector.FloorSlopeOffset;
|
|
|
|
|
ceilingslope = sector.CeilSlope;
|
|
|
|
|
ceilingslopeoffset = sector.CeilSlopeOffset;
|
2019-10-23 18:55:41 +00:00
|
|
|
|
|
|
|
|
|
foreach (Sidedef sd in sector.Sidedefs)
|
|
|
|
|
{
|
|
|
|
|
if (sd.Line.Action == 160)
|
|
|
|
|
{
|
|
|
|
|
bordertexture = sd.MiddleTexture;
|
|
|
|
|
udmftag = sd.Line.Args[0];
|
|
|
|
|
type = sd.Line.Args[1];
|
|
|
|
|
flags = sd.Line.Args[2];
|
|
|
|
|
alpha = sd.Line.Args[3];
|
|
|
|
|
|
|
|
|
|
foreach (Sector s in General.Map.Map.GetSectorsByTag(sd.Line.Args[0]))
|
|
|
|
|
{
|
|
|
|
|
if(!taggedsectors.Contains(s))
|
|
|
|
|
taggedsectors.Add(s);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void BindTag(int tag)
|
|
|
|
|
{
|
|
|
|
|
Linedef line = null;
|
|
|
|
|
|
|
|
|
|
// try to find an line without an action
|
|
|
|
|
foreach (Sidedef sd in sector.Sidedefs)
|
|
|
|
|
{
|
|
|
|
|
if (sd.Line.Action == 0 && sd.Line.Tag == 0 && line == null)
|
|
|
|
|
line = sd.Line;
|
|
|
|
|
|
|
|
|
|
// if a line of the control sector already has the tag
|
|
|
|
|
// nothing has to be done
|
|
|
|
|
if (sd.Line.Args[0] == tag)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// no lines without an action, so a line has to get split
|
|
|
|
|
// find the longest line to split
|
|
|
|
|
if (line == null)
|
|
|
|
|
{
|
|
|
|
|
line = sector.Sidedefs.First().Line;
|
|
|
|
|
|
|
|
|
|
foreach (Sidedef sd in sector.Sidedefs)
|
|
|
|
|
{
|
|
|
|
|
if (sd.Line.Length > line.Length)
|
|
|
|
|
line = sd.Line;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Lines may not have a length of less than 1 after splitting
|
|
|
|
|
if (line.Length / 2 < 1)
|
|
|
|
|
throw new Exception("Can't split more lines in Sector " + line.Front.Sector.Index.ToString() + ".");
|
|
|
|
|
|
|
|
|
|
Vertex v = General.Map.Map.CreateVertex(line.Line.GetCoordinatesAt(0.5f));
|
|
|
|
|
v.SnapToAccuracy();
|
|
|
|
|
|
|
|
|
|
line = line.Split(v);
|
|
|
|
|
|
|
|
|
|
General.Map.Map.Update();
|
|
|
|
|
General.Interface.RedrawDisplay();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
line.Action = 160;
|
|
|
|
|
line.Args[0] = tag;
|
|
|
|
|
line.Args[1] = type;
|
|
|
|
|
line.Args[2] = flags;
|
|
|
|
|
line.Args[3] = alpha;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void UpdateGeometry()
|
|
|
|
|
{
|
|
|
|
|
if (sector == null)
|
|
|
|
|
throw new Exception("3D floor has no geometry");
|
|
|
|
|
|
|
|
|
|
sector.CeilHeight = topheight;
|
|
|
|
|
sector.FloorHeight = bottomheight;
|
|
|
|
|
sector.SetCeilTexture(topflat);
|
|
|
|
|
sector.SetFloorTexture(bottomflat);
|
|
|
|
|
sector.Brightness = brightness;
|
|
|
|
|
sector.Tags = tags;
|
2020-03-14 20:31:24 +00:00
|
|
|
|
sector.FloorSlope = floorslope;
|
|
|
|
|
sector.FloorSlopeOffset = floorslopeoffset;
|
|
|
|
|
sector.CeilSlope = ceilingslope;
|
|
|
|
|
sector.CeilSlopeOffset = ceilingslopeoffset;
|
2019-10-23 18:55:41 +00:00
|
|
|
|
|
|
|
|
|
foreach (Sidedef sd in sector.Sidedefs)
|
|
|
|
|
{
|
|
|
|
|
sd.SetTextureMid(bordertexture);
|
|
|
|
|
|
|
|
|
|
if (sd.Line.Action == 160)
|
|
|
|
|
{
|
|
|
|
|
sd.Line.Args[1] = type;
|
|
|
|
|
sd.Line.Args[2] = flags;
|
|
|
|
|
sd.Line.Args[3] = alpha;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool CreateGeometry(List<int> tagblacklist)
|
2020-06-12 22:24:24 +00:00
|
|
|
|
{
|
|
|
|
|
int newtag;
|
|
|
|
|
|
|
|
|
|
return CreateGeometry(tagblacklist, false, out newtag);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool CreateGeometry(List<int> tagblacklist, bool forcenewtag, out int newtag)
|
2019-10-23 18:55:41 +00:00
|
|
|
|
{
|
|
|
|
|
List<DrawnVertex> drawnvertices = new List<DrawnVertex>();
|
|
|
|
|
List<Vertex> vertices = new List<Vertex>();
|
|
|
|
|
Vector3D slopetopthingpos = new Vector3D(0, 0, 0);
|
|
|
|
|
Vector3D slopebottomthingpos = new Vector3D(0, 0, 0);
|
|
|
|
|
Line2D slopeline = new Line2D(0, 0, 0, 0);
|
|
|
|
|
|
2020-06-12 22:24:24 +00:00
|
|
|
|
newtag = -1;
|
|
|
|
|
|
2019-10-23 18:55:41 +00:00
|
|
|
|
drawnvertices = BuilderPlug.Me.ControlSectorArea.GetNewControlSectorVertices();
|
|
|
|
|
|
|
|
|
|
if (Tools.DrawLines(drawnvertices) == false)
|
|
|
|
|
{
|
|
|
|
|
General.Interface.DisplayStatus(StatusType.Warning, "Could not draw new sector");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sector = General.Map.Map.GetMarkedSectors(true)[0];
|
|
|
|
|
|
|
|
|
|
sector.FloorHeight = bottomheight;
|
|
|
|
|
sector.CeilHeight = topheight;
|
|
|
|
|
sector.SetFloorTexture(bottomflat);
|
|
|
|
|
sector.SetCeilTexture(topflat);
|
2020-03-14 20:31:24 +00:00
|
|
|
|
sector.FloorSlope = floorslope;
|
|
|
|
|
sector.FloorSlopeOffset = floorslopeoffset;
|
|
|
|
|
sector.CeilSlope = ceilingslope;
|
|
|
|
|
sector.CeilSlopeOffset = ceilingslopeoffset;
|
2019-10-23 18:55:41 +00:00
|
|
|
|
|
|
|
|
|
foreach (Sidedef sd in sector.Sidedefs)
|
|
|
|
|
{
|
|
|
|
|
sd.Line.Front.SetTextureMid(bordertexture);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!sector.Fields.ContainsKey("user_managed_3d_floor"))
|
|
|
|
|
sector.Fields.Add("user_managed_3d_floor", new UniValue(UniversalType.Boolean, true));
|
|
|
|
|
|
|
|
|
|
sector.Fields["comment"] = new UniValue(UniversalType.String, "[!]DO NOT DELETE! This sector is managed by the 3D floor plugin.");
|
|
|
|
|
|
|
|
|
|
// With multiple tag support in UDMF only one tag is needed, so bind it right away
|
|
|
|
|
if (General.Map.UDMF == true)
|
|
|
|
|
{
|
2020-06-12 22:24:24 +00:00
|
|
|
|
if (isnew || forcenewtag)
|
2020-06-01 09:54:25 +00:00
|
|
|
|
{
|
2020-06-12 22:24:24 +00:00
|
|
|
|
newtag = udmftag = BuilderPlug.Me.ControlSectorArea.GetNewSectorTag(tagblacklist);
|
2020-06-01 09:54:25 +00:00
|
|
|
|
tagblacklist.Add(udmftag);
|
|
|
|
|
}
|
2019-10-23 18:55:41 +00:00
|
|
|
|
|
|
|
|
|
BindTag(udmftag);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Snap to map format accuracy
|
|
|
|
|
General.Map.Map.SnapAllToAccuracy();
|
|
|
|
|
|
|
|
|
|
General.Map.Map.BeginAddRemove();
|
|
|
|
|
//MapSet.JoinVertices(vertices, vertices, false, MapSet.STITCH_DISTANCE);
|
|
|
|
|
General.Map.Map.EndAddRemove();
|
|
|
|
|
|
|
|
|
|
// Update textures
|
|
|
|
|
General.Map.Data.UpdateUsedTextures();
|
|
|
|
|
|
|
|
|
|
// Update caches
|
|
|
|
|
General.Map.Map.Update();
|
|
|
|
|
General.Interface.RedrawDisplay();
|
|
|
|
|
General.Map.IsChanged = true;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Cleanup()
|
|
|
|
|
{
|
|
|
|
|
int taggedLines = 0;
|
|
|
|
|
|
|
|
|
|
foreach (Sidedef sd in sector.Sidedefs)
|
|
|
|
|
{
|
|
|
|
|
if (sd.Line.Action == 160 && General.Map.Map.GetSectorsByTag(sd.Line.Args[0]).Count == 0)
|
|
|
|
|
{
|
|
|
|
|
sd.Line.Action = 0;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < 5; i++)
|
|
|
|
|
sd.Line.Args[i] = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (sd.Line.Action != 0)
|
|
|
|
|
taggedLines++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (taggedLines == 0)
|
|
|
|
|
{
|
|
|
|
|
DeleteControlSector(sector);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void DeleteControlSector(Sector sector)
|
|
|
|
|
{
|
|
|
|
|
if (sector == null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
General.Map.Map.BeginAddRemove();
|
|
|
|
|
|
|
|
|
|
// Get all the linedefs
|
|
|
|
|
List<Linedef> lines = new List<Linedef>(sector.Sidedefs.Count);
|
|
|
|
|
foreach (Sidedef side in sector.Sidedefs) lines.Add(side.Line);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Dispose the sector
|
|
|
|
|
sector.Dispose();
|
|
|
|
|
|
|
|
|
|
// Check all the lines
|
|
|
|
|
for (int i = lines.Count - 1; i >= 0; i--)
|
|
|
|
|
{
|
|
|
|
|
// If the line has become orphaned, remove it
|
|
|
|
|
if ((lines[i].Front == null) && (lines[i].Back == null))
|
|
|
|
|
{
|
|
|
|
|
// Remove line
|
|
|
|
|
lines[i].Dispose();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// If the line only has a back side left, flip the line and sides
|
|
|
|
|
if ((lines[i].Front == null) && (lines[i].Back != null))
|
|
|
|
|
{
|
|
|
|
|
lines[i].FlipVertices();
|
|
|
|
|
lines[i].FlipSidedefs();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check textures.
|
|
|
|
|
if (lines[i].Front.MiddleRequired() && (lines[i].Front.MiddleTexture.Length == 0 || lines[i].Front.MiddleTexture == "-"))
|
|
|
|
|
{
|
|
|
|
|
if (lines[i].Front.HighTexture.Length > 0 && lines[i].Front.HighTexture != "-")
|
|
|
|
|
{
|
|
|
|
|
lines[i].Front.SetTextureMid(lines[i].Front.HighTexture);
|
|
|
|
|
}
|
|
|
|
|
else if (lines[i].Front.LowTexture.Length > 0 && lines[i].Front.LowTexture != "-")
|
|
|
|
|
{
|
|
|
|
|
lines[i].Front.SetTextureMid(lines[i].Front.LowTexture);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Do we still need high/low textures?
|
|
|
|
|
lines[i].Front.RemoveUnneededTextures(false);
|
|
|
|
|
|
|
|
|
|
// Update sided flags
|
|
|
|
|
lines[i].ApplySidedFlags();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
General.Map.Map.EndAddRemove();
|
|
|
|
|
|
|
|
|
|
// Update cache values
|
|
|
|
|
General.Map.IsChanged = true;
|
|
|
|
|
General.Map.Map.Update();
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void DeleteControlSector()
|
|
|
|
|
{
|
|
|
|
|
DeleteControlSector(sector);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|