mirror of
https://git.do.srb2.org/STJr/UltimateZoneBuilder.git
synced 2024-12-18 16:10:58 +00:00
c86d92ce63
Things with "hangs" flag are now aligned to ceiling properly in GZDoom Visual mode. Things can now be added and deleted in GZDoom Visual mode. Several fixes in Doom, Doom 2, Heretic and Hexen configs (based on Doom Builder 2 SVN 1553 and 1560) Added "countsecret" thing UDMF flag to configs. UDMF Controls plugin: Scale of 3d-floor's sidedefs textures is now applied properly. Translation of 3d-floor's sidedefs textures is now applied properly. Added "hidden" UDMF flag. Tag Explorer plugin: TreeView is now updated when thing is deleted. Tag Explorer plugin is now compatible with Doom Builder 2.
435 lines
17 KiB
C#
435 lines
17 KiB
C#
|
|
#region ================== Copyright (c) 2010 Pascal vd Heiden
|
|
|
|
/*
|
|
* Copyright (c) 2010 Pascal vd Heiden
|
|
* 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
|
|
|
|
#region ================== Namespaces
|
|
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.Globalization;
|
|
using System.Text;
|
|
using System.Windows.Forms;
|
|
using System.IO;
|
|
using System.Reflection;
|
|
using CodeImp.DoomBuilder.Controls;
|
|
using CodeImp.DoomBuilder.Windows;
|
|
using CodeImp.DoomBuilder.IO;
|
|
using CodeImp.DoomBuilder.Map;
|
|
using CodeImp.DoomBuilder.Rendering;
|
|
using CodeImp.DoomBuilder.Geometry;
|
|
using System.Drawing;
|
|
using CodeImp.DoomBuilder.Editing;
|
|
using CodeImp.DoomBuilder.Plugins;
|
|
using CodeImp.DoomBuilder.Actions;
|
|
using CodeImp.DoomBuilder.Types;
|
|
using CodeImp.DoomBuilder.Config;
|
|
using CodeImp.DoomBuilder.Data;
|
|
|
|
#endregion
|
|
|
|
namespace CodeImp.DoomBuilder.GZDoomEditing
|
|
{
|
|
public class BuilderPlug : Plug
|
|
{
|
|
#region ================== Structures
|
|
|
|
private struct SidedefAlignJob
|
|
{
|
|
public Sidedef sidedef;
|
|
|
|
public float offsetx;
|
|
|
|
// When this is true, the previous sidedef was on the left of
|
|
// this one and the texture X offset of this sidedef can be set
|
|
// directly. When this is false, the length of this sidedef
|
|
// must be subtracted from the X offset first.
|
|
public bool forward;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== Variables
|
|
|
|
// Static instance
|
|
private static BuilderPlug me;
|
|
|
|
// Settings
|
|
private int showvisualthings; // 0 = none, 1 = sprite only, 2 = sprite caged
|
|
private int changeheightbysidedef; // 0 = nothing, 1 = change ceiling, 2 = change floor
|
|
private bool visualmodeclearselection;
|
|
private bool usegravity;
|
|
private bool usehighlight;
|
|
private float stitchrange;
|
|
|
|
//mxd
|
|
private bool editnewthing;
|
|
|
|
// Copy/paste
|
|
private string copiedtexture;
|
|
private string copiedflat;
|
|
private Point copiedoffsets;
|
|
private VertexProperties copiedvertexprops;
|
|
private SectorProperties copiedsectorprops;
|
|
private SidedefProperties copiedsidedefprops;
|
|
private LinedefProperties copiedlinedefprops;
|
|
private ThingProperties copiedthingprops;
|
|
|
|
#endregion
|
|
|
|
#region ================== Properties
|
|
|
|
// Static property to access the BuilderPlug
|
|
public static BuilderPlug Me { get { return me; } }
|
|
|
|
// This is the lowest Doom Builder core revision that is required for this plugin to work
|
|
public override int MinimumRevision { get { return 1394; } }
|
|
|
|
// Settings
|
|
public int ShowVisualThings { get { return showvisualthings; } set { showvisualthings = value; } }
|
|
public int ChangeHeightBySidedef { get { return changeheightbysidedef; } }
|
|
public bool VisualModeClearSelection { get { return visualmodeclearselection; } }
|
|
public bool UseGravity { get { return usegravity; } set { usegravity = value; } }
|
|
public bool UseHighlight { get { return usehighlight; } set { usehighlight = value; } }
|
|
public float StitchRange { get { return stitchrange; } }
|
|
|
|
//mxd
|
|
public bool EditNewThing { get { return editnewthing; } }
|
|
|
|
// Copy/paste
|
|
public string CopiedTexture { get { return copiedtexture; } set { copiedtexture = value; } }
|
|
public string CopiedFlat { get { return copiedflat; } set { copiedflat = value; } }
|
|
public Point CopiedOffsets { get { return copiedoffsets; } set { copiedoffsets = value; } }
|
|
public VertexProperties CopiedVertexProps { get { return copiedvertexprops; } set { copiedvertexprops = value; } }
|
|
public SectorProperties CopiedSectorProps { get { return copiedsectorprops; } set { copiedsectorprops = value; } }
|
|
public SidedefProperties CopiedSidedefProps { get { return copiedsidedefprops; } set { copiedsidedefprops = value; } }
|
|
public LinedefProperties CopiedLinedefProps { get { return copiedlinedefprops; } set { copiedlinedefprops = value; } }
|
|
public ThingProperties CopiedThingProps { get { return copiedthingprops; } set { copiedthingprops = value; } }
|
|
|
|
#endregion
|
|
|
|
#region ================== Initialize / Dispose
|
|
|
|
// This event is called when the plugin is initialized
|
|
public override void OnInitialize()
|
|
{
|
|
base.OnInitialize();
|
|
|
|
// Keep a static reference
|
|
me = this;
|
|
|
|
// Settings
|
|
showvisualthings = 2;
|
|
usegravity = false;
|
|
usehighlight = true;
|
|
LoadSettings();
|
|
}
|
|
|
|
// This is called when the plugin is terminated
|
|
public override void Dispose()
|
|
{
|
|
base.Dispose();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== Methods
|
|
|
|
// This loads the plugin settings
|
|
private void LoadSettings()
|
|
{
|
|
changeheightbysidedef = General.Settings.ReadPluginSetting("BuilderModes", "changeheightbysidedef", 0);
|
|
visualmodeclearselection = General.Settings.ReadPluginSetting("BuilderModes", "visualmodeclearselection", false);
|
|
stitchrange = (float)General.Settings.ReadPluginSetting("BuilderModes", "stitchrange", 20);
|
|
|
|
//mxd
|
|
editnewthing = General.Settings.ReadPluginSetting("BuilderModes", "editnewthing", true);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== Events
|
|
|
|
// When the Preferences dialog is closed
|
|
public override void OnClosePreferences(PreferencesController controller)
|
|
{
|
|
base.OnClosePreferences(controller);
|
|
|
|
// Apply settings that could have been changed
|
|
LoadSettings();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== Classic Mode Surfaces
|
|
|
|
// This is called when the vertices are created for the classic mode surfaces
|
|
public override void OnSectorFloorSurfaceUpdate(Sector s, ref FlatVertex[] vertices)
|
|
{
|
|
ImageData img = General.Map.Data.GetFlatImage(s.LongFloorTexture);
|
|
if((img != null) && img.IsImageLoaded)
|
|
{
|
|
// Fetch ZDoom fields
|
|
Vector2D offset = new Vector2D(s.Fields.GetValue("xpanningfloor", 0.0f),
|
|
s.Fields.GetValue("ypanningfloor", 0.0f));
|
|
Vector2D scale = new Vector2D(s.Fields.GetValue("xscalefloor", 1.0f),
|
|
s.Fields.GetValue("yscalefloor", 1.0f));
|
|
float rotate = s.Fields.GetValue("rotationfloor", 0.0f);
|
|
int color = s.Fields.GetValue("lightcolor", -1);
|
|
int light = s.Fields.GetValue("lightfloor", 0);
|
|
bool absolute = s.Fields.GetValue("lightfloorabsolute", false);
|
|
|
|
// Setup the vertices with the given settings
|
|
SetupSurfaceVertices(vertices, s, img, offset, scale, rotate, color, light, absolute);
|
|
}
|
|
}
|
|
|
|
// This is called when the vertices are created for the classic mode surfaces
|
|
public override void OnSectorCeilingSurfaceUpdate(Sector s, ref FlatVertex[] vertices)
|
|
{
|
|
ImageData img = General.Map.Data.GetFlatImage(s.LongFloorTexture);
|
|
if((img != null) && img.IsImageLoaded)
|
|
{
|
|
// Fetch ZDoom fields
|
|
Vector2D offset = new Vector2D(s.Fields.GetValue("xpanningceiling", 0.0f),
|
|
s.Fields.GetValue("ypanningceiling", 0.0f));
|
|
Vector2D scale = new Vector2D(s.Fields.GetValue("xscaleceiling", 1.0f),
|
|
s.Fields.GetValue("yscaleceiling", 1.0f));
|
|
float rotate = s.Fields.GetValue("rotationceiling", 0.0f);
|
|
int color = s.Fields.GetValue("lightcolor", -1);
|
|
int light = s.Fields.GetValue("lightceiling", 0);
|
|
bool absolute = s.Fields.GetValue("lightceilingabsolute", false);
|
|
|
|
// Setup the vertices with the given settings
|
|
SetupSurfaceVertices(vertices, s, img, offset, scale, rotate, color, light, absolute);
|
|
}
|
|
}
|
|
|
|
// This applies the given values on the vertices
|
|
private void SetupSurfaceVertices(FlatVertex[] vertices, Sector s, ImageData img, Vector2D offset,
|
|
Vector2D scale, float rotate, int color, int light, bool absolute)
|
|
{
|
|
// Prepare for math!
|
|
rotate = Angle2D.DegToRad(rotate);
|
|
Vector2D texscale = new Vector2D(1.0f / img.ScaledWidth, 1.0f / img.ScaledHeight);
|
|
if(!absolute) light = s.Brightness + light;
|
|
PixelColor lightcolor = PixelColor.FromInt(color);
|
|
PixelColor brightness = PixelColor.FromInt(General.Map.Renderer2D.CalculateBrightness(light));
|
|
PixelColor finalcolor = PixelColor.Modulate(lightcolor, brightness);
|
|
color = finalcolor.WithAlpha(255).ToInt();
|
|
|
|
// Do the math for all vertices
|
|
for(int i = 0; i < vertices.Length; i++)
|
|
{
|
|
Vector2D pos = new Vector2D(vertices[i].x, vertices[i].y);
|
|
pos = pos.GetRotated(rotate);
|
|
pos.y = -pos.y;
|
|
pos = (pos + offset) * scale * texscale;
|
|
vertices[i].u = pos.x;
|
|
vertices[i].v = pos.y;
|
|
vertices[i].c = color;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== Texture Alignment
|
|
|
|
// This performs texture alignment along all walls that match with the same texture
|
|
// NOTE: This method uses the sidedefs marking to indicate which sides have been aligned
|
|
// When resetsidemarks is set to true, all sidedefs will first be marked false (not aligned).
|
|
// Setting resetsidemarks to false is usefull to align only within a specific selection
|
|
// (set the marked property to true for the sidedefs outside the selection)
|
|
public static void AutoAlignTextures(Sidedef start, SidedefPart part, ImageData texture, bool alignx, bool aligny, bool resetsidemarks)
|
|
{
|
|
Stack<SidedefAlignJob> todo = new Stack<SidedefAlignJob>(50);
|
|
float scalex = (General.Map.Config.ScaledTextureOffsets && !texture.WorldPanning) ? texture.Scale.x : 1.0f;
|
|
float scaley = (General.Map.Config.ScaledTextureOffsets && !texture.WorldPanning) ? texture.Scale.y : 1.0f;
|
|
|
|
// Mark all sidedefs false (they will be marked true when the texture is aligned)
|
|
if(resetsidemarks) General.Map.Map.ClearMarkedSidedefs(false);
|
|
|
|
if(!texture.IsImageLoaded) return;
|
|
|
|
// Determine the Y alignment
|
|
float ystartalign = start.OffsetY;
|
|
switch(part)
|
|
{
|
|
case SidedefPart.Upper: ystartalign += start.Fields.GetValue("offsety_top", 0.0f); break;
|
|
case SidedefPart.Middle: ystartalign += start.Fields.GetValue("offsety_mid", 0.0f); break;
|
|
case SidedefPart.Lower: ystartalign += start.Fields.GetValue("offsety_bottom", 0.0f); break;
|
|
}
|
|
|
|
// Begin with first sidedef
|
|
SidedefAlignJob first = new SidedefAlignJob();
|
|
first.sidedef = start;
|
|
first.offsetx = start.OffsetX;
|
|
switch(part)
|
|
{
|
|
case SidedefPart.Upper: first.offsetx += start.Fields.GetValue("offsetx_top", 0.0f); break;
|
|
case SidedefPart.Middle: first.offsetx += start.Fields.GetValue("offsetx_mid", 0.0f); break;
|
|
case SidedefPart.Lower: first.offsetx += start.Fields.GetValue("offsetx_bottom", 0.0f); break;
|
|
}
|
|
first.forward = true;
|
|
todo.Push(first);
|
|
|
|
// Continue until nothing more to align
|
|
while(todo.Count > 0)
|
|
{
|
|
Vertex v;
|
|
float forwardoffset;
|
|
float backwardoffset;
|
|
float offsetscalex = 1.0f;
|
|
|
|
// Get the align job to do
|
|
SidedefAlignJob j = todo.Pop();
|
|
|
|
bool matchtop = ((j.sidedef.LongHighTexture == texture.LongName) && j.sidedef.HighRequired());
|
|
bool matchbottom = ((j.sidedef.LongLowTexture == texture.LongName) && j.sidedef.LowRequired());
|
|
bool matchmid = ((j.sidedef.LongMiddleTexture == texture.LongName) && (j.sidedef.MiddleRequired() || ((j.sidedef.MiddleTexture.Length > 0) && (j.sidedef.MiddleTexture[0] != '-'))));
|
|
|
|
if(matchtop) offsetscalex = j.sidedef.Fields.GetValue("scalex_top", 1.0f);
|
|
else if(matchbottom) offsetscalex = j.sidedef.Fields.GetValue("scalex_bottom", 1.0f);
|
|
else if(matchmid) offsetscalex = j.sidedef.Fields.GetValue("scalex_mid", 1.0f);
|
|
|
|
if(j.forward)
|
|
{
|
|
// Apply alignment
|
|
if(alignx)
|
|
{
|
|
//j.sidedef.OffsetX = j.offsetx;
|
|
float offset = j.offsetx;
|
|
offset %= (float)texture.Height;
|
|
offset -= j.sidedef.OffsetX;
|
|
|
|
j.sidedef.Fields.BeforeFieldsChange();
|
|
if(matchtop) j.sidedef.Fields["offsetx_top"] = new UniValue(UniversalType.Float, offset);
|
|
if(matchbottom) j.sidedef.Fields["offsetx_bottom"] = new UniValue(UniversalType.Float, offset);
|
|
if(matchmid) j.sidedef.Fields["offsetx_mid"] = new UniValue(UniversalType.Float, offset);
|
|
}
|
|
if(aligny)
|
|
{
|
|
//j.sidedef.OffsetY = (int)Math.Round((start.Sector.CeilHeight - j.sidedef.Sector.CeilHeight) / scaley) + start.OffsetY;
|
|
float offset = ((float)(start.Sector.CeilHeight - j.sidedef.Sector.CeilHeight) / scaley) + ystartalign;
|
|
offset %= (float)texture.Height;
|
|
offset -= j.sidedef.OffsetY;
|
|
|
|
j.sidedef.Fields.BeforeFieldsChange();
|
|
if(matchtop) j.sidedef.Fields["offsety_top"] = new UniValue(UniversalType.Float, offset);
|
|
if(matchbottom) j.sidedef.Fields["offsety_bottom"] = new UniValue(UniversalType.Float, offset);
|
|
if(matchmid) j.sidedef.Fields["offsety_mid"] = new UniValue(UniversalType.Float, offset);
|
|
}
|
|
forwardoffset = j.offsetx + (int)Math.Round(j.sidedef.Line.Length / scalex * offsetscalex);
|
|
backwardoffset = j.offsetx;
|
|
|
|
// Done this sidedef
|
|
j.sidedef.Marked = true;
|
|
|
|
// Add sidedefs backward (connected to the left vertex)
|
|
v = j.sidedef.IsFront ? j.sidedef.Line.Start : j.sidedef.Line.End;
|
|
AddSidedefsForAlignment(todo, v, false, backwardoffset, texture.LongName);
|
|
|
|
// Add sidedefs forward (connected to the right vertex)
|
|
v = j.sidedef.IsFront ? j.sidedef.Line.End : j.sidedef.Line.Start;
|
|
AddSidedefsForAlignment(todo, v, true, forwardoffset, texture.LongName);
|
|
}
|
|
else
|
|
{
|
|
// Apply alignment
|
|
if(alignx)
|
|
{
|
|
//j.sidedef.OffsetX = j.offsetx - (int)Math.Round(j.sidedef.Line.Length / scalex);
|
|
float offset = j.offsetx - (int)Math.Round(j.sidedef.Line.Length / scalex);
|
|
offset %= (float)texture.Height;
|
|
offset -= j.sidedef.OffsetX;
|
|
|
|
j.sidedef.Fields.BeforeFieldsChange();
|
|
if(matchtop) j.sidedef.Fields["offsetx_top"] = new UniValue(UniversalType.Float, offset);
|
|
if(matchbottom) j.sidedef.Fields["offsetx_bottom"] = new UniValue(UniversalType.Float, offset);
|
|
if(matchmid) j.sidedef.Fields["offsetx_mid"] = new UniValue(UniversalType.Float, offset);
|
|
}
|
|
if(aligny)
|
|
{
|
|
//j.sidedef.OffsetY = (int)Math.Round((start.Sector.CeilHeight - j.sidedef.Sector.CeilHeight) / scaley) + start.OffsetY;
|
|
float offset = ((float)(start.Sector.CeilHeight - j.sidedef.Sector.CeilHeight) / scaley) + ystartalign;
|
|
offset %= (float)texture.Height;
|
|
offset -= j.sidedef.OffsetY;
|
|
|
|
j.sidedef.Fields.BeforeFieldsChange();
|
|
if(matchtop) j.sidedef.Fields["offsety_top"] = new UniValue(UniversalType.Float, offset);
|
|
if(matchbottom) j.sidedef.Fields["offsety_bottom"] = new UniValue(UniversalType.Float, offset);
|
|
if(matchmid) j.sidedef.Fields["offsety_mid"] = new UniValue(UniversalType.Float, offset);
|
|
}
|
|
forwardoffset = j.offsetx;
|
|
backwardoffset = j.offsetx - (int)Math.Round(j.sidedef.Line.Length / scalex * offsetscalex);
|
|
|
|
// Done this sidedef
|
|
j.sidedef.Marked = true;
|
|
|
|
// Add sidedefs forward (connected to the right vertex)
|
|
v = j.sidedef.IsFront ? j.sidedef.Line.End : j.sidedef.Line.Start;
|
|
AddSidedefsForAlignment(todo, v, true, forwardoffset, texture.LongName);
|
|
|
|
// Add sidedefs backward (connected to the left vertex)
|
|
v = j.sidedef.IsFront ? j.sidedef.Line.Start : j.sidedef.Line.End;
|
|
AddSidedefsForAlignment(todo, v, false, backwardoffset, texture.LongName);
|
|
}
|
|
}
|
|
}
|
|
|
|
// This adds the matching, unmarked sidedefs from a vertex for texture alignment
|
|
private static void AddSidedefsForAlignment(Stack<SidedefAlignJob> stack, Vertex v, bool forward, float offsetx, long texturelongname)
|
|
{
|
|
foreach(Linedef ld in v.Linedefs)
|
|
{
|
|
Sidedef side1 = forward ? ld.Front : ld.Back;
|
|
Sidedef side2 = forward ? ld.Back : ld.Front;
|
|
if((ld.Start == v) && (side1 != null) && !side1.Marked)
|
|
{
|
|
if(SidedefTextureMatch(side1, texturelongname))
|
|
{
|
|
SidedefAlignJob nj = new SidedefAlignJob();
|
|
nj.forward = forward;
|
|
nj.offsetx = offsetx;
|
|
nj.sidedef = side1;
|
|
stack.Push(nj);
|
|
}
|
|
}
|
|
else if((ld.End == v) && (side2 != null) && !side2.Marked)
|
|
{
|
|
if(SidedefTextureMatch(side2, texturelongname))
|
|
{
|
|
SidedefAlignJob nj = new SidedefAlignJob();
|
|
nj.forward = forward;
|
|
nj.offsetx = offsetx;
|
|
nj.sidedef = side2;
|
|
stack.Push(nj);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// This checks if any of the sidedef texture match the given texture
|
|
private static bool SidedefTextureMatch(Sidedef sd, long texturelongname)
|
|
{
|
|
return ((sd.LongHighTexture == texturelongname) && sd.HighRequired()) ||
|
|
((sd.LongLowTexture == texturelongname) && sd.LowRequired()) ||
|
|
((sd.LongMiddleTexture == texturelongname) && (sd.MiddleRequired() || ((sd.MiddleTexture.Length > 0) && (sd.MiddleTexture[0] != '-'))));
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|