mirror of
https://git.do.srb2.org/STJr/UltimateZoneBuilder.git
synced 2024-11-26 22:01:45 +00:00
Merge branch 'visual-slope2'
This commit is contained in:
commit
58d5bfd59b
20 changed files with 1624 additions and 563 deletions
|
@ -252,6 +252,8 @@
|
||||||
<Compile Include="Rendering\Vector3.cs" />
|
<Compile Include="Rendering\Vector3.cs" />
|
||||||
<Compile Include="Rendering\Vector4.cs" />
|
<Compile Include="Rendering\Vector4.cs" />
|
||||||
<Compile Include="Rendering\VertexBuffer.cs" />
|
<Compile Include="Rendering\VertexBuffer.cs" />
|
||||||
|
<Compile Include="Rendering\VisualSlopeHandle.cs" />
|
||||||
|
<Compile Include="VisualModes\VisualSlope.cs" />
|
||||||
<Compile Include="Windows\ThingStatisticsForm.cs">
|
<Compile Include="Windows\ThingStatisticsForm.cs">
|
||||||
<SubType>Form</SubType>
|
<SubType>Form</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
|
|
@ -2181,6 +2181,7 @@ namespace CodeImp.DoomBuilder
|
||||||
// Update settings
|
// Update settings
|
||||||
renderer3d.CreateProjection();
|
renderer3d.CreateProjection();
|
||||||
renderer3d.UpdateVertexHandle(); //mxd
|
renderer3d.UpdateVertexHandle(); //mxd
|
||||||
|
renderer3d.UpdateVisualSlopeHandle();
|
||||||
|
|
||||||
// Things filters
|
// Things filters
|
||||||
General.MainWindow.UpdateThingsFilters();
|
General.MainWindow.UpdateThingsFilters();
|
||||||
|
|
|
@ -50,6 +50,7 @@ namespace CodeImp.DoomBuilder.Rendering
|
||||||
void AddSectorGeometry(VisualGeometry g);
|
void AddSectorGeometry(VisualGeometry g);
|
||||||
void AddThingGeometry(VisualThing t);
|
void AddThingGeometry(VisualThing t);
|
||||||
void SetVisualVertices(List<VisualVertex> verts);
|
void SetVisualVertices(List<VisualVertex> verts);
|
||||||
|
void SetVisualSlopeHandles(List<VisualSlope> handles);
|
||||||
void SetEventLines(List<Line3D> lines);
|
void SetEventLines(List<Line3D> lines);
|
||||||
void RenderCrosshair();
|
void RenderCrosshair();
|
||||||
void SetFogMode(bool usefog);
|
void SetFogMode(bool usefog);
|
||||||
|
|
|
@ -68,6 +68,7 @@ namespace CodeImp.DoomBuilder.Rendering
|
||||||
DeclareUniform(UniformName.fogcolor, "fogcolor", UniformType.Vec4f);
|
DeclareUniform(UniformName.fogcolor, "fogcolor", UniformType.Vec4f);
|
||||||
DeclareUniform(UniformName.sectorfogcolor, "sectorfogcolor", UniformType.Vec4f);
|
DeclareUniform(UniformName.sectorfogcolor, "sectorfogcolor", UniformType.Vec4f);
|
||||||
DeclareUniform(UniformName.lightsEnabled, "lightsEnabled", UniformType.Float);
|
DeclareUniform(UniformName.lightsEnabled, "lightsEnabled", UniformType.Float);
|
||||||
|
DeclareUniform(UniformName.slopeHandleLength, "slopeHandleLength", UniformType.Float);
|
||||||
|
|
||||||
// 2d fsaa
|
// 2d fsaa
|
||||||
CompileShader(ShaderName.display2d_fsaa, "display2d.shader", "display2d_fsaa");
|
CompileShader(ShaderName.display2d_fsaa, "display2d.shader", "display2d_fsaa");
|
||||||
|
@ -100,6 +101,9 @@ namespace CodeImp.DoomBuilder.Rendering
|
||||||
CompileShader(ShaderName.world3d_main_fog_vertexcolor, "world3d.shader", "world3d_main_fog_vertexcolor");
|
CompileShader(ShaderName.world3d_main_fog_vertexcolor, "world3d.shader", "world3d_main_fog_vertexcolor");
|
||||||
CompileShader(ShaderName.world3d_main_highlight_fog_vertexcolor, "world3d.shader", "world3d_main_highlight_fog_vertexcolor");
|
CompileShader(ShaderName.world3d_main_highlight_fog_vertexcolor, "world3d.shader", "world3d_main_highlight_fog_vertexcolor");
|
||||||
|
|
||||||
|
// Slope handle
|
||||||
|
CompileShader(ShaderName.world3d_slope_handle, "world3d.shader", "world3d_slope_handle");
|
||||||
|
|
||||||
SetupSettings();
|
SetupSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -730,7 +734,8 @@ namespace CodeImp.DoomBuilder.Rendering
|
||||||
world3d_p13,
|
world3d_p13,
|
||||||
world3d_main_highlight_fog_vertexcolor,
|
world3d_main_highlight_fog_vertexcolor,
|
||||||
world3d_vertex_color,
|
world3d_vertex_color,
|
||||||
world3d_constant_color
|
world3d_constant_color,
|
||||||
|
world3d_slope_handle
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum UniformType : int
|
public enum UniformType : int
|
||||||
|
@ -772,7 +777,8 @@ namespace CodeImp.DoomBuilder.Rendering
|
||||||
fogsettings,
|
fogsettings,
|
||||||
fogcolor,
|
fogcolor,
|
||||||
sectorfogcolor,
|
sectorfogcolor,
|
||||||
lightsEnabled
|
lightsEnabled,
|
||||||
|
slopeHandleLength
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum VertexFormat : int { Flat, World }
|
public enum VertexFormat : int { Flat, World }
|
||||||
|
|
|
@ -65,6 +65,9 @@ namespace CodeImp.DoomBuilder.Rendering
|
||||||
private VisualVertexHandle vertexhandle;
|
private VisualVertexHandle vertexhandle;
|
||||||
private int[] lightOffsets;
|
private int[] lightOffsets;
|
||||||
|
|
||||||
|
// Slope handle
|
||||||
|
private VisualSlopeHandle visualslopehandle;
|
||||||
|
|
||||||
// Crosshair
|
// Crosshair
|
||||||
private FlatVertex[] crosshairverts;
|
private FlatVertex[] crosshairverts;
|
||||||
private bool crosshairbusy;
|
private bool crosshairbusy;
|
||||||
|
@ -112,6 +115,9 @@ namespace CodeImp.DoomBuilder.Rendering
|
||||||
//mxd. Visual vertices
|
//mxd. Visual vertices
|
||||||
private List<VisualVertex> visualvertices;
|
private List<VisualVertex> visualvertices;
|
||||||
|
|
||||||
|
// Visual slope handles
|
||||||
|
private List<VisualSlope> visualslopehandles;
|
||||||
|
|
||||||
//mxd. Event lines
|
//mxd. Event lines
|
||||||
private List<Line3D> eventlines;
|
private List<Line3D> eventlines;
|
||||||
|
|
||||||
|
@ -166,6 +172,7 @@ namespace CodeImp.DoomBuilder.Rendering
|
||||||
{
|
{
|
||||||
// Clean up
|
// Clean up
|
||||||
if(vertexhandle != null) vertexhandle.Dispose(); //mxd
|
if(vertexhandle != null) vertexhandle.Dispose(); //mxd
|
||||||
|
if (visualslopehandle != null) visualslopehandle.Dispose();
|
||||||
|
|
||||||
// Done
|
// Done
|
||||||
base.Dispose();
|
base.Dispose();
|
||||||
|
@ -232,6 +239,15 @@ namespace CodeImp.DoomBuilder.Rendering
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void UpdateVisualSlopeHandle()
|
||||||
|
{
|
||||||
|
if (visualslopehandle != null)
|
||||||
|
{
|
||||||
|
visualslopehandle.UnloadResource();
|
||||||
|
visualslopehandle.ReloadResource();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region ================== Presentation
|
#region ================== Presentation
|
||||||
|
@ -345,6 +361,9 @@ namespace CodeImp.DoomBuilder.Rendering
|
||||||
//mxd. Crate vertex handle
|
//mxd. Crate vertex handle
|
||||||
if(vertexhandle == null) vertexhandle = new VisualVertexHandle();
|
if(vertexhandle == null) vertexhandle = new VisualVertexHandle();
|
||||||
|
|
||||||
|
// Create slope handle
|
||||||
|
if (visualslopehandle == null) visualslopehandle = new VisualSlopeHandle();
|
||||||
|
|
||||||
// Ready
|
// Ready
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -447,8 +466,12 @@ namespace CodeImp.DoomBuilder.Rendering
|
||||||
//mxd. Visual vertices
|
//mxd. Visual vertices
|
||||||
RenderVertices();
|
RenderVertices();
|
||||||
|
|
||||||
|
// Slope handles
|
||||||
|
if (General.Map.UDMF /* && General.Settings.ShowVisualSlopeHandles */)
|
||||||
|
RenderSlopeHandles();
|
||||||
|
|
||||||
//mxd. Event lines
|
//mxd. Event lines
|
||||||
if(General.Settings.GZShowEventLines) RenderArrows(eventlines);
|
if (General.Settings.GZShowEventLines) RenderArrows(eventlines);
|
||||||
|
|
||||||
// Remove references
|
// Remove references
|
||||||
graphics.SetTexture(null);
|
graphics.SetTexture(null);
|
||||||
|
@ -615,6 +638,45 @@ namespace CodeImp.DoomBuilder.Rendering
|
||||||
graphics.SetUniform(UniformName.texturefactor, new Color4(1f, 1f, 1f, 1f));
|
graphics.SetUniform(UniformName.texturefactor, new Color4(1f, 1f, 1f, 1f));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void RenderSlopeHandles()
|
||||||
|
{
|
||||||
|
if (visualslopehandles == null || !showselection) return;
|
||||||
|
|
||||||
|
graphics.SetAlphaBlendEnable(true);
|
||||||
|
graphics.SetAlphaTestEnable(false);
|
||||||
|
graphics.SetZWriteEnable(false);
|
||||||
|
graphics.SetSourceBlend(Blend.SourceAlpha);
|
||||||
|
graphics.SetDestinationBlend(Blend.InverseSourceAlpha);
|
||||||
|
|
||||||
|
graphics.SetShader(ShaderName.world3d_slope_handle);
|
||||||
|
|
||||||
|
foreach (VisualSlope handle in visualslopehandles)
|
||||||
|
{
|
||||||
|
PixelColor color = General.Colors.Vertices;
|
||||||
|
|
||||||
|
if (handle.Pivot)
|
||||||
|
color = General.Colors.Guideline;
|
||||||
|
else if (handle.Selected)
|
||||||
|
color = General.Colors.Selection3D;
|
||||||
|
else if (handle == highlighted)
|
||||||
|
color = General.Colors.Highlight3D;
|
||||||
|
else if (handle.SmartPivot)
|
||||||
|
color = General.Colors.Vertices;
|
||||||
|
|
||||||
|
world = handle.Position;
|
||||||
|
graphics.SetUniform(UniformName.world, ref world);
|
||||||
|
graphics.SetUniform(UniformName.slopeHandleLength, handle.Length);
|
||||||
|
graphics.SetUniform(UniformName.vertexColor, color.ToColorValue());
|
||||||
|
|
||||||
|
graphics.SetVertexBuffer(visualslopehandle.Geometry);
|
||||||
|
graphics.Draw(PrimitiveType.TriangleList, 0, 2);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Done
|
||||||
|
graphics.SetUniform(UniformName.texturefactor, new Color4(1f, 1f, 1f, 1f));
|
||||||
|
}
|
||||||
|
|
||||||
//mxd
|
//mxd
|
||||||
private void RenderArrows(ICollection<Line3D> lines)
|
private void RenderArrows(ICollection<Line3D> lines)
|
||||||
{
|
{
|
||||||
|
@ -1755,6 +1817,8 @@ namespace CodeImp.DoomBuilder.Rendering
|
||||||
//mxd
|
//mxd
|
||||||
public void SetVisualVertices(List<VisualVertex> verts) { visualvertices = verts; }
|
public void SetVisualVertices(List<VisualVertex> verts) { visualvertices = verts; }
|
||||||
|
|
||||||
|
public void SetVisualSlopeHandles(List<VisualSlope> handles) { visualslopehandles = handles; }
|
||||||
|
|
||||||
//mxd
|
//mxd
|
||||||
public void SetEventLines(List<Line3D> lines) { eventlines = lines; }
|
public void SetEventLines(List<Line3D> lines) { eventlines = lines; }
|
||||||
|
|
||||||
|
|
89
Source/Core/Rendering/VisualSlopeHandle.cs
Normal file
89
Source/Core/Rendering/VisualSlopeHandle.cs
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
#region ================== Namespaces
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
namespace CodeImp.DoomBuilder.Rendering
|
||||||
|
{
|
||||||
|
internal sealed class VisualSlopeHandle : IDisposable, IRenderResource
|
||||||
|
{
|
||||||
|
#region ================== Variables
|
||||||
|
|
||||||
|
private VertexBuffer geometry;
|
||||||
|
private bool isdisposed;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ================== Properties
|
||||||
|
|
||||||
|
public VertexBuffer Geometry { get { return geometry; } }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ================== Constructor / Disposer
|
||||||
|
|
||||||
|
public VisualSlopeHandle()
|
||||||
|
{
|
||||||
|
// Create geometry
|
||||||
|
ReloadResource();
|
||||||
|
|
||||||
|
// Register as source
|
||||||
|
General.Map.Graphics.RegisterResource(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
// Not already disposed?
|
||||||
|
if (!isdisposed)
|
||||||
|
{
|
||||||
|
if (geometry != null)
|
||||||
|
geometry.Dispose();
|
||||||
|
|
||||||
|
// Unregister resource
|
||||||
|
General.Map.Graphics.UnregisterResource(this);
|
||||||
|
|
||||||
|
// Done
|
||||||
|
isdisposed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ================== Methods
|
||||||
|
|
||||||
|
// This is called resets when the device is reset
|
||||||
|
// (when resized or display adapter was changed)
|
||||||
|
public void ReloadResource()
|
||||||
|
{
|
||||||
|
WorldVertex v0 = new WorldVertex(0.0f, -8.0f, 0.1f);
|
||||||
|
WorldVertex v1 = new WorldVertex(0.0f, 0.0f, 0.1f);
|
||||||
|
WorldVertex v2 = new WorldVertex(1.0f, 0.0f, 0.1f);
|
||||||
|
WorldVertex v3 = new WorldVertex(1.0f, -8.0f, 0.1f);
|
||||||
|
|
||||||
|
v1.c = v2.c = PixelColor.INT_WHITE;
|
||||||
|
v0.c = v3.c = PixelColor.INT_WHITE_NO_ALPHA;
|
||||||
|
|
||||||
|
WorldVertex[] vertices = new[]
|
||||||
|
{
|
||||||
|
v0, v1, v2,
|
||||||
|
v0, v2, v3
|
||||||
|
};
|
||||||
|
|
||||||
|
geometry = new VertexBuffer();
|
||||||
|
General.Map.Graphics.SetBufferData(geometry, vertices);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is called before a device is reset
|
||||||
|
// (when resized or display adapter was changed)
|
||||||
|
public void UnloadResource()
|
||||||
|
{
|
||||||
|
if (geometry != null)
|
||||||
|
geometry.Dispose();
|
||||||
|
|
||||||
|
geometry = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,6 +25,9 @@ uniforms
|
||||||
float ignoreNormals;
|
float ignoreNormals;
|
||||||
float lightsEnabled;
|
float lightsEnabled;
|
||||||
|
|
||||||
|
// Slope handle length
|
||||||
|
float slopeHandleLength;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
functions
|
functions
|
||||||
|
@ -356,3 +359,15 @@ shader world3d_main_highlight_fog_vertexcolor extends world3d_main_highlight_fog
|
||||||
v2f.Normal = normalize((modelnormal * vec4(in.Normal, 1.0)).xyz);
|
v2f.Normal = normalize((modelnormal * vec4(in.Normal, 1.0)).xyz);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Slope handle shader
|
||||||
|
shader world3d_slope_handle extends world3d_vertex_color
|
||||||
|
{
|
||||||
|
vertex
|
||||||
|
{
|
||||||
|
v2f.viewpos = view * world * vec4(in.Position.x * slopeHandleLength, in.Position.y, in.Position.z, 1.0);
|
||||||
|
gl_Position = projection * v2f.viewpos;
|
||||||
|
v2f.Color = in.Color * vertexColor;
|
||||||
|
v2f.UV = in.TextureCoordinate;
|
||||||
|
}
|
||||||
|
}
|
|
@ -30,6 +30,12 @@ using CodeImp.DoomBuilder.Editing;
|
||||||
|
|
||||||
namespace CodeImp.DoomBuilder.VisualModes
|
namespace CodeImp.DoomBuilder.VisualModes
|
||||||
{
|
{
|
||||||
|
public enum PickingMode
|
||||||
|
{
|
||||||
|
Default,
|
||||||
|
SlopeHandles
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Provides specialized functionality for a visual (3D) Doom Builder editing mode.
|
/// Provides specialized functionality for a visual (3D) Doom Builder editing mode.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -68,10 +74,14 @@ namespace CodeImp.DoomBuilder.VisualModes
|
||||||
private Vector3D playerStartPosition;
|
private Vector3D playerStartPosition;
|
||||||
private float playerStartAngle;
|
private float playerStartAngle;
|
||||||
|
|
||||||
|
// For picking
|
||||||
|
protected PickingMode pickingmode;
|
||||||
|
|
||||||
// Map
|
// Map
|
||||||
protected VisualBlockMap blockmap;
|
protected VisualBlockMap blockmap;
|
||||||
protected Dictionary<Thing, VisualThing> allthings;
|
protected Dictionary<Thing, VisualThing> allthings;
|
||||||
protected Dictionary<Sector, VisualSector> allsectors;
|
protected Dictionary<Sector, VisualSector> allsectors;
|
||||||
|
protected Dictionary<Sector, List<VisualSlope>> allslopehandles;
|
||||||
protected List<VisualBlockEntry> visibleblocks;
|
protected List<VisualBlockEntry> visibleblocks;
|
||||||
protected List<VisualThing> visiblethings;
|
protected List<VisualThing> visiblethings;
|
||||||
protected List<VisualSector> visiblesectors;
|
protected List<VisualSector> visiblesectors;
|
||||||
|
@ -85,6 +95,7 @@ namespace CodeImp.DoomBuilder.VisualModes
|
||||||
public bool ProcessThings { get { return processthings; } set { processthings = value; } }
|
public bool ProcessThings { get { return processthings; } set { processthings = value; } }
|
||||||
public VisualBlockMap BlockMap { get { return blockmap; } }
|
public VisualBlockMap BlockMap { get { return blockmap; } }
|
||||||
public Dictionary<Vertex, VisualVertexPair> VisualVertices { get { return vertices; } } //mxd
|
public Dictionary<Vertex, VisualVertexPair> VisualVertices { get { return vertices; } } //mxd
|
||||||
|
public Dictionary<Sector, List<VisualSlope>> AllSlopeHandles { get { return allslopehandles; } }
|
||||||
|
|
||||||
// Rendering
|
// Rendering
|
||||||
public IRenderer3D Renderer { get { return renderer; } }
|
public IRenderer3D Renderer { get { return renderer; } }
|
||||||
|
@ -103,6 +114,7 @@ namespace CodeImp.DoomBuilder.VisualModes
|
||||||
this.blockmap = new VisualBlockMap();
|
this.blockmap = new VisualBlockMap();
|
||||||
this.allsectors = new Dictionary<Sector, VisualSector>(General.Map.Map.Sectors.Count);
|
this.allsectors = new Dictionary<Sector, VisualSector>(General.Map.Map.Sectors.Count);
|
||||||
this.allthings = new Dictionary<Thing, VisualThing>(General.Map.Map.Things.Count);
|
this.allthings = new Dictionary<Thing, VisualThing>(General.Map.Map.Things.Count);
|
||||||
|
this.allslopehandles = new Dictionary<Sector, List<VisualSlope>>(General.Map.Map.Sectors.Count);
|
||||||
this.visibleblocks = new List<VisualBlockEntry>();
|
this.visibleblocks = new List<VisualBlockEntry>();
|
||||||
this.visiblesectors = new List<VisualSector>(50);
|
this.visiblesectors = new List<VisualSector>(50);
|
||||||
this.visiblegeometry = new List<VisualGeometry>(200);
|
this.visiblegeometry = new List<VisualGeometry>(200);
|
||||||
|
@ -110,6 +122,7 @@ namespace CodeImp.DoomBuilder.VisualModes
|
||||||
this.processgeometry = true;
|
this.processgeometry = true;
|
||||||
this.processthings = true;
|
this.processthings = true;
|
||||||
this.vertices = new Dictionary<Vertex, VisualVertexPair>(); //mxd
|
this.vertices = new Dictionary<Vertex, VisualVertexPair>(); //mxd
|
||||||
|
this.pickingmode = PickingMode.Default;
|
||||||
|
|
||||||
//mxd. Synch camera position to cursor position or center of the screen in 2d-mode
|
//mxd. Synch camera position to cursor position or center of the screen in 2d-mode
|
||||||
if(General.Settings.GZSynchCameras && General.Editing.Mode is ClassicMode)
|
if(General.Settings.GZSynchCameras && General.Editing.Mode is ClassicMode)
|
||||||
|
@ -720,6 +733,10 @@ namespace CodeImp.DoomBuilder.VisualModes
|
||||||
VisualSector vs = allsectors[General.Map.VisualCamera.Sector];
|
VisualSector vs = allsectors[General.Map.VisualCamera.Sector];
|
||||||
sectors.Add(General.Map.VisualCamera.Sector, vs);
|
sectors.Add(General.Map.VisualCamera.Sector, vs);
|
||||||
foreach(VisualGeometry g in vs.FixedGeometry) pickables.Add(g);
|
foreach(VisualGeometry g in vs.FixedGeometry) pickables.Add(g);
|
||||||
|
|
||||||
|
// Add slope handles
|
||||||
|
if (General.Map.UDMF && pickingmode == PickingMode.SlopeHandles && allslopehandles.ContainsKey(General.Map.VisualCamera.Sector))
|
||||||
|
pickables.AddRange(allslopehandles[General.Map.VisualCamera.Sector]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Go for all lines to see which ones we intersect
|
// Go for all lines to see which ones we intersect
|
||||||
|
@ -758,12 +775,16 @@ namespace CodeImp.DoomBuilder.VisualModes
|
||||||
if(!sectors.ContainsKey(ld.Front.Sector))
|
if(!sectors.ContainsKey(ld.Front.Sector))
|
||||||
{
|
{
|
||||||
sectors.Add(ld.Front.Sector, vs);
|
sectors.Add(ld.Front.Sector, vs);
|
||||||
foreach(VisualGeometry g in vs.FixedGeometry)
|
foreach (VisualGeometry g in vs.FixedGeometry)
|
||||||
{
|
{
|
||||||
// Must have content
|
// Must have content
|
||||||
if(g.Triangles > 0)
|
if (g.Triangles > 0)
|
||||||
pickables.Add(g);
|
pickables.Add(g);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add slope handles
|
||||||
|
if (General.Map.UDMF && pickingmode == PickingMode.SlopeHandles && allslopehandles.ContainsKey(ld.Front.Sector))
|
||||||
|
pickables.AddRange(allslopehandles[ld.Front.Sector]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add sidedef if on the front side
|
// Add sidedef if on the front side
|
||||||
|
@ -795,12 +816,16 @@ namespace CodeImp.DoomBuilder.VisualModes
|
||||||
if(!sectors.ContainsKey(ld.Back.Sector))
|
if(!sectors.ContainsKey(ld.Back.Sector))
|
||||||
{
|
{
|
||||||
sectors.Add(ld.Back.Sector, vs);
|
sectors.Add(ld.Back.Sector, vs);
|
||||||
foreach(VisualGeometry g in vs.FixedGeometry)
|
foreach (VisualGeometry g in vs.FixedGeometry)
|
||||||
{
|
{
|
||||||
// Must have content
|
// Must have content
|
||||||
if(g.Triangles > 0)
|
if (g.Triangles > 0)
|
||||||
pickables.Add(g);
|
pickables.Add(g);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add slope handles
|
||||||
|
if (General.Map.UDMF && pickingmode == PickingMode.SlopeHandles && allslopehandles.ContainsKey(ld.Back.Sector))
|
||||||
|
pickables.AddRange(allslopehandles[ld.Back.Sector]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add sidedef if on the front side
|
// Add sidedef if on the front side
|
||||||
|
@ -828,9 +853,9 @@ namespace CodeImp.DoomBuilder.VisualModes
|
||||||
foreach(VisualThing vt in visiblethings) pickables.Add(vt);
|
foreach(VisualThing vt in visiblethings) pickables.Add(vt);
|
||||||
|
|
||||||
//mxd. And all visual vertices
|
//mxd. And all visual vertices
|
||||||
if(General.Map.UDMF && General.Settings.GZShowVisualVertices)
|
if (General.Map.UDMF && General.Settings.GZShowVisualVertices)
|
||||||
{
|
{
|
||||||
foreach(KeyValuePair<Vertex, VisualVertexPair> pair in vertices)
|
foreach (KeyValuePair<Vertex, VisualVertexPair> pair in vertices)
|
||||||
pickables.AddRange(pair.Value.Vertices);
|
pickables.AddRange(pair.Value.Vertices);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -864,6 +889,11 @@ namespace CodeImp.DoomBuilder.VisualModes
|
||||||
// Setup final result
|
// Setup final result
|
||||||
result.hitpos = from + to * result.u_ray;
|
result.hitpos = from + to * result.u_ray;
|
||||||
|
|
||||||
|
// If picking mode is for slope handles only return slope handles. We have to do it this
|
||||||
|
// way because otherwise it's possible to pick slope handles through other geometry
|
||||||
|
if (pickingmode == PickingMode.SlopeHandles && !(result.picked is VisualSlope))
|
||||||
|
result.picked = null;
|
||||||
|
|
||||||
// Done
|
// Done
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
138
Source/Core/VisualModes/VisualSlope.cs
Normal file
138
Source/Core/VisualModes/VisualSlope.cs
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
using System;
|
||||||
|
using CodeImp.DoomBuilder.Geometry;
|
||||||
|
using CodeImp.DoomBuilder.Map;
|
||||||
|
using CodeImp.DoomBuilder.Rendering;
|
||||||
|
|
||||||
|
namespace CodeImp.DoomBuilder.VisualModes
|
||||||
|
{
|
||||||
|
public abstract class VisualSlope : IVisualPickable
|
||||||
|
{
|
||||||
|
#region ================== Variables
|
||||||
|
|
||||||
|
// Disposing
|
||||||
|
private bool isdisposed;
|
||||||
|
|
||||||
|
// Selected?
|
||||||
|
protected bool selected;
|
||||||
|
|
||||||
|
// Pivot?
|
||||||
|
protected bool pivot;
|
||||||
|
|
||||||
|
// Smart Pivot?
|
||||||
|
protected bool smartpivot;
|
||||||
|
|
||||||
|
// Was changed?
|
||||||
|
private bool changed;
|
||||||
|
|
||||||
|
protected float length;
|
||||||
|
|
||||||
|
private Matrix position;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ================== Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Selected or not? This is only used by the core to determine what color to draw it with.
|
||||||
|
/// </summary>
|
||||||
|
public bool Selected { get { return selected; } set { selected = value; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Pivot or not? This is only used by the core to determine what color to draw it with.
|
||||||
|
/// </summary>
|
||||||
|
public bool Pivot { get { return pivot; } set { pivot = value; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Disposed or not?
|
||||||
|
/// </summary>
|
||||||
|
public bool IsDisposed { get { return isdisposed; } }
|
||||||
|
|
||||||
|
public bool SmartPivot { get { return smartpivot; } set { smartpivot = value; } }
|
||||||
|
|
||||||
|
public bool Changed { get { return changed; } set { changed = value; } }
|
||||||
|
|
||||||
|
public float Length { get { return length; } }
|
||||||
|
|
||||||
|
public Matrix Position { get { return position; } }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ================== Constructor / Destructor
|
||||||
|
|
||||||
|
public VisualSlope()
|
||||||
|
{
|
||||||
|
pivot = false;
|
||||||
|
smartpivot = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ================== Methods
|
||||||
|
|
||||||
|
// This is called before a device is reset (when resized or display adapter was changed)
|
||||||
|
public void UnloadResource()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is called resets when the device is reset
|
||||||
|
// (when resized or display adapter was changed)
|
||||||
|
public void ReloadResource()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This is called when the thing must be tested for line intersection. This should reject
|
||||||
|
/// as fast as possible to rule out all geometry that certainly does not touch the line.
|
||||||
|
/// </summary>
|
||||||
|
public virtual bool PickFastReject(Vector3D from, Vector3D to, Vector3D dir)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This is called when the thing must be tested for line intersection. This should perform
|
||||||
|
/// accurate hit detection and set u_ray to the position on the ray where this hits the geometry.
|
||||||
|
/// </summary>
|
||||||
|
public virtual bool PickAccurate(Vector3D from, Vector3D to, Vector3D dir, ref float u_ray)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Update() {}
|
||||||
|
|
||||||
|
public void SetPosition(Line2D line, Plane plane)
|
||||||
|
{
|
||||||
|
Line3D line3d = new Line3D(new Vector3D(line.v1, plane.GetZ(line.v1)), new Vector3D(line.v2, plane.GetZ(line.v2)));
|
||||||
|
|
||||||
|
// This vector is perpendicular to the line, with a 90° angle between it and the plane normal
|
||||||
|
Vector3D perpendicularvector = Vector3D.CrossProduct(line3d.GetDelta().GetNormal(), plane.Normal) * (-1);
|
||||||
|
|
||||||
|
// This vector is on the plane, with a 90° angle to the perpendicular vector (so effectively
|
||||||
|
// it's on the line, but in 3D
|
||||||
|
Vector3D linevector = Vector3D.CrossProduct(plane.Normal, perpendicularvector) * (-1);
|
||||||
|
|
||||||
|
Matrix m = Matrix.Null;
|
||||||
|
|
||||||
|
m.M11 = linevector.x;
|
||||||
|
m.M12 = linevector.y;
|
||||||
|
m.M13 = linevector.z;
|
||||||
|
|
||||||
|
m.M21 = perpendicularvector.x;
|
||||||
|
m.M22 = perpendicularvector.y;
|
||||||
|
m.M23 = perpendicularvector.z;
|
||||||
|
|
||||||
|
m.M31 = plane.Normal.x;
|
||||||
|
m.M32 = plane.Normal.y;
|
||||||
|
m.M33 = plane.Normal.z;
|
||||||
|
|
||||||
|
m.M44 = 1.0f;
|
||||||
|
|
||||||
|
// The matrix is at the 0,0 origin, so move it to the start vertex of the line
|
||||||
|
Vector3D tp = new Vector3D(line.v1, plane.GetZ(line.v1));
|
||||||
|
|
||||||
|
position = Matrix.Multiply(m, Matrix.Translation(RenderDevice.V3(tp)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
|
@ -495,6 +495,7 @@
|
||||||
<Compile Include="VisualModes\VisualMiddleDouble.cs" />
|
<Compile Include="VisualModes\VisualMiddleDouble.cs" />
|
||||||
<Compile Include="VisualModes\VisualMiddleSingle.cs" />
|
<Compile Include="VisualModes\VisualMiddleSingle.cs" />
|
||||||
<Compile Include="VisualModes\VisualSidedefParts.cs" />
|
<Compile Include="VisualModes\VisualSidedefParts.cs" />
|
||||||
|
<Compile Include="VisualModes\VisualSidedefSlope.cs" />
|
||||||
<Compile Include="VisualModes\VisualUpper.cs" />
|
<Compile Include="VisualModes\VisualUpper.cs" />
|
||||||
<Compile Include="VisualModes\WallPolygon.cs" />
|
<Compile Include="VisualModes\WallPolygon.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -170,6 +170,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
||||||
private ICollection<Vertex> unselectedvertices;
|
private ICollection<Vertex> unselectedvertices;
|
||||||
private ICollection<Linedef> unselectedlines;
|
private ICollection<Linedef> unselectedlines;
|
||||||
private ICollection<Linedef> unstablelines; //mxd
|
private ICollection<Linedef> unstablelines; //mxd
|
||||||
|
private Dictionary<Sector, float[]> slopeheights;
|
||||||
|
|
||||||
// Modification
|
// Modification
|
||||||
private float rotation;
|
private float rotation;
|
||||||
|
@ -1326,6 +1327,32 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
||||||
thingangle.Add(t.Angle);
|
thingangle.Add(t.Angle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get z heights of floor and ceiling slopes (from the center of the sector). This is used
|
||||||
|
// to easily compute the new slope after moving and rotating. We can't simply use the sector
|
||||||
|
// heights, since they might be wrong (as sector heights are technically irrelevant for slopes)
|
||||||
|
// Floor/ceiling heights are stored if there is no slope, but they won't get used anyway
|
||||||
|
// Important: this has to be done before the first call to UpdateGeometry, since that will change
|
||||||
|
// the sector and subsequently the bounding box, but not the slope
|
||||||
|
slopeheights = new Dictionary<Sector, float[]>();
|
||||||
|
|
||||||
|
foreach(Sector s in sectors)
|
||||||
|
{
|
||||||
|
// Make sure the sector has a valid bounding box
|
||||||
|
s.UpdateCache();
|
||||||
|
|
||||||
|
Vector2D center = new Vector2D(s.BBox.X + s.BBox.Width / 2, s.BBox.Y + s.BBox.Height / 2);
|
||||||
|
float floorz = s.FloorHeight;
|
||||||
|
float ceilingz = s.CeilHeight;
|
||||||
|
|
||||||
|
if (!float.IsNaN(s.FloorSlopeOffset))
|
||||||
|
floorz = new Plane(s.FloorSlope, s.FloorSlopeOffset).GetZ(center);
|
||||||
|
|
||||||
|
if (!float.IsNaN(s.CeilSlopeOffset))
|
||||||
|
ceilingz = new Plane(s.CeilSlope, s.CeilSlopeOffset).GetZ(center);
|
||||||
|
|
||||||
|
slopeheights.Add(s, new float[] { floorz, ceilingz });
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate size
|
// Calculate size
|
||||||
size = right - offset;
|
size = right - offset;
|
||||||
|
|
||||||
|
@ -1550,7 +1577,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
||||||
// Update floor slope?
|
// Update floor slope?
|
||||||
if(s.FloorSlope.GetLengthSq() > 0 && !float.IsNaN(s.FloorSlopeOffset / s.FloorSlope.z))
|
if(s.FloorSlope.GetLengthSq() > 0 && !float.IsNaN(s.FloorSlopeOffset / s.FloorSlope.z))
|
||||||
{
|
{
|
||||||
Vector3D center = new Vector3D(s.BBox.X + s.BBox.Width / 2, s.BBox.Y + s.BBox.Height / 2, s.FloorHeight);
|
Vector3D center = new Vector3D(s.BBox.X + s.BBox.Width / 2, s.BBox.Y + s.BBox.Height / 2, slopeheights[s][0]);
|
||||||
Plane p = new Plane(center, s.FloorSlope.GetAngleXY() + rotation + Angle2D.PIHALF, -s.FloorSlope.GetAngleZ(), true);
|
Plane p = new Plane(center, s.FloorSlope.GetAngleXY() + rotation + Angle2D.PIHALF, -s.FloorSlope.GetAngleZ(), true);
|
||||||
s.FloorSlope = p.Normal;
|
s.FloorSlope = p.Normal;
|
||||||
s.FloorSlopeOffset = p.Offset;
|
s.FloorSlopeOffset = p.Offset;
|
||||||
|
@ -1559,7 +1586,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
||||||
// Update ceiling slope?
|
// Update ceiling slope?
|
||||||
if(s.CeilSlope.GetLengthSq() > 0 && !float.IsNaN(s.CeilSlopeOffset / s.CeilSlope.z))
|
if(s.CeilSlope.GetLengthSq() > 0 && !float.IsNaN(s.CeilSlopeOffset / s.CeilSlope.z))
|
||||||
{
|
{
|
||||||
Vector3D center = new Vector3D(s.BBox.X + s.BBox.Width / 2, s.BBox.Y + s.BBox.Height / 2, s.CeilHeight);
|
Vector3D center = new Vector3D(s.BBox.X + s.BBox.Width / 2, s.BBox.Y + s.BBox.Height / 2, slopeheights[s][1]);
|
||||||
Plane p = new Plane(center, s.CeilSlope.GetAngleXY() + rotation + Angle2D.PIHALF, -s.CeilSlope.GetAngleZ(), false);
|
Plane p = new Plane(center, s.CeilSlope.GetAngleXY() + rotation + Angle2D.PIHALF, -s.CeilSlope.GetAngleZ(), false);
|
||||||
s.CeilSlope = p.Normal;
|
s.CeilSlope = p.Normal;
|
||||||
s.CeilSlopeOffset = p.Offset;
|
s.CeilSlopeOffset = p.Offset;
|
||||||
|
|
|
@ -136,6 +136,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
||||||
private bool alphabasedtexturehighlighting; //mxd
|
private bool alphabasedtexturehighlighting; //mxd
|
||||||
private bool showlightradii; //mxd
|
private bool showlightradii; //mxd
|
||||||
private bool showsoundradii; //mxd
|
private bool showsoundradii; //mxd
|
||||||
|
private int scaletexturesonslopes; // 0 = base scale of 1, 1 = use current scale as base, 2 = don't scale
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
@ -189,6 +190,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
||||||
public bool AlphaBasedTextureHighlighting { get { return alphabasedtexturehighlighting; } internal set { alphabasedtexturehighlighting = value; } } //mxd
|
public bool AlphaBasedTextureHighlighting { get { return alphabasedtexturehighlighting; } internal set { alphabasedtexturehighlighting = value; } } //mxd
|
||||||
public bool ShowLightRadii { get { return showlightradii; } internal set { showlightradii = value; } } //mxd
|
public bool ShowLightRadii { get { return showlightradii; } internal set { showlightradii = value; } } //mxd
|
||||||
public bool ShowSoundRadii { get { return showsoundradii; } internal set { showsoundradii = value; } } //mxd
|
public bool ShowSoundRadii { get { return showsoundradii; } internal set { showsoundradii = value; } } //mxd
|
||||||
|
public int ScaleTexturesOnSlopes { get { return scaletexturesonslopes; } internal set { scaletexturesonslopes = value; } }
|
||||||
|
|
||||||
//mxd. "Make Door" action persistent settings
|
//mxd. "Make Door" action persistent settings
|
||||||
internal MakeDoorSettings MakeDoor;
|
internal MakeDoorSettings MakeDoor;
|
||||||
|
@ -291,6 +293,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
||||||
autoAlignTextureOffsetsOnCreate = General.Settings.ReadPluginSetting("autoaligntextureoffsetsoncreate", false); //mxd
|
autoAlignTextureOffsetsOnCreate = General.Settings.ReadPluginSetting("autoaligntextureoffsetsoncreate", false); //mxd
|
||||||
dontMoveGeometryOutsideMapBoundary = General.Settings.ReadPluginSetting("dontmovegeometryoutsidemapboundary", false); //mxd
|
dontMoveGeometryOutsideMapBoundary = General.Settings.ReadPluginSetting("dontmovegeometryoutsidemapboundary", false); //mxd
|
||||||
syncSelection = General.Settings.ReadPluginSetting("syncselection", false); //mxd
|
syncSelection = General.Settings.ReadPluginSetting("syncselection", false); //mxd
|
||||||
|
scaletexturesonslopes = General.Settings.ReadPluginSetting("scaletexturesonslopes", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
//mxd. Load settings, which can be changed via UI
|
//mxd. Load settings, which can be changed via UI
|
||||||
|
|
|
@ -40,6 +40,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
||||||
this.defaultbrightness = new CodeImp.DoomBuilder.Controls.ButtonsNumericTextbox();
|
this.defaultbrightness = new CodeImp.DoomBuilder.Controls.ButtonsNumericTextbox();
|
||||||
this.label11 = new System.Windows.Forms.Label();
|
this.label11 = new System.Windows.Forms.Label();
|
||||||
this.groupBox3 = new System.Windows.Forms.GroupBox();
|
this.groupBox3 = new System.Windows.Forms.GroupBox();
|
||||||
|
this.additivepaintselect = new System.Windows.Forms.CheckBox();
|
||||||
this.switchviewmodes = new System.Windows.Forms.CheckBox();
|
this.switchviewmodes = new System.Windows.Forms.CheckBox();
|
||||||
this.autodrawonedit = new System.Windows.Forms.CheckBox();
|
this.autodrawonedit = new System.Windows.Forms.CheckBox();
|
||||||
this.syncSelection = new System.Windows.Forms.CheckBox();
|
this.syncSelection = new System.Windows.Forms.CheckBox();
|
||||||
|
@ -72,7 +73,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
||||||
this.label10 = new System.Windows.Forms.Label();
|
this.label10 = new System.Windows.Forms.Label();
|
||||||
this.label1 = new System.Windows.Forms.Label();
|
this.label1 = new System.Windows.Forms.Label();
|
||||||
this.heightbysidedef = new System.Windows.Forms.ComboBox();
|
this.heightbysidedef = new System.Windows.Forms.ComboBox();
|
||||||
this.additivepaintselect = new System.Windows.Forms.CheckBox();
|
this.label18 = new System.Windows.Forms.Label();
|
||||||
|
this.scaletexturesonslopes = new System.Windows.Forms.ComboBox();
|
||||||
this.tabs.SuspendLayout();
|
this.tabs.SuspendLayout();
|
||||||
this.taboptions.SuspendLayout();
|
this.taboptions.SuspendLayout();
|
||||||
this.groupBox4.SuspendLayout();
|
this.groupBox4.SuspendLayout();
|
||||||
|
@ -120,7 +122,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
||||||
this.groupBox4.Controls.Add(this.label12);
|
this.groupBox4.Controls.Add(this.label12);
|
||||||
this.groupBox4.Controls.Add(this.defaultbrightness);
|
this.groupBox4.Controls.Add(this.defaultbrightness);
|
||||||
this.groupBox4.Controls.Add(this.label11);
|
this.groupBox4.Controls.Add(this.label11);
|
||||||
this.groupBox4.Location = new System.Drawing.Point(6, 300);
|
this.groupBox4.Location = new System.Drawing.Point(6, 335);
|
||||||
this.groupBox4.Name = "groupBox4";
|
this.groupBox4.Name = "groupBox4";
|
||||||
this.groupBox4.Size = new System.Drawing.Size(272, 136);
|
this.groupBox4.Size = new System.Drawing.Size(272, 136);
|
||||||
this.groupBox4.TabIndex = 2;
|
this.groupBox4.TabIndex = 2;
|
||||||
|
@ -240,13 +242,23 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
||||||
this.groupBox3.Controls.Add(this.editnewthing);
|
this.groupBox3.Controls.Add(this.editnewthing);
|
||||||
this.groupBox3.Controls.Add(this.editnewsector);
|
this.groupBox3.Controls.Add(this.editnewsector);
|
||||||
this.groupBox3.Controls.Add(this.additiveselect);
|
this.groupBox3.Controls.Add(this.additiveselect);
|
||||||
this.groupBox3.Location = new System.Drawing.Point(284, 104);
|
this.groupBox3.Location = new System.Drawing.Point(284, 139);
|
||||||
this.groupBox3.Name = "groupBox3";
|
this.groupBox3.Name = "groupBox3";
|
||||||
this.groupBox3.Size = new System.Drawing.Size(379, 332);
|
this.groupBox3.Size = new System.Drawing.Size(379, 332);
|
||||||
this.groupBox3.TabIndex = 3;
|
this.groupBox3.TabIndex = 3;
|
||||||
this.groupBox3.TabStop = false;
|
this.groupBox3.TabStop = false;
|
||||||
this.groupBox3.Text = " Options ";
|
this.groupBox3.Text = " Options ";
|
||||||
//
|
//
|
||||||
|
// additivepaintselect
|
||||||
|
//
|
||||||
|
this.additivepaintselect.AutoSize = true;
|
||||||
|
this.additivepaintselect.Location = new System.Drawing.Point(13, 135);
|
||||||
|
this.additivepaintselect.Name = "additivepaintselect";
|
||||||
|
this.additivepaintselect.Size = new System.Drawing.Size(233, 17);
|
||||||
|
this.additivepaintselect.TabIndex = 11;
|
||||||
|
this.additivepaintselect.Text = "Additive paint selecting without holding Shift";
|
||||||
|
this.additivepaintselect.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
// switchviewmodes
|
// switchviewmodes
|
||||||
//
|
//
|
||||||
this.switchviewmodes.AutoSize = true;
|
this.switchviewmodes.AutoSize = true;
|
||||||
|
@ -375,7 +387,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
||||||
this.groupBox2.Controls.Add(this.label6);
|
this.groupBox2.Controls.Add(this.label6);
|
||||||
this.groupBox2.Controls.Add(this.label4);
|
this.groupBox2.Controls.Add(this.label4);
|
||||||
this.groupBox2.Controls.Add(this.label7);
|
this.groupBox2.Controls.Add(this.label7);
|
||||||
this.groupBox2.Location = new System.Drawing.Point(6, 104);
|
this.groupBox2.Location = new System.Drawing.Point(6, 139);
|
||||||
this.groupBox2.Name = "groupBox2";
|
this.groupBox2.Name = "groupBox2";
|
||||||
this.groupBox2.Size = new System.Drawing.Size(272, 190);
|
this.groupBox2.Size = new System.Drawing.Size(272, 190);
|
||||||
this.groupBox2.TabIndex = 1;
|
this.groupBox2.TabIndex = 1;
|
||||||
|
@ -569,13 +581,15 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
||||||
//
|
//
|
||||||
// groupBox1
|
// groupBox1
|
||||||
//
|
//
|
||||||
|
this.groupBox1.Controls.Add(this.scaletexturesonslopes);
|
||||||
|
this.groupBox1.Controls.Add(this.label18);
|
||||||
this.groupBox1.Controls.Add(this.splitbehavior);
|
this.groupBox1.Controls.Add(this.splitbehavior);
|
||||||
this.groupBox1.Controls.Add(this.label10);
|
this.groupBox1.Controls.Add(this.label10);
|
||||||
this.groupBox1.Controls.Add(this.label1);
|
this.groupBox1.Controls.Add(this.label1);
|
||||||
this.groupBox1.Controls.Add(this.heightbysidedef);
|
this.groupBox1.Controls.Add(this.heightbysidedef);
|
||||||
this.groupBox1.Location = new System.Drawing.Point(6, 6);
|
this.groupBox1.Location = new System.Drawing.Point(6, 6);
|
||||||
this.groupBox1.Name = "groupBox1";
|
this.groupBox1.Name = "groupBox1";
|
||||||
this.groupBox1.Size = new System.Drawing.Size(657, 92);
|
this.groupBox1.Size = new System.Drawing.Size(657, 127);
|
||||||
this.groupBox1.TabIndex = 0;
|
this.groupBox1.TabIndex = 0;
|
||||||
this.groupBox1.TabStop = false;
|
this.groupBox1.TabStop = false;
|
||||||
this.groupBox1.Text = " Behavior ";
|
this.groupBox1.Text = " Behavior ";
|
||||||
|
@ -607,7 +621,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
||||||
// label1
|
// label1
|
||||||
//
|
//
|
||||||
this.label1.AutoSize = true;
|
this.label1.AutoSize = true;
|
||||||
this.label1.Location = new System.Drawing.Point(9, 22);
|
this.label1.Location = new System.Drawing.Point(15, 22);
|
||||||
this.label1.Name = "label1";
|
this.label1.Name = "label1";
|
||||||
this.label1.Size = new System.Drawing.Size(308, 13);
|
this.label1.Size = new System.Drawing.Size(308, 13);
|
||||||
this.label1.TabIndex = 0;
|
this.label1.TabIndex = 0;
|
||||||
|
@ -628,15 +642,28 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
||||||
this.heightbysidedef.Size = new System.Drawing.Size(309, 21);
|
this.heightbysidedef.Size = new System.Drawing.Size(309, 21);
|
||||||
this.heightbysidedef.TabIndex = 0;
|
this.heightbysidedef.TabIndex = 0;
|
||||||
//
|
//
|
||||||
// additivepaintselect
|
// label18
|
||||||
//
|
//
|
||||||
this.additivepaintselect.AutoSize = true;
|
this.label18.AutoSize = true;
|
||||||
this.additivepaintselect.Location = new System.Drawing.Point(13, 135);
|
this.label18.Location = new System.Drawing.Point(133, 94);
|
||||||
this.additivepaintselect.Name = "additivepaintselect";
|
this.label18.Name = "label18";
|
||||||
this.additivepaintselect.Size = new System.Drawing.Size(233, 17);
|
this.label18.Size = new System.Drawing.Size(190, 13);
|
||||||
this.additivepaintselect.TabIndex = 11;
|
this.label18.TabIndex = 2;
|
||||||
this.additivepaintselect.Text = "Additive paint selecting without holding Shift";
|
this.label18.Text = "When auto-aligning textures on slopes:";
|
||||||
this.additivepaintselect.UseVisualStyleBackColor = true;
|
this.label18.TextAlign = System.Drawing.ContentAlignment.TopRight;
|
||||||
|
//
|
||||||
|
// scaletexturesonslopes
|
||||||
|
//
|
||||||
|
this.scaletexturesonslopes.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||||
|
this.scaletexturesonslopes.FormattingEnabled = true;
|
||||||
|
this.scaletexturesonslopes.Items.AddRange(new object[] {
|
||||||
|
"Use a scale of 1 as base",
|
||||||
|
"Use current scale as base",
|
||||||
|
"Don\'t scale"});
|
||||||
|
this.scaletexturesonslopes.Location = new System.Drawing.Point(342, 91);
|
||||||
|
this.scaletexturesonslopes.Name = "scaletexturesonslopes";
|
||||||
|
this.scaletexturesonslopes.Size = new System.Drawing.Size(309, 21);
|
||||||
|
this.scaletexturesonslopes.TabIndex = 3;
|
||||||
//
|
//
|
||||||
// PreferencesForm
|
// PreferencesForm
|
||||||
//
|
//
|
||||||
|
@ -710,5 +737,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
||||||
private System.Windows.Forms.Label label16;
|
private System.Windows.Forms.Label label16;
|
||||||
private System.Windows.Forms.Label label17;
|
private System.Windows.Forms.Label label17;
|
||||||
private System.Windows.Forms.CheckBox additivepaintselect;
|
private System.Windows.Forms.CheckBox additivepaintselect;
|
||||||
|
private System.Windows.Forms.ComboBox scaletexturesonslopes;
|
||||||
|
private System.Windows.Forms.Label label18;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -64,6 +64,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
||||||
defaultbrightness.Text = General.Settings.DefaultBrightness.ToString(); //mxd
|
defaultbrightness.Text = General.Settings.DefaultBrightness.ToString(); //mxd
|
||||||
defaultceilheight.Text = General.Settings.DefaultCeilingHeight.ToString();//mxd
|
defaultceilheight.Text = General.Settings.DefaultCeilingHeight.ToString();//mxd
|
||||||
defaultfloorheight.Text = General.Settings.DefaultFloorHeight.ToString(); //mxd
|
defaultfloorheight.Text = General.Settings.DefaultFloorHeight.ToString(); //mxd
|
||||||
|
scaletexturesonslopes.SelectedIndex = General.Settings.ReadPluginSetting("scaletexturesonslopes", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -91,9 +92,11 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
||||||
General.Settings.WritePluginSetting("autoaligntextureoffsetsoncreate", autoaligntexturesoncreate.Checked);//mxd
|
General.Settings.WritePluginSetting("autoaligntextureoffsetsoncreate", autoaligntexturesoncreate.Checked);//mxd
|
||||||
General.Settings.WritePluginSetting("dontmovegeometryoutsidemapboundary", dontMoveGeometryOutsideBounds.Checked);//mxd
|
General.Settings.WritePluginSetting("dontmovegeometryoutsidemapboundary", dontMoveGeometryOutsideBounds.Checked);//mxd
|
||||||
General.Settings.WritePluginSetting("syncselection", syncSelection.Checked);//mxd
|
General.Settings.WritePluginSetting("syncselection", syncSelection.Checked);//mxd
|
||||||
|
General.Settings.WritePluginSetting("scaletexturesonslopes", scaletexturesonslopes.SelectedIndex);
|
||||||
General.Settings.SwitchViewModes = switchviewmodes.Checked; //mxd
|
General.Settings.SwitchViewModes = switchviewmodes.Checked; //mxd
|
||||||
General.Settings.SplitLineBehavior = (SplitLineBehavior)splitbehavior.SelectedIndex;//mxd
|
General.Settings.SplitLineBehavior = (SplitLineBehavior)splitbehavior.SelectedIndex;//mxd
|
||||||
|
|
||||||
|
|
||||||
//default sector values
|
//default sector values
|
||||||
General.Settings.DefaultBrightness = General.Clamp(defaultbrightness.GetResult(192), 0, 255);
|
General.Settings.DefaultBrightness = General.Clamp(defaultbrightness.GetResult(192), 0, 255);
|
||||||
|
|
||||||
|
|
|
@ -1405,3 +1405,25 @@ visualpaintselect
|
||||||
disregardcontrol = true;
|
disregardcontrol = true;
|
||||||
disregardalt = true;
|
disregardalt = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
togglevisualslopepicking
|
||||||
|
{
|
||||||
|
title = "Toggle Visual Slope Picking";
|
||||||
|
category = "visual";
|
||||||
|
description = "Toggles picking visual slope handles.";
|
||||||
|
allowkeys = true;
|
||||||
|
allowmouse = true;
|
||||||
|
allowscroll = false;
|
||||||
|
default = 65623; // Shift-W
|
||||||
|
}
|
||||||
|
|
||||||
|
slopebetweenhandles
|
||||||
|
{
|
||||||
|
title = "Slope Between Handles";
|
||||||
|
category = "visual";
|
||||||
|
description = "Slopes the selected floors and ceilings between the selected slope handles.";
|
||||||
|
allowkeys = true;
|
||||||
|
allowmouse = true;
|
||||||
|
allowscroll = false;
|
||||||
|
default = 131142; // Ctrl-F
|
||||||
|
}
|
|
@ -298,6 +298,32 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
||||||
//update angle
|
//update angle
|
||||||
UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "rotationfloor" : "rotationceiling"), sourceAngle, 0f);
|
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
|
//set scale
|
||||||
UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "xscalefloor" : "xscaleceiling"), scaleX, 1.0f);
|
UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "xscalefloor" : "xscaleceiling"), scaleX, 1.0f);
|
||||||
UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "yscalefloor" : "yscaleceiling"), scaleY, 1.0f);
|
UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "yscalefloor" : "yscaleceiling"), scaleY, 1.0f);
|
||||||
|
@ -323,96 +349,6 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
||||||
Sector.UpdateSectorGeometry(false);
|
Sector.UpdateSectorGeometry(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
//mxd
|
|
||||||
protected void AlignTextureToSlopeLine(Linedef slopeSource, float slopeAngle, bool isFront, bool alignx, bool aligny)
|
|
||||||
{
|
|
||||||
bool isFloor = (geometrytype == VisualGeometryType.FLOOR);
|
|
||||||
Sector.Sector.Fields.BeforeFieldsChange();
|
|
||||||
float sourceAngle = (float)Math.Round(General.ClampAngle(isFront ? -Angle2D.RadToDeg(slopeSource.Angle) + 90 : -Angle2D.RadToDeg(slopeSource.Angle) - 90), 1);
|
|
||||||
|
|
||||||
if(isFloor)
|
|
||||||
{
|
|
||||||
if((isFront && slopeSource.Front.Sector.FloorHeight > slopeSource.Back.Sector.FloorHeight) ||
|
|
||||||
(!isFront && slopeSource.Front.Sector.FloorHeight < slopeSource.Back.Sector.FloorHeight))
|
|
||||||
{
|
|
||||||
sourceAngle = General.ClampAngle(sourceAngle + 180);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if((isFront && slopeSource.Front.Sector.CeilHeight < slopeSource.Back.Sector.CeilHeight) ||
|
|
||||||
(!isFront && slopeSource.Front.Sector.CeilHeight > slopeSource.Back.Sector.CeilHeight))
|
|
||||||
{
|
|
||||||
sourceAngle = General.ClampAngle(sourceAngle + 180);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//update angle
|
|
||||||
UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "rotationfloor" : "rotationceiling"), sourceAngle, 0f);
|
|
||||||
|
|
||||||
//update scaleY
|
|
||||||
string xScaleKey = (isFloor ? "xscalefloor" : "xscaleceiling");
|
|
||||||
string yScaleKey = (isFloor ? "yscalefloor" : "yscaleceiling");
|
|
||||||
|
|
||||||
float scaleX = Sector.Sector.Fields.GetValue(xScaleKey, 1.0f);
|
|
||||||
float scaleY;
|
|
||||||
|
|
||||||
//set scale
|
|
||||||
if(aligny)
|
|
||||||
{
|
|
||||||
scaleY = (float)Math.Round(scaleX * (1 / (float)Math.Cos(slopeAngle)), 2);
|
|
||||||
UniFields.SetFloat(Sector.Sector.Fields, yScaleKey, scaleY, 1.0f);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
scaleY = Sector.Sector.Fields.GetValue(yScaleKey, 1.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
//update texture offsets
|
|
||||||
Vector2D offset;
|
|
||||||
if(isFloor)
|
|
||||||
{
|
|
||||||
if((isFront && slopeSource.Front.Sector.FloorHeight < slopeSource.Back.Sector.FloorHeight) ||
|
|
||||||
(!isFront && slopeSource.Front.Sector.FloorHeight > slopeSource.Back.Sector.FloorHeight))
|
|
||||||
{
|
|
||||||
offset = slopeSource.End.Position;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
offset = slopeSource.Start.Position;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if((isFront && slopeSource.Front.Sector.CeilHeight > slopeSource.Back.Sector.CeilHeight) ||
|
|
||||||
(!isFront && slopeSource.Front.Sector.CeilHeight < slopeSource.Back.Sector.CeilHeight))
|
|
||||||
{
|
|
||||||
offset = slopeSource.End.Position;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
offset = slopeSource.Start.Position;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
offset = offset.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
|
//mxd
|
||||||
protected void ClearFields(IEnumerable<string> keys, string undodescription, string resultdescription)
|
protected void ClearFields(IEnumerable<string> keys, string undodescription, string resultdescription)
|
||||||
{
|
{
|
||||||
|
@ -878,6 +814,14 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
||||||
}
|
}
|
||||||
|
|
||||||
if(vs != null) vs.UpdateSectorGeometry(true);
|
if(vs != null) vs.UpdateSectorGeometry(true);
|
||||||
|
|
||||||
|
// Visual slope handles need to be updated, too
|
||||||
|
if (General.Map.UDMF)
|
||||||
|
{
|
||||||
|
if (mode.AllSlopeHandles.ContainsKey(level.sector))
|
||||||
|
foreach (VisualSidedefSlope handle in mode.AllSlopeHandles[level.sector])
|
||||||
|
handle.Changed = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sector brightness change
|
// Sector brightness change
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -391,6 +391,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
||||||
//mxd. Modify slope offset?
|
//mxd. Modify slope offset?
|
||||||
if(level.sector.CeilSlope.GetLengthSq() > 0)
|
if(level.sector.CeilSlope.GetLengthSq() > 0)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
Vector3D center = new Vector3D(level.sector.BBox.X + level.sector.BBox.Width / 2,
|
Vector3D center = new Vector3D(level.sector.BBox.X + level.sector.BBox.Width / 2,
|
||||||
level.sector.BBox.Y + level.sector.BBox.Height / 2,
|
level.sector.BBox.Y + level.sector.BBox.Height / 2,
|
||||||
level.sector.CeilHeight);
|
level.sector.CeilHeight);
|
||||||
|
@ -401,6 +402,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
||||||
false);
|
false);
|
||||||
|
|
||||||
level.sector.CeilSlopeOffset = p.Offset;
|
level.sector.CeilSlopeOffset = p.Offset;
|
||||||
|
*/
|
||||||
|
|
||||||
|
level.sector.CeilSlopeOffset -= level.sector.CeilSlope.z * amount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -650,42 +654,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
||||||
{
|
{
|
||||||
if(!General.Map.UDMF) return;
|
if(!General.Map.UDMF) return;
|
||||||
|
|
||||||
//is is a surface with line slope?
|
AlignTextureToClosestLine(alignx, aligny);
|
||||||
float slopeAngle = level.plane.Normal.GetAngleZ() - Angle2D.PIHALF;
|
|
||||||
|
|
||||||
if(slopeAngle == 0) //it's a horizontal plane
|
|
||||||
{
|
|
||||||
AlignTextureToClosestLine(alignx, aligny);
|
|
||||||
}
|
|
||||||
else //it can be a surface with line slope
|
|
||||||
{
|
|
||||||
Linedef slopeSource = null;
|
|
||||||
bool isFront = false;
|
|
||||||
|
|
||||||
foreach(Sidedef side in Sector.Sector.Sidedefs)
|
|
||||||
{
|
|
||||||
if(side.Line.Action == 181)
|
|
||||||
{
|
|
||||||
if(side.Line.Args[1] == 1 && side.Line.Front != null && side.Line.Front == side)
|
|
||||||
{
|
|
||||||
slopeSource = side.Line;
|
|
||||||
isFront = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(side.Line.Args[1] == 2 && side.Line.Back != null && side.Line.Back == side)
|
|
||||||
{
|
|
||||||
slopeSource = side.Line;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(slopeSource != null && slopeSource.Front != null && slopeSource.Front.Sector != null && slopeSource.Back != null && slopeSource.Back.Sector != null)
|
|
||||||
AlignTextureToSlopeLine(slopeSource, slopeAngle, isFront, alignx, aligny);
|
|
||||||
else
|
|
||||||
AlignTextureToClosestLine(alignx, aligny);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
|
@ -351,6 +351,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
||||||
//mxd. Modify slope offset?
|
//mxd. Modify slope offset?
|
||||||
if(level.sector.FloorSlope.GetLengthSq() > 0)
|
if(level.sector.FloorSlope.GetLengthSq() > 0)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
Vector3D center = new Vector3D(level.sector.BBox.X + level.sector.BBox.Width / 2,
|
Vector3D center = new Vector3D(level.sector.BBox.X + level.sector.BBox.Width / 2,
|
||||||
level.sector.BBox.Y + level.sector.BBox.Height / 2,
|
level.sector.BBox.Y + level.sector.BBox.Height / 2,
|
||||||
level.sector.FloorHeight);
|
level.sector.FloorHeight);
|
||||||
|
@ -361,6 +362,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
||||||
true);
|
true);
|
||||||
|
|
||||||
level.sector.FloorSlopeOffset = p.Offset;
|
level.sector.FloorSlopeOffset = p.Offset;
|
||||||
|
*/
|
||||||
|
|
||||||
|
level.sector.FloorSlopeOffset -= level.sector.FloorSlope.z * amount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -582,42 +586,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
||||||
{
|
{
|
||||||
if(!General.Map.UDMF) return;
|
if(!General.Map.UDMF) return;
|
||||||
|
|
||||||
//is is a surface with line slope?
|
AlignTextureToClosestLine(alignx, aligny);
|
||||||
float slopeAngle = level.plane.Normal.GetAngleZ() - Angle2D.PIHALF;
|
|
||||||
|
|
||||||
if(slopeAngle == 0) //it's a horizontal plane
|
|
||||||
{
|
|
||||||
AlignTextureToClosestLine(alignx, aligny);
|
|
||||||
}
|
|
||||||
else //it can be a surface with line slope
|
|
||||||
{
|
|
||||||
Linedef slopeSource = null;
|
|
||||||
bool isFront = false;
|
|
||||||
|
|
||||||
foreach(Sidedef side in Sector.Sector.Sidedefs)
|
|
||||||
{
|
|
||||||
if(side.Line.Action == 181)
|
|
||||||
{
|
|
||||||
if(side.Line.Args[0] == 1 && side.Line.Front != null && side.Line.Front == side)
|
|
||||||
{
|
|
||||||
slopeSource = side.Line;
|
|
||||||
isFront = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(side.Line.Args[0] == 2 && side.Line.Back != null && side.Line.Back == side)
|
|
||||||
{
|
|
||||||
slopeSource = side.Line;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(slopeSource != null && slopeSource.Front != null && slopeSource.Front.Sector != null && slopeSource.Back != null && slopeSource.Back.Sector != null)
|
|
||||||
AlignTextureToSlopeLine(slopeSource, slopeAngle, isFront, alignx, aligny);
|
|
||||||
else
|
|
||||||
AlignTextureToClosestLine(alignx, aligny);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
412
Source/Plugins/BuilderModes/VisualModes/VisualSidedefSlope.cs
Normal file
412
Source/Plugins/BuilderModes/VisualModes/VisualSidedefSlope.cs
Normal file
|
@ -0,0 +1,412 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using CodeImp.DoomBuilder.BuilderModes;
|
||||||
|
using CodeImp.DoomBuilder.Geometry;
|
||||||
|
using CodeImp.DoomBuilder.Map;
|
||||||
|
using CodeImp.DoomBuilder.Rendering;
|
||||||
|
|
||||||
|
namespace CodeImp.DoomBuilder.VisualModes
|
||||||
|
{
|
||||||
|
internal class VisualSidedefSlope : VisualSlope, IVisualEventReceiver
|
||||||
|
{
|
||||||
|
#region ================== Variables
|
||||||
|
|
||||||
|
private readonly BaseVisualMode mode;
|
||||||
|
private readonly Sidedef sidedef;
|
||||||
|
private readonly SectorLevel level;
|
||||||
|
private readonly bool up;
|
||||||
|
private Vector3D pickintersect;
|
||||||
|
private float pickrayu;
|
||||||
|
private Plane plane;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ================== Constants
|
||||||
|
|
||||||
|
private const int SIZE = 8;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ================== Properties
|
||||||
|
|
||||||
|
public Sidedef Sidedef { get { return sidedef; } }
|
||||||
|
public SectorLevel Level { get { return level; } }
|
||||||
|
public int NormalizedAngleDeg { get { return (sidedef.Line.AngleDeg >= 180) ? (sidedef.Line.AngleDeg - 180) : sidedef.Line.AngleDeg; } }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ================== Constructor / Destructor
|
||||||
|
|
||||||
|
public VisualSidedefSlope(BaseVisualMode mode, SectorLevel level, Sidedef sidedef, bool up) : base()
|
||||||
|
{
|
||||||
|
this.mode = mode;
|
||||||
|
this.sidedef = sidedef;
|
||||||
|
this.level = level;
|
||||||
|
this.up = up;
|
||||||
|
|
||||||
|
// length = sidedef.Line.Length;
|
||||||
|
|
||||||
|
Update();
|
||||||
|
|
||||||
|
// We have no destructor
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ================== Methods
|
||||||
|
|
||||||
|
public Vector3D GetCenterPoint()
|
||||||
|
{
|
||||||
|
Vector2D p = sidedef.Line.GetCenterPoint();
|
||||||
|
return new Vector3D(p, level.plane.GetZ(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Update()
|
||||||
|
{
|
||||||
|
plane = new Plane(level.plane.Normal, level.plane.Offset - 0.1f);
|
||||||
|
|
||||||
|
if (!up)
|
||||||
|
plane = plane.GetInverted();
|
||||||
|
|
||||||
|
UpdatePosition();
|
||||||
|
|
||||||
|
length = new Line3D(new Vector3D(sidedef.Line.Line.v1, plane.GetZ(sidedef.Line.Line.v1)), new Vector3D(sidedef.Line.Line.v2, plane.GetZ(sidedef.Line.Line.v2))).GetDelta().GetLength();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This is called when the thing must be tested for line intersection. This should reject
|
||||||
|
/// as fast as possible to rule out all geometry that certainly does not touch the line.
|
||||||
|
/// </summary>
|
||||||
|
public override bool PickFastReject(Vector3D from, Vector3D to, Vector3D dir)
|
||||||
|
{
|
||||||
|
RectangleF bbox = sidedef.Sector.BBox;
|
||||||
|
|
||||||
|
if ((up && plane.Distance(from) > 0.0f) || (!up && plane.Distance(from) < 0.0f))
|
||||||
|
{
|
||||||
|
if (plane.GetIntersection(from, to, ref pickrayu))
|
||||||
|
{
|
||||||
|
if (pickrayu > 0.0f)
|
||||||
|
{
|
||||||
|
pickintersect = from + (to - from) * pickrayu;
|
||||||
|
|
||||||
|
return ((pickintersect.x >= bbox.Left) && (pickintersect.x <= bbox.Right) &&
|
||||||
|
(pickintersect.y >= bbox.Top) && (pickintersect.y <= bbox.Bottom));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This is called when the thing must be tested for line intersection. This should perform
|
||||||
|
/// accurate hit detection and set u_ray to the position on the ray where this hits the geometry.
|
||||||
|
/// </summary>
|
||||||
|
public override bool PickAccurate(Vector3D from, Vector3D to, Vector3D dir, ref float u_ray)
|
||||||
|
{
|
||||||
|
u_ray = pickrayu;
|
||||||
|
|
||||||
|
Sidedef sd = MapSet.NearestSidedef(sidedef.Sector.Sidedefs, pickintersect);
|
||||||
|
if (sd == sidedef) {
|
||||||
|
float side = sd.Line.SideOfLine(pickintersect);
|
||||||
|
|
||||||
|
if ((side <= 0.0f && sd.IsFront) || (side > 0.0f && !sd.IsFront))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the position. Depending on 3D floors and which side of the linedef the slope handle is on the
|
||||||
|
/// direction of the line used as a base has to be inverted
|
||||||
|
/// </summary>
|
||||||
|
public void UpdatePosition()
|
||||||
|
{
|
||||||
|
bool invertline = false;
|
||||||
|
|
||||||
|
if (up)
|
||||||
|
{
|
||||||
|
if (level.extrafloor && level.type == SectorLevelType.Ceiling)
|
||||||
|
{
|
||||||
|
if (sidedef.IsFront)
|
||||||
|
invertline = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!sidedef.IsFront)
|
||||||
|
invertline = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (level.extrafloor && level.type == SectorLevelType.Floor)
|
||||||
|
{
|
||||||
|
if (!sidedef.IsFront)
|
||||||
|
invertline = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (sidedef.IsFront)
|
||||||
|
invertline = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (invertline)
|
||||||
|
SetPosition(new Line2D(sidedef.Line.End.Position, sidedef.Line.Start.Position), level.plane);
|
||||||
|
else
|
||||||
|
SetPosition(sidedef.Line.Line, level.plane);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to find a slope handle to pivot around. If possible if finds the handle belonging to a line that has the
|
||||||
|
/// same angle as the start handle, and is the furthest away. If such a handle does not exist it finds one that's
|
||||||
|
/// closest to those specs
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="starthandle">The slope handle to start from (the one we need to find a pivot handle for)</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static VisualSidedefSlope GetSmartPivotHandle(VisualSidedefSlope starthandle, BaseVisualMode mode)
|
||||||
|
{
|
||||||
|
VisualSidedefSlope handle = starthandle;
|
||||||
|
List<VisualSidedefSlope> potentialhandles = new List<VisualSidedefSlope>();
|
||||||
|
List<IVisualEventReceiver> selectedsectors = mode.GetSelectedObjects(true, false, false, false, false);
|
||||||
|
|
||||||
|
if (selectedsectors.Count == 0)
|
||||||
|
{
|
||||||
|
// No sectors selected, so find all handles that belong to the same level
|
||||||
|
foreach (VisualSidedefSlope checkhandle in mode.AllSlopeHandles[starthandle.Sidedef.Sector])
|
||||||
|
if (checkhandle != starthandle && checkhandle.Level == starthandle.Level)
|
||||||
|
potentialhandles.Add(checkhandle);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Sectors are selected, get all handles from those sectors that have the same level
|
||||||
|
HashSet<Sector> sectors = new HashSet<Sector>();
|
||||||
|
|
||||||
|
foreach (BaseVisualGeometrySector bvgs in selectedsectors)
|
||||||
|
sectors.Add(bvgs.Sector.Sector);
|
||||||
|
|
||||||
|
foreach (Sector s in sectors)
|
||||||
|
foreach (VisualSidedefSlope checkhandle in mode.AllSlopeHandles[s])
|
||||||
|
if(checkhandle != starthandle)
|
||||||
|
foreach (BaseVisualGeometrySector bvgs in selectedsectors)
|
||||||
|
if (bvgs.Level == checkhandle.Level)
|
||||||
|
potentialhandles.Add(checkhandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (KeyValuePair<Sector, List<VisualSlope>> kvp in mode.AllSlopeHandles)
|
||||||
|
foreach (VisualSidedefSlope checkhandle in kvp.Value)
|
||||||
|
checkhandle.SmartPivot = false;
|
||||||
|
|
||||||
|
// Sort potential handles by their angle difference to the start handle. That means that handles with less angle difference will be at the beginning of the list
|
||||||
|
List<VisualSidedefSlope> anglediffsortedhandles = potentialhandles.OrderBy(h => Math.Abs(starthandle.NormalizedAngleDeg - h.NormalizedAngleDeg)).ToList();
|
||||||
|
|
||||||
|
// Get all potential handles that have to same angle as the one that's closest to the start handle, then sort them by distance, and take the one that's furthest away
|
||||||
|
if (anglediffsortedhandles.Count > 0)
|
||||||
|
handle = anglediffsortedhandles.Where(h => h.NormalizedAngleDeg == anglediffsortedhandles[0].NormalizedAngleDeg).OrderByDescending(h => Math.Abs(starthandle.Sidedef.Line.Line.GetDistanceToLine(h.sidedef.Line.GetCenterPoint(), false))).First();
|
||||||
|
|
||||||
|
if (handle == starthandle)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ApplySlope(SectorLevel level, Plane plane, BaseVisualMode mode)
|
||||||
|
{
|
||||||
|
bool applytoceiling = false;
|
||||||
|
|
||||||
|
Vector2D center = new Vector2D(level.sector.BBox.X + level.sector.BBox.Width / 2,
|
||||||
|
level.sector.BBox.Y + level.sector.BBox.Height / 2);
|
||||||
|
|
||||||
|
if (level.extrafloor)
|
||||||
|
{
|
||||||
|
// The top side of 3D floors is the ceiling of the sector, but it's a "floor" in UDB, so the
|
||||||
|
// ceiling of the control sector has to be modified
|
||||||
|
if (level.type == SectorLevelType.Floor)
|
||||||
|
applytoceiling = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (level.type == SectorLevelType.Ceiling)
|
||||||
|
applytoceiling = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (applytoceiling)
|
||||||
|
{
|
||||||
|
Plane downplane = plane.GetInverted();
|
||||||
|
level.sector.CeilSlope = downplane.Normal;
|
||||||
|
level.sector.CeilSlopeOffset = downplane.Offset;
|
||||||
|
level.sector.CeilHeight = (int)new Plane(level.sector.CeilSlope, level.sector.CeilSlopeOffset).GetZ(center);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
level.sector.FloorSlope = plane.Normal;
|
||||||
|
level.sector.FloorSlopeOffset = plane.Offset;
|
||||||
|
level.sector.FloorHeight = (int)new Plane(level.sector.FloorSlope, level.sector.FloorSlopeOffset).GetZ(center);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rebuild sector
|
||||||
|
BaseVisualSector vs;
|
||||||
|
if (mode.VisualSectorExists(level.sector))
|
||||||
|
{
|
||||||
|
vs = (BaseVisualSector)mode.GetVisualSector(level.sector);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vs = mode.CreateBaseVisualSector(level.sector);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vs != null) vs.UpdateSectorGeometry(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ================== Events
|
||||||
|
|
||||||
|
public void OnChangeTargetHeight(int amount)
|
||||||
|
{
|
||||||
|
VisualSlope pivothandle = null;
|
||||||
|
List<IVisualEventReceiver> selectedsectors = mode.GetSelectedObjects(true, false, false, false, false);
|
||||||
|
List<SectorLevel> levels = new List<SectorLevel>();
|
||||||
|
|
||||||
|
if (selectedsectors.Count == 0)
|
||||||
|
levels.Add(level);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (BaseVisualGeometrySector bvgs in selectedsectors)
|
||||||
|
levels.Add(bvgs.Level);
|
||||||
|
|
||||||
|
if (!levels.Contains(level))
|
||||||
|
levels.Add(level);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to find a slope handle the user set to be the pivot handle
|
||||||
|
// TODO: doing this every time is kind of stupid. Maybe store the pivot handle in the mode?
|
||||||
|
foreach (KeyValuePair<Sector, List<VisualSlope>> kvp in mode.AllSlopeHandles)
|
||||||
|
{
|
||||||
|
foreach (VisualSidedefSlope handle in kvp.Value)
|
||||||
|
{
|
||||||
|
if (handle.Pivot)
|
||||||
|
{
|
||||||
|
pivothandle = handle;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// User didn't set a pivot handle, try to find the smart pivot handle
|
||||||
|
if(pivothandle == null)
|
||||||
|
pivothandle = GetSmartPivotHandle(this, mode);
|
||||||
|
|
||||||
|
// Still no pivot handle, cancle
|
||||||
|
if (pivothandle == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pivothandle.SmartPivot = true;
|
||||||
|
|
||||||
|
mode.CreateUndo("Change slope");
|
||||||
|
|
||||||
|
Plane originalplane = level.plane;
|
||||||
|
Plane pivotplane = ((VisualSidedefSlope)pivothandle).Level.plane;
|
||||||
|
|
||||||
|
// Build a new plane. p1 and p2 are the points of the slope handle that is modified, p3 is on the line of the pivot handle
|
||||||
|
Vector3D p1 = new Vector3D(sidedef.Line.Start.Position, (float)Math.Round(originalplane.GetZ(sidedef.Line.Start.Position)));
|
||||||
|
Vector3D p2 = new Vector3D(sidedef.Line.End.Position, (float)Math.Round(originalplane.GetZ(sidedef.Line.End.Position)));
|
||||||
|
Vector3D p3 = new Vector3D(((VisualSidedefSlope)pivothandle).Sidedef.Line.Line.GetCoordinatesAt(0.5f), (float)Math.Round(pivotplane.GetZ(((VisualSidedefSlope)pivothandle).Sidedef.Line.Line.GetCoordinatesAt(0.5f))));
|
||||||
|
|
||||||
|
// Move the points of the handle up/down
|
||||||
|
p1 += new Vector3D(0f, 0f, amount);
|
||||||
|
p2 += new Vector3D(0f, 0f, amount);
|
||||||
|
|
||||||
|
Plane plane = new Plane(p1, p2, p3, true);
|
||||||
|
|
||||||
|
// Apply slope to surfaces
|
||||||
|
foreach (SectorLevel l in levels)
|
||||||
|
ApplySlope(l, plane, mode);
|
||||||
|
|
||||||
|
mode.SetActionResult("Changed slope.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select or deselect
|
||||||
|
public void OnSelectEnd()
|
||||||
|
{
|
||||||
|
if (this.selected)
|
||||||
|
{
|
||||||
|
this.selected = false;
|
||||||
|
mode.RemoveSelectedObject(this);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(this.pivot)
|
||||||
|
{
|
||||||
|
General.Interface.DisplayStatus(Windows.StatusType.Warning, "It is not allowed to mark pivot slope handles as selected.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.selected = true;
|
||||||
|
mode.AddSelectedObject(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnEditEnd()
|
||||||
|
{
|
||||||
|
// We can only have one pivot handle, so remove it from all first
|
||||||
|
foreach (KeyValuePair<Sector, List<VisualSlope>> kvp in mode.AllSlopeHandles)
|
||||||
|
{
|
||||||
|
foreach (VisualSlope handle in kvp.Value)
|
||||||
|
{
|
||||||
|
if (handle == mode.HighlightedTarget)
|
||||||
|
{
|
||||||
|
if (handle.Selected)
|
||||||
|
General.Interface.DisplayStatus(Windows.StatusType.Warning, "It is not allowed to mark selected slope handles as pivot slope handles.");
|
||||||
|
else
|
||||||
|
handle.Pivot = !handle.Pivot;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
handle.Pivot = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return texture name
|
||||||
|
public string GetTextureName() { return ""; }
|
||||||
|
|
||||||
|
// Unused
|
||||||
|
public void OnSelectBegin() { }
|
||||||
|
public void OnEditBegin() { }
|
||||||
|
public void OnChangeTargetBrightness(bool up) { }
|
||||||
|
public void OnChangeTextureOffset(int horizontal, int vertical, bool doSurfaceAngleCorrection) { }
|
||||||
|
public void OnSelectTexture() { }
|
||||||
|
public void OnCopyTexture() { }
|
||||||
|
public void OnPasteTexture() { }
|
||||||
|
public void OnCopyTextureOffsets() { }
|
||||||
|
public void OnPasteTextureOffsets() { }
|
||||||
|
public void OnTextureAlign(bool alignx, bool aligny) { }
|
||||||
|
public void OnToggleUpperUnpegged() { }
|
||||||
|
public void OnToggleLowerUnpegged() { }
|
||||||
|
public void OnProcess(long deltatime) { }
|
||||||
|
public void OnTextureFloodfill() { }
|
||||||
|
public void OnInsert() { }
|
||||||
|
public void OnTextureFit(FitTextureOptions options) { } //mxd
|
||||||
|
public void ApplyTexture(string texture) { }
|
||||||
|
public void ApplyUpperUnpegged(bool set) { }
|
||||||
|
public void ApplyLowerUnpegged(bool set) { }
|
||||||
|
public void SelectNeighbours(bool select, bool withSameTexture, bool withSameHeight) { } //mxd
|
||||||
|
public virtual void OnPaintSelectEnd() { } // biwa
|
||||||
|
public void OnChangeScale(int x, int y) { }
|
||||||
|
public void OnResetTextureOffset() { }
|
||||||
|
public void OnResetLocalTextureOffset() { }
|
||||||
|
public void OnCopyProperties() { }
|
||||||
|
public void OnPasteProperties(bool usecopysetting) { }
|
||||||
|
public void OnDelete() { }
|
||||||
|
public void OnPaintSelectBegin() { }
|
||||||
|
public void OnMouseMove(MouseEventArgs e) { }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue