From c00a8995aa78b8e80da3c49cd71356b731b76a9e Mon Sep 17 00:00:00 2001 From: biwa Date: Thu, 8 Aug 2019 12:17:49 +0200 Subject: [PATCH 01/34] - Fixed a crash when loading OBJ models with faces without normals --- Source/Core/GZBuilder/md3/ModelReader.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Core/GZBuilder/md3/ModelReader.cs b/Source/Core/GZBuilder/md3/ModelReader.cs index 441f5404..c8177e37 100755 --- a/Source/Core/GZBuilder/md3/ModelReader.cs +++ b/Source/Core/GZBuilder/md3/ModelReader.cs @@ -1653,12 +1653,12 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 face.Add(int.Parse(vertexdata[0], CultureInfo.InvariantCulture) - 1); - if (vertexdata.Length >= 1 && vertexdata[1] != "") + if (vertexdata.Length > 1 && vertexdata[1] != "") texcoords.Add(int.Parse(vertexdata[1], CultureInfo.InvariantCulture) - 1); else texcoords.Add(-1); - if (vertexdata.Length >= 2 && vertexdata[2] != "") + if (vertexdata.Length > 2 && vertexdata[2] != "") normals.Add(int.Parse(vertexdata[2], CultureInfo.InvariantCulture) - 1); else normals.Add(-1); From b603cb35c740c87991c5b72ba054d24712d0b484 Mon Sep 17 00:00:00 2001 From: biwa Date: Thu, 8 Aug 2019 15:06:10 +0200 Subject: [PATCH 02/34] - Unused textures error checker doesn't erroneously report textures on 3D floors with the use upper/lower flags set (followup to #269) @ Refactored texture error checks to reuse code --- .../Plugins/BuilderModes/BuilderModes.csproj | 1 + .../ErrorChecks/BaseCheckTextures.cs | 103 ++++++++++++++++++ .../ErrorChecks/CheckMissingTextures.cs | 53 +-------- .../ErrorChecks/CheckUnusedTextures.cs | 78 ++++++++++++- 4 files changed, 181 insertions(+), 54 deletions(-) create mode 100644 Source/Plugins/BuilderModes/ErrorChecks/BaseCheckTextures.cs diff --git a/Source/Plugins/BuilderModes/BuilderModes.csproj b/Source/Plugins/BuilderModes/BuilderModes.csproj index d4a67a16..1a8d19b4 100755 --- a/Source/Plugins/BuilderModes/BuilderModes.csproj +++ b/Source/Plugins/BuilderModes/BuilderModes.csproj @@ -123,6 +123,7 @@ + diff --git a/Source/Plugins/BuilderModes/ErrorChecks/BaseCheckTextures.cs b/Source/Plugins/BuilderModes/ErrorChecks/BaseCheckTextures.cs new file mode 100644 index 00000000..78dbe675 --- /dev/null +++ b/Source/Plugins/BuilderModes/ErrorChecks/BaseCheckTextures.cs @@ -0,0 +1,103 @@ +#region ================== Copyright (c) 2007 Pascal vd Heiden + +/* + * Copyright (c) 2007 Pascal vd Heiden, www.codeimp.com + * Copyright (c) 2019 Boris Iwanski + * This program is released under GNU General Public License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#endregion + +#region ================== Namespaces + +using CodeImp.DoomBuilder.Map; +using System.Collections.Generic; +using System.Threading; +using System; + +#endregion + +namespace CodeImp.DoomBuilder.BuilderModes +{ + public abstract class BaseCheckTextures : ErrorChecker + { + #region ================== Constants + + private const int PROGRESS_STEP = 1000; + + #endregion + + #region ================== Variables + + protected Dictionary sector3dfloors; + + #endregion + + #region ================== Constructor / Destructor + + // Constructor + public BaseCheckTextures() + { + // Total progress is done when all lines are checked + SetTotalProgress(General.Map.Map.Sidedefs.Count / PROGRESS_STEP); + + sector3dfloors = new Dictionary(); + } + + #endregion + + #region ================== Enum + + [Flags] + protected enum Flags3DFloor + { + UseUpper = 1, + UseLower = 2, + RenderInside = 4 + } + + #endregion + + #region ================== Methods + + // Create a cache of sectors that have 3D floors, with their flags relevant to the error checker + protected void Build3DFloorCache() + { + foreach (Linedef ld in General.Map.Map.Linedefs) + { + if (ld.Action == 160) + { + if ((ld.Args[1] & 4) == 4) // Type render inside + { + if (!sector3dfloors.ContainsKey(ld.Args[0])) + sector3dfloors.Add(ld.Args[0], Flags3DFloor.RenderInside); + } + + if ((ld.Args[2] & 16) == 16) // Flag use upper + { + if (!sector3dfloors.ContainsKey(ld.Args[0])) + sector3dfloors.Add(ld.Args[0], Flags3DFloor.UseUpper); + else + sector3dfloors[ld.Args[0]] |= Flags3DFloor.UseUpper; + } + + if ((ld.Args[2] & 32) == 32) // Flag use lower + { + if (!sector3dfloors.ContainsKey(ld.Args[0])) + sector3dfloors.Add(ld.Args[0], Flags3DFloor.UseLower); + else + sector3dfloors[ld.Args[0]] |= Flags3DFloor.UseLower; + } + } + } + } + + #endregion + } +} diff --git a/Source/Plugins/BuilderModes/ErrorChecks/CheckMissingTextures.cs b/Source/Plugins/BuilderModes/ErrorChecks/CheckMissingTextures.cs index 37a94be3..c3ffad44 100755 --- a/Source/Plugins/BuilderModes/ErrorChecks/CheckMissingTextures.cs +++ b/Source/Plugins/BuilderModes/ErrorChecks/CheckMissingTextures.cs @@ -26,7 +26,7 @@ using System; namespace CodeImp.DoomBuilder.BuilderModes { [ErrorChecker("Check missing textures", true, 80)] - public class CheckMissingTextures : ErrorChecker + public class CheckMissingTextures : BaseCheckTextures { #region ================== Constants @@ -37,22 +37,8 @@ namespace CodeImp.DoomBuilder.BuilderModes #region ================== Constructor / Destructor // Constructor - public CheckMissingTextures() + public CheckMissingTextures() : base() { - // Total progress is done when all lines are checked - SetTotalProgress(General.Map.Map.Sidedefs.Count / PROGRESS_STEP); - } - - #endregion - - #region ================== Enum - - [Flags] - private enum Flags3DFloor - { - UseUpper = 1, - UseLower = 2, - RenderInside = 4 } #endregion @@ -65,36 +51,7 @@ namespace CodeImp.DoomBuilder.BuilderModes int progress = 0; int stepprogress = 0; - Dictionary sector3dfloors = new Dictionary(); - - // Create a cache of sectors that have 3D floors, with their flags relevant to the error checker - foreach (Linedef ld in General.Map.Map.Linedefs) - { - if (ld.Action == 160) - { - if ((ld.Args[1] & 4) == 4) // Type render inside - { - if (!sector3dfloors.ContainsKey(ld.Args[0])) - sector3dfloors.Add(ld.Args[0], Flags3DFloor.RenderInside); - } - - if ((ld.Args[2] & 16) == 16) // Flag use upper - { - if (!sector3dfloors.ContainsKey(ld.Args[0])) - sector3dfloors.Add(ld.Args[0], Flags3DFloor.UseUpper); - else - sector3dfloors[ld.Args[0]] |= Flags3DFloor.UseUpper; - } - - if ((ld.Args[2] & 32) == 32) // Flag use lower - { - if (!sector3dfloors.ContainsKey(ld.Args[0])) - sector3dfloors.Add(ld.Args[0], Flags3DFloor.UseLower); - else - sector3dfloors[ld.Args[0]] |= Flags3DFloor.UseLower; - } - } - } + Build3DFloorCache(); // Go for all the sidedefs foreach(Sidedef sd in General.Map.Map.Sidedefs) @@ -102,7 +59,7 @@ namespace CodeImp.DoomBuilder.BuilderModes // Check upper texture. Also make sure not to return a false // positive if the sector on the other side has the ceiling // set to be sky - if (sd.HighTexture == "-") { + if (sd.LongHighTexture == MapSet.EmptyLongName) { if (sd.HighRequired()) { if (sd.Line.Action == 181 && sd.Line.Args[1] > 0) continue; //mxd. Ceiling slopes doesn't require upper texture @@ -150,7 +107,7 @@ namespace CodeImp.DoomBuilder.BuilderModes // Check lower texture. Also make sure not to return a false // positive if the sector on the other side has the floor // set to be sky - if(sd.LowTexture == "-") + if(sd.LongLowTexture == MapSet.EmptyLongName) { if (sd.LowRequired()) { diff --git a/Source/Plugins/BuilderModes/ErrorChecks/CheckUnusedTextures.cs b/Source/Plugins/BuilderModes/ErrorChecks/CheckUnusedTextures.cs index 404dbcec..83a03d38 100755 --- a/Source/Plugins/BuilderModes/ErrorChecks/CheckUnusedTextures.cs +++ b/Source/Plugins/BuilderModes/ErrorChecks/CheckUnusedTextures.cs @@ -8,7 +8,7 @@ using System.Threading; namespace CodeImp.DoomBuilder.BuilderModes { [ErrorChecker("Check unused textures", true, 60)] - public class CheckUnusedTextures : ErrorChecker + public class CheckUnusedTextures : BaseCheckTextures { #region ================== Constants @@ -19,10 +19,8 @@ namespace CodeImp.DoomBuilder.BuilderModes #region ================== Constructor / Destructor // Constructor - public CheckUnusedTextures() + public CheckUnusedTextures() : base() { - // Total progress is done when all lines are checked - SetTotalProgress(General.Map.Map.Sidedefs.Count / PROGRESS_STEP); } #endregion @@ -35,19 +33,87 @@ namespace CodeImp.DoomBuilder.BuilderModes int progress = 0; int stepprogress = 0; + Build3DFloorCache(); + // Go for all the sidedefs foreach(Sidedef sd in General.Map.Map.Sidedefs) { // Check upper texture if(!sd.HighRequired() && sd.LongHighTexture != MapSet.EmptyLongName) { - SubmitResult(new ResultUnusedTexture(sd, SidedefPart.Upper)); + if (sd.Other == null) + SubmitResult(new ResultUnusedTexture(sd, SidedefPart.Upper)); + else + { + bool unused = true; + + // Check if the sidedef's sector is a 3D floor. Since it points toward the 3D floor it only needs a texture if inside rendering is enabled + if (sd.Sector.Tags.Count > 0) + { + foreach (int tag in sd.Sector.Tags) + { + if (sector3dfloors.ContainsKey(tag) && sector3dfloors[tag].HasFlag(Flags3DFloor.UseUpper) && sector3dfloors[tag].HasFlag(Flags3DFloor.RenderInside)) + { + unused = false; + break; + } + } + } + + // Check if the other sidedef's sector is a 3D floor, since we still might need a texture on this one depending on the flags + if(sd.Other.Sector.Tags.Count > 0) + { + foreach(int tag in sd.Other.Sector.Tags) + { + if(sector3dfloors.ContainsKey(tag) && sector3dfloors[tag].HasFlag(Flags3DFloor.UseUpper)) + { + unused = false; + break; + } + } + } + + if (unused) SubmitResult(new ResultUnusedTexture(sd, SidedefPart.Upper)); + } } // Check lower texture if(!sd.LowRequired() && sd.LongLowTexture != MapSet.EmptyLongName) { - SubmitResult(new ResultUnusedTexture(sd, SidedefPart.Lower)); + if (sd.Other == null) + SubmitResult(new ResultUnusedTexture(sd, SidedefPart.Lower)); + else + { + bool unused = true; + + // Check if the sidedef's sector is a 3D floor. Since it points toward the 3D floor it only needs a texture if inside rendering is enabled + if (sd.Sector.Tags.Count > 0) + { + foreach (int tag in sd.Sector.Tags) + { + if (sector3dfloors.ContainsKey(tag) && sector3dfloors[tag].HasFlag(Flags3DFloor.UseLower) && sector3dfloors[tag].HasFlag(Flags3DFloor.RenderInside)) + { + unused = false; + break; + } + } + } + + // Check if the other sidedef's sector is a 3D floor, since we still might need a texture on this one depending on the flags + if (sd.Other.Sector.Tags.Count > 0) + { + foreach (int tag in sd.Other.Sector.Tags) + { + if (sector3dfloors.ContainsKey(tag) && sector3dfloors[tag].HasFlag(Flags3DFloor.UseLower)) + { + unused = false; + break; + } + } + } + + if (unused) SubmitResult(new ResultUnusedTexture(sd, SidedefPart.Lower)); + } } // Handle thread interruption From 64c04f424677e51ef393b3e8edf77ccf130cfe20 Mon Sep 17 00:00:00 2001 From: biwa Date: Sat, 24 Aug 2019 12:43:35 +0200 Subject: [PATCH 03/34] - Fixed a bug where lights defined in GLDEFS wouldn't show up in visual mode. Fixes #294. --- Source/Core/Rendering/Renderer3D.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Core/Rendering/Renderer3D.cs b/Source/Core/Rendering/Renderer3D.cs index 46a412dc..3f3c91a3 100755 --- a/Source/Core/Rendering/Renderer3D.cs +++ b/Source/Core/Rendering/Renderer3D.cs @@ -1975,7 +1975,7 @@ namespace CodeImp.DoomBuilder.Rendering public void AddThingGeometry(VisualThing t) { //mxd. Gather lights - if (General.Settings.GZDrawLightsMode != LightRenderMode.NONE && !fullbrightness && t.LightType != null && t.LightType.LightInternal) + if (General.Settings.GZDrawLightsMode != LightRenderMode.NONE && !fullbrightness && t.LightType != null) { t.UpdateLightRadius(); if (t.LightRadius > 0) From a8ef8d526ce58aba6083743e59b940cd00ec7453 Mon Sep 17 00:00:00 2001 From: DoomKrawa Date: Tue, 3 Sep 2019 10:57:44 +0200 Subject: [PATCH 04/34] ZDaemon sprites (PR#282 by Krawa) * Flags and Railgun taken from zdaemon.wad. Thanks to ZDaemon team for the sprites. * ZDaemon Flags and Railgun. --- Build/Configurations/Includes/ZDaemon_things.cfg | 13 ++++++++----- Build/Sprites/ZDFlagBlue.png | Bin 0 -> 1367 bytes Build/Sprites/ZDFlagGreen.png | Bin 0 -> 1367 bytes Build/Sprites/ZDFlagRed.png | Bin 0 -> 1367 bytes Build/Sprites/ZDFlagWhite.png | Bin 0 -> 1367 bytes Build/Sprites/ZDRailgun.png | Bin 0 -> 1627 bytes 6 files changed, 8 insertions(+), 5 deletions(-) create mode 100644 Build/Sprites/ZDFlagBlue.png create mode 100644 Build/Sprites/ZDFlagGreen.png create mode 100644 Build/Sprites/ZDFlagRed.png create mode 100644 Build/Sprites/ZDFlagWhite.png create mode 100644 Build/Sprites/ZDRailgun.png diff --git a/Build/Configurations/Includes/ZDaemon_things.cfg b/Build/Configurations/Includes/ZDaemon_things.cfg index 2ac32342..5c9eee0d 100755 --- a/Build/Configurations/Includes/ZDaemon_things.cfg +++ b/Build/Configurations/Includes/ZDaemon_things.cfg @@ -1,4 +1,6 @@ -// Version: 2017-02-13 +// Version: 2019-07-24 +// Flags and Railgun taken from zdaemon.wad. +// Thanks to ZDaemon team for the sprites. redteam { @@ -19,7 +21,7 @@ redteam 5131 { title = "Red Flag"; - sprite = "internal:ZandFlagRed"; + sprite = "internal:ZDFlagRed"; height = 55; } } @@ -43,7 +45,7 @@ blueteam 5130 { title = "Blue Flag"; - sprite = "internal:ZandFlagBlue"; + sprite = "internal:ZDFlagBlue"; height = 55; } } @@ -67,7 +69,7 @@ greenteam 5133 { title = "Green Flag"; - sprite = "internal:ZandFlagGreen"; + sprite = "internal:ZDFlagGreen"; } } @@ -90,7 +92,7 @@ whiteteam 5134 { title = "White Flag"; - sprite = "internal:ZandFlagWhite"; + sprite = "internal:ZDFlagWhite"; } } @@ -127,5 +129,6 @@ weapons 5012 { title = "Railgun"; + sprite = "internal:ZDRailgun"; } } diff --git a/Build/Sprites/ZDFlagBlue.png b/Build/Sprites/ZDFlagBlue.png new file mode 100644 index 0000000000000000000000000000000000000000..f7c080d9c179054ff9592cc6ee9b3456962bc4bc GIT binary patch literal 1367 zcmd^7@oO7(6n~?*+j_P^BSgF(;&#)}o^WW!PCVJMUdOeK?Ty~xC`#1dZeec8f zJ>KVizu(WBJ~pQGbU)J#06oJ)gX0AIh`qe0i+KIuz6S*MgiaqhLGY=agmic1Yk)2| z_S*5Ib#=lB`GJ08NWZx^A5))SvKzV#uz5z@z`#+<#L5+ zI!I9lMQIeJ0w@470Is!gxsJ^$*2}n9#A+TZ87!x;7~d{LJ2|_Zv05p!ku((c zTCG~GRw|WJsZ=Z$3xz^HpU-Bq>2x}kN+pxYcsw49#UhbNI2^Vt%QQ{HFmzp4RaH?G zS(Zgn6a<0id7sb6vTOvy;Z7*j3I-Q-qoQi_N+2uADM5(dyo?D6wRKKKfg5*QA*P42xEH7mE`KUKzxDzsEb3nAlW)sV0 z%w#Yc#b6L63B6tf=m0DOGyrM<6@Vf@9v}md1c(9H03iSafJjF4YPYdk#XP4^8JZv})9xMH1+&+lCc!(y zgGY`JP2aAc>Rx#E@!d=7X9vQc9nzopmfos9JU{c?dd`^HxH|gEMBn>~w_mTXUb?Z` zn!DYbIuy$PH1g8-zw~d>t1pPB{&{e1?7-=+3Hbo_qD1+1kzTeoW8Le!>4+ob2oVX!Gv4{$&5mTNC?7nUgCMb6;NExS-rS zfB4N@c~t+jYyTnP$~6D!N`$)mcR;NK#%Dv%z47=TjV)WZAgi?=nox=d-1tf$-Ub~>GQyWMKFn$2dt zUa!?^)oQg|E|*HBVzF2#6mq#-CX-30)5&Bq9*?`O8;ixF(WqrvrfC|6q3gP;s*0k> zvMh?CAP79q2Lb_>Wn&nPb|aB?INZ>Us;bQ@p`0YA1u4!8HpiQ6Kx6!}&lmJ~S(^4y z)k3PAOU!26LMoO^M6<4ycFd%0#4X)1)mS(b)#ZpLg+qca2Q`V$#m!Vqi(8>sSc+&t zL*Z1Bm4l4qno(PiSgK(vnl378P*ONS3Lx6cEq$>f&u95r$DcL437N7vAX;Oqg_R0s zv*s^b6_fVSFqxrK`rtYxv}VBWx#h%R&6_AN&}?TBYFOxJa4UWKv( zv+})r;v!-RF@t2T@c9wI8!-c?%z)9*h-g4c%n zcOM))_HEPXnSXTCeHV{R?773fQ~7JV^Nr$O8;IOwUw`E1qfgCT-n2Dw>D=%s`ur(3 zeX@W5(a{eFn6J;i^}$8{rTcGw_It}7n7r`x)ajA*HnBk;5B1fod*nwyJf;iWA{nEyvv3=rr!b!aRRXQO)^U8^h vzyAB(yMO+(b4k29d3kE$r!QiCOY5lP=Xy6!U3h^!6o&Q=_kXhI`8WRq5wXyy literal 0 HcmV?d00001 diff --git a/Build/Sprites/ZDFlagRed.png b/Build/Sprites/ZDFlagRed.png new file mode 100644 index 0000000000000000000000000000000000000000..d882fa3a9cc37039e87ddcae2dce4f15e004829b GIT binary patch literal 1367 zcmd^7fomIO6n|s5TbI=c8Jz2ZnY-37PCX&wsfXOwYrSr9y}2u#a>Ix>4D*B(PnThE z5hI2!LW+S!dt%TIGZ)$nBgPpeN(TX>i!?&e=puA9n~_GkVX?xVU-xhL@xAxsdyn^f z-}n9A)S+>uf7`$|0O;R8HgcHY9%2t~-Augx;N9y4wuWBX_Z-0;8wu(1l`jD{!=Wc8 zM#$r}(DiKqRXhhyEnUa!;XwA<}gtJP>UYPDLm zTCG$nrBbO_Eavn1TrQW*W;2;gI-O1?lks>w7K=q9k#IO{S(a&mw2io>M@=;n41{$#q)EYmpv!(u;PVJey~Dym;nI6?9u+TE7kEXxZHUx<1g!;_FHn**XXwpv&&qvK#S zioqaC5_-J|&;wWkXadv#DgZ@*9DoCm1c(9H03iSafJjF4>U6ML#e5!9DYR|WG!z6f zMTCZILPIzR0jZ7ySOD5a-);+=Wvn__jN+_;DG_7Lb(`*n-R+RO8FbZjYC(mP0tNZj zJ+X;cL`)%ChzcT$2ssI|0;G9Juw*!WGS3LChi6=*#jQ~i0eAowfCeBzz^sg&07gkE z)}fvSCk$53vMyceKLD@^UOqgok<|Zs&56q#`KrFjv8Rd3F3*N-f|>X4B*EYIkL;Tm zoBE;g*zF6uw%_*qjT2)RhVCf5eeaP$S)YH>xp}64%hzW|_q?#{>F*bNyU8r t*xp|5_?z|4bnoik1EJ-qwaf2LGqHhR|L6>~7s*3m|LFM0{P44H{0Gly)gu4^ literal 0 HcmV?d00001 diff --git a/Build/Sprites/ZDFlagWhite.png b/Build/Sprites/ZDFlagWhite.png new file mode 100644 index 0000000000000000000000000000000000000000..d2abb48ac72724fce21700b85305a88abbf9e582 GIT binary patch literal 1367 zcmd^7@vBpH6h9($_08v?Nmm+=nHL;-jSDWl!G$h*pWZ$9^orNIJZ`Y`hNCXE>Wa7L zjRxIl$g-uA7T#>hkRju>V8x^vD_*b%tDZPx#n2h=)qa>UXo*qa>8t-nU%uyj_@2Z0 zobUJhIVTV7m&eB*8v}sxsp#ZEf}4pwwQ42t+LMp}Lts_n^_@ouuDhQQZ!UiYuo4bT zAKFdMA=*d#saPzAh{0em5D55uK8m6^KE$woIz;(tPy|+vFd`eoTJ3JRJSr9k`FuZ{ z?WNOQ$7x$u%QTyY(a`m}rd1WCBFiOFEDC}biR3vh%d#1UaYLb0Flf`X6$qGqf5PXB zQMy*z>R;%T5xl}3@3Wa<=pUdSknT+eYsZ`3g?PM}(nxQAcB}_#(WK|PnB_hf!FNP7VL09Y4rFoC5I3Z6Dq$SE?foP50F4pVldFVJ8 zkE1AJD1-n*fF*zqKntJ&Pz5LfcmNrI6o3Vg0MG%5WJIriADc}qmob|~%R*H}o+nd8 zXviisgo6-}Y8Su+Q1AC0bg@&%riWDri#lcnOa(_4JxKa{34bTs_KfC;xo85P%IC19I+2gm@-d)>zC+xS6eZO_$ s>c5vJejUv&*k3RgBctz};q=1zr|PB5^{@4J$wOgk_x{Pxc0K?0e+@Oxng9R* literal 0 HcmV?d00001 diff --git a/Build/Sprites/ZDRailgun.png b/Build/Sprites/ZDRailgun.png new file mode 100644 index 0000000000000000000000000000000000000000..0d02d62b4173a943c0baf65f5d07355ba31874ad GIT binary patch literal 1627 zcmd^7@oy7V9RF@$I%q~0Iw;Uc#TyjXA8w{di8r{w4Q^Z64%aOw6nA6?Hsb;XPVBUk zG7B_I#fk-nR4h`Yux3;#ql~HrCUiJt!XQN&tYnj#jHNCUrzY~e;h*8l`@T=!d-;C8 z-+Vux*45Q?{^VJc0U*DkysSpT#ZpYqn;@OXpN2O{kZ0MxtUoHQNM$zb4C^Q-f47Igo zJf5`6m9pFWMX^^95jDNhV_eXaEWT4W-dQKT0J~e+>0SP$G!pJ{0q!h;uAt&j!SdPe^5!EQ2&9iEJeK!KB#^?lE%Tbt#)EEtF5?ASUN*$)iX0w@0CY?^F zQmOv_{@&i+L?RK7$D`3`BoYaQLcw6r@AtR0wRyc>x7+P>Ivoy&&1SP&t%4x%Ja0Ce zS(arOhNfwXq6mU87z{X$YqeSo!)(ZE%~~vJj_YI1amEy;jee5y8b~K@5Op|@X-#Sk zrBdk?N=zKpz)b9$nIf5RW-(~eV1h1WUi)N?5+Ihyt8Lcd3F_E0nz*2e>iTj%00)2wU;!`#NRml< zWilv{K%o%wc#tR}lL;9Nl8Yo7X-hN`heRM{I{^d$(|FyX6iUWW!iOSu6fh$XfgI{l zQ8i>$q%DdhC+}rt-3&x&2vg7cL`j4q2zd|^5TX&n5P~2Hegk-MaAA@;wG^&4U`kvq zmr6Xd5&?h%U;rur=@F2hLK!2nOR1<2`uyOtf)Eshn}hk406FkxP4%3>dNi?hUQS8>9{GmtcT1*Z z3&ffAPq;_J+M_<&MVF>-TsQwJc6?t~6I9N;b|JB?KAa5QeJk>yuCt)<*!y*3=Xz#vJLA*xH(VpO zZ0P*4c}+N4*SWc2B!4V-sms0U?9+mchTAu>hN>O!Ulr$! zlouX8OrEbVVvpadY`kRK$JGwvq@Te#Pr|$K%3o9eY~1?kOE6em8o4mB;FtMFR&Crq zXIaal$+-{LtvU3~X?YK~-#6#W_-=jE#hT)o)0gI+>iW5xDp@}7>?>H$DfNkk@yqXS z+gNJPd&BY7^$&^aEr)K+RsFPlr}JK7q%5X>8tfT9+K~LZ+gEt`fp+DX8~vSb+L^Oy X+d$F4+qX(32SCM&>asJ-*T45KS`S8p literal 0 HcmV?d00001 From 399e527b5c03d2621551d5df0f98b48c4842ffd8 Mon Sep 17 00:00:00 2001 From: Xabis Date: Thu, 5 Sep 2019 06:37:31 -0400 Subject: [PATCH 05/34] Support for RenderRadius (PR#297 by Xabis) --- Source/Core/Config/ThingTypeInfo.cs | 6 ++++++ Source/Core/Map/Thing.cs | 4 ++++ Source/Core/VisualModes/VisualBlockMap.cs | 4 ++-- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Source/Core/Config/ThingTypeInfo.cs b/Source/Core/Config/ThingTypeInfo.cs index df7ac80f..6540db4b 100755 --- a/Source/Core/Config/ThingTypeInfo.cs +++ b/Source/Core/Config/ThingTypeInfo.cs @@ -71,6 +71,7 @@ namespace CodeImp.DoomBuilder.Config private bool bright; //mxd private bool arrow; private float radius; + private float renderradius; private float height; private int distancechecksq; //mxd. Contains squared value or int.MaxValue when not set private bool hangs; @@ -120,6 +121,7 @@ namespace CodeImp.DoomBuilder.Config public bool Bright { get { return bright; } } //mxd public bool Arrow { get { return arrow; } } public float Radius { get { return radius; } } + public float RenderRadius { get { return renderradius; } } public float Height { get { return height; } } public int DistanceCheckSq { get { return distancechecksq; } } //mxd public bool Hangs { get { return hangs; } } @@ -177,6 +179,7 @@ namespace CodeImp.DoomBuilder.Config this.bright = false; //mxd this.arrow = true; this.radius = 10f; + this.renderradius = 10f; this.height = 20f; this.distancechecksq = int.MaxValue; //mxd this.hangs = false; @@ -552,6 +555,9 @@ namespace CodeImp.DoomBuilder.Config // Size if(actor.HasPropertyWithValue("radius")) radius = actor.GetPropertyValueInt("radius", 0); if(actor.HasPropertyWithValue("height")) height = actor.GetPropertyValueInt("height", 0); + if (actor.HasPropertyWithValue("renderradius")) renderradius = actor.GetPropertyValueInt("renderradius", 0); + if (renderradius == 0) + renderradius = radius; //mxd. DistanceCheck. The value is CVAR. Also we'll need squared value if(actor.HasPropertyWithValue("distancecheck")) diff --git a/Source/Core/Map/Thing.cs b/Source/Core/Map/Thing.cs index 1803cbc4..8b650093 100755 --- a/Source/Core/Map/Thing.cs +++ b/Source/Core/Map/Thing.cs @@ -80,6 +80,7 @@ namespace CodeImp.DoomBuilder.Map // Configuration private float size; + private float rendersize; private float height; //mxd private PixelColor color; private bool fixedsize; @@ -106,6 +107,7 @@ namespace CodeImp.DoomBuilder.Map public int Action { get { return action; } set { BeforePropsChange(); action = value; } } public int[] Args { get { return args; } } public float Size { get { return size; } } + public float RenderSize { get { return rendersize; } } public float Height { get { return height; } } //mxd public PixelColor Color { get { return color; } } public bool FixedSize { get { return fixedsize; } } @@ -242,6 +244,7 @@ namespace CodeImp.DoomBuilder.Map t.action = action; t.args = (int[])args.Clone(); t.size = size; + t.rendersize = rendersize; t.height = height; //mxd t.color = color; t.directional = directional; @@ -532,6 +535,7 @@ namespace CodeImp.DoomBuilder.Map dynamiclighttype = ti.DynamicLightType; //General.ErrorLogger.Add(ErrorType.Warning, string.Format("thing dynamiclighttype is {0}; class is {1}", dynamiclighttype, ti.Actor.ClassName)); size = ti.Radius; + rendersize = ti.RenderRadius; height = ti.Height; //mxd fixedsize = ti.FixedSize; spritescale = ti.SpriteScale; //mxd diff --git a/Source/Core/VisualModes/VisualBlockMap.cs b/Source/Core/VisualModes/VisualBlockMap.cs index 50d1ea35..e0e68b6b 100755 --- a/Source/Core/VisualModes/VisualBlockMap.cs +++ b/Source/Core/VisualModes/VisualBlockMap.cs @@ -266,8 +266,8 @@ namespace CodeImp.DoomBuilder.VisualModes public void AddThing(Thing t) { //mxd - Point p1 = GetBlockCoordinates(new Vector2D(t.Position.x - t.Size, t.Position.y - t.Size)); - Point p2 = GetBlockCoordinates(new Vector2D(t.Position.x + t.Size, t.Position.y + t.Size)); + Point p1 = GetBlockCoordinates(new Vector2D(t.Position.x - t.RenderSize, t.Position.y - t.RenderSize)); + Point p2 = GetBlockCoordinates(new Vector2D(t.Position.x + t.RenderSize, t.Position.y + t.RenderSize)); for(int x = p1.X; x <= p2.X; x++) { for(int y = p1.Y; y <= p2.Y; y++) From e799d882a9ff2407ef443c0386d6c888a826b63a Mon Sep 17 00:00:00 2001 From: biwa Date: Tue, 17 Sep 2019 20:22:51 +0200 Subject: [PATCH 06/34] Fixed a crash when manually modifying a sidedef's sector index to a sector with a tag --- .../Plugins/BuilderModes/ClassicModes/LinedefsMode.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Source/Plugins/BuilderModes/ClassicModes/LinedefsMode.cs b/Source/Plugins/BuilderModes/ClassicModes/LinedefsMode.cs index b8434667..5606628e 100755 --- a/Source/Plugins/BuilderModes/ClassicModes/LinedefsMode.cs +++ b/Source/Plugins/BuilderModes/ClassicModes/LinedefsMode.cs @@ -821,7 +821,10 @@ namespace CodeImp.DoomBuilder.BuilderModes if(General.Interface.IsActiveWindow) { // Show line edit dialog + General.Interface.OnEditFormValuesChanged += linedefEditForm_OnValuesChanged; DialogResult result = General.Interface.ShowEditLinedefs(selected); + General.Interface.OnEditFormValuesChanged -= linedefEditForm_OnValuesChanged; + General.Map.Map.Update(); // When a single line was selected, deselect it now @@ -835,6 +838,7 @@ namespace CodeImp.DoomBuilder.BuilderModes } // Update entire display + SetupSectorLabels(); General.Map.Renderer2D.UpdateExtraFloorFlag(); //mxd UpdateSelectionInfo(); //mxd General.Interface.RedrawDisplay(); @@ -847,6 +851,12 @@ namespace CodeImp.DoomBuilder.BuilderModes base.OnEditEnd(); } + private void linedefEditForm_OnValuesChanged(object sender, EventArgs e) + { + // This does nothing. It prevents automatic OnRedrawDisplay when closing the linedef edit form + // Required to prevent crash from issue #298 + } + //mxd public override void OnUndoEnd() { From c6b879bb1a5c617fd86464fe45af376122f0c9bf Mon Sep 17 00:00:00 2001 From: mykola-ambar Date: Fri, 20 Sep 2019 21:49:30 +0300 Subject: [PATCH 07/34] Fix sector offset transformation in Edit Selection mode (PR#274 by mykola-ambar) --- .../BuilderModes/ClassicModes/EditSelectionMode.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Source/Plugins/BuilderModes/ClassicModes/EditSelectionMode.cs b/Source/Plugins/BuilderModes/ClassicModes/EditSelectionMode.cs index 9e63c3a3..2e109034 100755 --- a/Source/Plugins/BuilderModes/ClassicModes/EditSelectionMode.cs +++ b/Source/Plugins/BuilderModes/ClassicModes/EditSelectionMode.cs @@ -893,13 +893,14 @@ namespace CodeImp.DoomBuilder.BuilderModes float texrotation = Angle2D.PI2 - rotation; // Update texture offsets - if(transformoffsets) + if (transformoffsets) { - Vector2D toffset = (selectionbasecenter - selectioncenter).GetRotated((texrotation + si.Rotation)); - Vector2D soffset = si.Offset.GetRotated(texrotation + si.Rotation); + float trotation = rotateoffsets ? (si.Rotation + texrotation) : (si.Rotation); + Vector2D offset = selectioncenter.GetRotated(trotation); + + fields["xpanning" + si.Part] = new UniValue(UniversalType.Float, (float)Math.Round(-offset.x, General.Map.FormatInterface.VertexDecimals)); + fields["ypanning" + si.Part] = new UniValue(UniversalType.Float, (float)Math.Round(offset.y, General.Map.FormatInterface.VertexDecimals)); - fields["xpanning" + si.Part] = new UniValue(UniversalType.Float, (float)Math.Round(soffset.x + toffset.x, General.Map.FormatInterface.VertexDecimals) % si.TextureSize.Width); - fields["ypanning" + si.Part] = new UniValue(UniversalType.Float, (float)Math.Round(-(soffset.y + toffset.y), General.Map.FormatInterface.VertexDecimals) % si.TextureSize.Height); } // Restore texture offsets else @@ -1825,7 +1826,7 @@ namespace CodeImp.DoomBuilder.BuilderModes renderer.RenderRectangleFilled(rotategrips[i], General.Colors.Background, true); renderer.RenderRectangle(rotategrips[i], 2, General.Colors.Indication, true); } - + renderer.Finish(); } From 67a6818632acfbdb00af70bbcdaeab0aef5d1674 Mon Sep 17 00:00:00 2001 From: biwa Date: Fri, 20 Sep 2019 23:14:53 +0200 Subject: [PATCH 08/34] - UDMF vertex heights are now preserved in a more sensible way when joining vertices. Fixes #299. --- Source/Core/Map/Vertex.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Source/Core/Map/Vertex.cs b/Source/Core/Map/Vertex.cs index b87fe50e..e2f4e5af 100755 --- a/Source/Core/Map/Vertex.cs +++ b/Source/Core/Map/Vertex.cs @@ -306,6 +306,10 @@ namespace CodeImp.DoomBuilder.Map // Which means this vertex is removed and the other is kept! public void Join(Vertex other) { + // biwa. Preserve z coords in a smart way + if (float.IsNaN(other.ZCeiling)) other.ZCeiling = zceiling; + if (float.IsNaN(other.ZFloor)) other.ZFloor = zfloor; + // If either of the two vertices was selected, keep the other selected if(this.Selected) other.Selected = true; if(this.marked) other.marked = true; From 6aa82e2ad9159ed62d02a3691f33a705108e266a Mon Sep 17 00:00:00 2001 From: biwa Date: Sat, 21 Sep 2019 14:03:30 +0200 Subject: [PATCH 09/34] - Slope effects related to slope things are now displayed more correctly in visual mode (they were not applied at all). Fixes #160 - Slope effects of UDMF vertex heights are now displayed more correctly in visual mode (they could be overwritten by lower tier slopes) --- .../VisualModes/BaseVisualMode.cs | 94 ++++++++++--------- 1 file changed, 49 insertions(+), 45 deletions(-) diff --git a/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs b/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs index 7193ae9c..14a91042 100755 --- a/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs +++ b/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs @@ -813,51 +813,6 @@ namespace CodeImp.DoomBuilder.BuilderModes } } - // Find sectors with 3 vertices, because they can be sloped - foreach(Sector s in General.Map.Map.Sectors) - { - // ========== Thing vertex slope, vertices with UDMF vertex offsets ========== - if(s.Sidedefs.Count == 3) - { - if(General.Map.UDMF) GetSectorData(s).AddEffectVertexOffset(); //mxd - List slopeceilingthings = new List(3); - List slopefloorthings = new List(3); - - foreach(Sidedef sd in s.Sidedefs) - { - Vertex v = sd.IsFront ? sd.Line.End : sd.Line.Start; - - // Check if a thing is at this vertex - VisualBlockEntry b = blockmap.GetBlock(blockmap.GetBlockCoordinates(v.Position)); - foreach(Thing t in b.Things) - { - if((Vector2D)t.Position == v.Position) - { - switch(t.Type) - { - case 1504: slopefloorthings.Add(t); break; - case 1505: slopeceilingthings.Add(t); break; - } - } - } - } - - // Slope any floor vertices? - if(slopefloorthings.Count > 0) - { - SectorData sd = GetSectorData(s); - sd.AddEffectThingVertexSlope(slopefloorthings, true); - } - - // Slope any ceiling vertices? - if(slopeceilingthings.Count > 0) - { - SectorData sd = GetSectorData(s); - sd.AddEffectThingVertexSlope(slopeceilingthings, false); - } - } - } - // Find interesting linedefs (such as line slopes) foreach(Linedef l in General.Map.Map.Linedefs) { @@ -1044,6 +999,51 @@ namespace CodeImp.DoomBuilder.BuilderModes break; } } + + // Find sectors with 3 vertices, because they can be sloped + foreach (Sector s in General.Map.Map.Sectors) + { + // ========== Thing vertex slope, vertices with UDMF vertex offsets ========== + if (s.Sidedefs.Count == 3) + { + if (General.Map.UDMF) GetSectorData(s).AddEffectVertexOffset(); //mxd + List slopeceilingthings = new List(3); + List slopefloorthings = new List(3); + + foreach (Sidedef sd in s.Sidedefs) + { + Vertex v = sd.IsFront ? sd.Line.End : sd.Line.Start; + + // Check if a thing is at this vertex + VisualBlockEntry b = blockmap.GetBlock(blockmap.GetBlockCoordinates(v.Position)); + foreach (Thing t in b.Things) + { + if ((Vector2D)t.Position == v.Position) + { + switch (t.Type) + { + case 1504: slopefloorthings.Add(t); break; + case 1505: slopeceilingthings.Add(t); break; + } + } + } + } + + // Slope any floor vertices? + if (slopefloorthings.Count > 0) + { + SectorData sd = GetSectorData(s); + sd.AddEffectThingVertexSlope(slopefloorthings, true); + } + + // Slope any ceiling vertices? + if (slopeceilingthings.Count > 0) + { + SectorData sd = GetSectorData(s); + sd.AddEffectThingVertexSlope(slopeceilingthings, false); + } + } + } } #endregion @@ -1071,6 +1071,10 @@ namespace CodeImp.DoomBuilder.BuilderModes foreach (Sector s in General.Map.Map.Sectors) s.UpdateFogColor(); + // biwa. We need a blockmap for the slope things. Can't wait until it's built in base.OnEngage + // This was the root cause for issue #160 + FillBlockMap(); + // (Re)create special effects RebuildElementData(); From c255a6e957f56cc1fb7b4e1a357480bdf5c4b192 Mon Sep 17 00:00:00 2001 From: biwa Date: Sun, 6 Oct 2019 21:56:55 +0200 Subject: [PATCH 10/34] - Fixed several issues where slopes were not shown correctly in visual mode --- .../VisualModes/BaseVisualMode.cs | 198 ++++++++++++------ .../VisualModes/EffectThingLineSlope.cs | 85 ++------ .../BuilderModes/VisualModes/SectorData.cs | 4 +- 3 files changed, 156 insertions(+), 131 deletions(-) diff --git a/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs b/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs index 14a91042..c743bacd 100755 --- a/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs +++ b/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs @@ -756,8 +756,10 @@ namespace CodeImp.DoomBuilder.BuilderModes internal void RebuildElementData() { HashSet effectsectors = null; //mxd + List[] slopelinedefpass = new List[] { new List(), new List() }; + List[] slopethingpass = new List[] { new List(), new List() }; - if(!General.Settings.EnhancedRenderingEffects) //mxd + if (!General.Settings.EnhancedRenderingEffects) //mxd { // Store all sectors with effects if(sectordata != null && sectordata.Count > 0) @@ -778,6 +780,7 @@ namespace CodeImp.DoomBuilder.BuilderModes } Dictionary> sectortags = new Dictionary>(); + Dictionary> linetags = new Dictionary>(); sectordata = new Dictionary(General.Map.Map.Sectors.Count); thingdata = new Dictionary(General.Map.Map.Things.Count); @@ -814,64 +817,40 @@ namespace CodeImp.DoomBuilder.BuilderModes } // Find interesting linedefs (such as line slopes) - foreach(Linedef l in General.Map.Map.Linedefs) + // This also determines which slope lines belong to pass one and pass two. See https://zdoom.org/wiki/Slope + foreach (Linedef l in General.Map.Map.Linedefs) { + // Builds a cache of linedef ids/tags. Used for slope things. Use linedef tags in UDMF + if(General.Map.UDMF) + { + foreach(int tag in l.Tags) + { + if (!linetags.ContainsKey(tag)) linetags[tag] = new List(); + linetags[tag].Add(l); + } + } + //mxd. Rewritten to use action ID instead of number - if(l.Action == 0 || !General.Map.Config.LinedefActions.ContainsKey(l.Action)) continue; + if (l.Action == 0 || !General.Map.Config.LinedefActions.ContainsKey(l.Action)) continue; switch(General.Map.Config.LinedefActions[l.Action].Id.ToLowerInvariant()) { + // ========== Line Set Identification (121) (see https://zdoom.org/wiki/Line_SetIdentification) ========== + // Builds a cache of linedef ids/tags. Used for slope things. Only used for Hexen format + case "line_setidentification": + int tag = l.Args[0] + l.Args[4] * 256; + if (!linetags.ContainsKey(tag)) linetags[tag] = new List(); + linetags[tag].Add(l); + break; + // ========== Plane Align (181) (see http://zdoom.org/wiki/Plane_Align) ========== case "plane_align": - if(((l.Args[0] == 1) || (l.Args[1] == 1)) && (l.Front != null)) - { - SectorData sd = GetSectorData(l.Front.Sector); - sd.AddEffectLineSlope(l); - } - if(((l.Args[0] == 2) || (l.Args[1] == 2)) && (l.Back != null)) - { - SectorData sd = GetSectorData(l.Back.Sector); - sd.AddEffectLineSlope(l); - } + slopelinedefpass[0].Add(l); break; // ========== Plane Copy (118) (mxd) (see http://zdoom.org/wiki/Plane_Copy) ========== - case "plane_copy": - { - //check the flags... - bool floorCopyToBack = false; - bool floorCopyToFront = false; - bool ceilingCopyToBack = false; - bool ceilingCopyToFront = false; - - if(l.Args[4] > 0 && l.Args[4] != 3 && l.Args[4] != 12) - { - floorCopyToBack = (l.Args[4] & 1) == 1; - floorCopyToFront = (l.Args[4] & 2) == 2; - ceilingCopyToBack = (l.Args[4] & 4) == 4; - ceilingCopyToFront = (l.Args[4] & 8) == 8; - } - - // Copy slope to front sector - if(l.Front != null) - { - if( (l.Args[0] > 0 || l.Args[1] > 0) || (l.Back != null && (floorCopyToFront || ceilingCopyToFront)) ) - { - SectorData sd = GetSectorData(l.Front.Sector); - sd.AddEffectPlaneClopySlope(l, true); - } - } - - // Copy slope to back sector - if(l.Back != null) - { - if( (l.Args[2] > 0 || l.Args[3] > 0) || (l.Front != null && (floorCopyToBack || ceilingCopyToBack)) ) - { - SectorData sd = GetSectorData(l.Back.Sector); - sd.AddEffectPlaneClopySlope(l, false); - } - } - } + case "plane_copy": + slopelinedefpass[1].Add(l); break; // ========== Sector 3D floor (160) (see http://zdoom.org/wiki/Sector_Set3dFloor) ========== @@ -959,31 +938,55 @@ namespace CodeImp.DoomBuilder.BuilderModes } } - // Find interesting things (such as sector slopes) - //TODO: rewrite using classnames instead of numbers - foreach(Thing t in General.Map.Map.Things) + // Pass one for linedefs + foreach (Linedef l in slopelinedefpass[0]) { - switch(t.Type) + //mxd. Rewritten to use action ID instead of number + if (l.Action == 0 || !General.Map.Config.LinedefActions.ContainsKey(l.Action)) continue; + + switch (General.Map.Config.LinedefActions[l.Action].Id.ToLowerInvariant()) + { + // ========== Plane Align (181) (see http://zdoom.org/wiki/Plane_Align) ========== + case "plane_align": + if (((l.Args[0] == 1) || (l.Args[1] == 1)) && (l.Front != null)) + { + SectorData sd = GetSectorData(l.Front.Sector); + sd.AddEffectLineSlope(l); + } + if (((l.Args[0] == 2) || (l.Args[1] == 2)) && (l.Back != null)) + { + SectorData sd = GetSectorData(l.Back.Sector); + sd.AddEffectLineSlope(l); + } + break; + } + } + + // Find interesting things (such as sector slopes) + // Pass one of slope things, and determine which one are for pass two + //TODO: rewrite using classnames instead of numbers + foreach (Thing t in General.Map.Map.Things) + { + switch (t.Type) { // ========== Copy slope ========== case 9511: case 9510: - t.DetermineSector(blockmap); - if(t.Sector != null) - { - SectorData sd = GetSectorData(t.Sector); - sd.AddEffectCopySlope(t); - } + slopethingpass[1].Add(t); break; // ========== Thing line slope ========== case 9501: case 9500: - t.DetermineSector(blockmap); - if(t.Sector != null) + if(linetags.ContainsKey(t.Args[0])) { - SectorData sd = GetSectorData(t.Sector); - sd.AddEffectThingLineSlope(t); + foreach(Linedef ld in linetags[t.Args[0]]) + { + if (ld.Line.GetSideOfLine(t.Position) < 0.0f) + GetSectorData(ld.Front.Sector).AddEffectThingLineSlope(t, ld.Front); + else if (ld.Back != null) + GetSectorData(ld.Back.Sector).AddEffectThingLineSlope(t, ld.Back); + } } break; @@ -991,7 +994,7 @@ namespace CodeImp.DoomBuilder.BuilderModes case 9503: case 9502: t.DetermineSector(blockmap); - if(t.Sector != null) + if (t.Sector != null) { SectorData sd = GetSectorData(t.Sector); sd.AddEffectThingSlope(t); @@ -1000,6 +1003,25 @@ namespace CodeImp.DoomBuilder.BuilderModes } } + // Pass two of slope things + //TODO: rewrite using classnames instead of numbers + foreach (Thing t in slopethingpass[1]) + { + switch (t.Type) + { + // ========== Copy slope ========== + case 9511: + case 9510: + t.DetermineSector(blockmap); + if (t.Sector != null) + { + SectorData sd = GetSectorData(t.Sector); + sd.AddEffectCopySlope(t); + } + break; + } + } + // Find sectors with 3 vertices, because they can be sloped foreach (Sector s in General.Map.Map.Sectors) { @@ -1044,6 +1066,54 @@ namespace CodeImp.DoomBuilder.BuilderModes } } } + + // Pass two for linedefs + foreach (Linedef l in slopelinedefpass[1]) + { + if (l.Action == 0 || !General.Map.Config.LinedefActions.ContainsKey(l.Action)) continue; + + switch (General.Map.Config.LinedefActions[l.Action].Id.ToLowerInvariant()) + { + // ========== Plane Copy (118) (mxd) (see http://zdoom.org/wiki/Plane_Copy) ========== + case "plane_copy": + { + //check the flags... + bool floorCopyToBack = false; + bool floorCopyToFront = false; + bool ceilingCopyToBack = false; + bool ceilingCopyToFront = false; + + if (l.Args[4] > 0 && l.Args[4] != 3 && l.Args[4] != 12) + { + floorCopyToBack = (l.Args[4] & 1) == 1; + floorCopyToFront = (l.Args[4] & 2) == 2; + ceilingCopyToBack = (l.Args[4] & 4) == 4; + ceilingCopyToFront = (l.Args[4] & 8) == 8; + } + + // Copy slope to front sector + if (l.Front != null) + { + if ((l.Args[0] > 0 || l.Args[1] > 0) || (l.Back != null && (floorCopyToFront || ceilingCopyToFront))) + { + SectorData sd = GetSectorData(l.Front.Sector); + sd.AddEffectPlaneClopySlope(l, true); + } + } + + // Copy slope to back sector + if (l.Back != null) + { + if ((l.Args[2] > 0 || l.Args[3] > 0) || (l.Front != null && (floorCopyToBack || ceilingCopyToBack))) + { + SectorData sd = GetSectorData(l.Back.Sector); + sd.AddEffectPlaneClopySlope(l, false); + } + } + } + break; + } + } } #endregion diff --git a/Source/Plugins/BuilderModes/VisualModes/EffectThingLineSlope.cs b/Source/Plugins/BuilderModes/VisualModes/EffectThingLineSlope.cs index 0ac9ebac..335e27ca 100755 --- a/Source/Plugins/BuilderModes/VisualModes/EffectThingLineSlope.cs +++ b/Source/Plugins/BuilderModes/VisualModes/EffectThingLineSlope.cs @@ -13,11 +13,13 @@ namespace CodeImp.DoomBuilder.BuilderModes // The thing is in the sector that must receive the slope and the // Thing's arg 0 indicates the linedef to start the slope at. private Thing thing; + private Sidedef sidedef; // Constructor - public EffectThingLineSlope(SectorData data, Thing sourcething) : base(data) + public EffectThingLineSlope(SectorData data, Thing sourcething, Sidedef sourcesidedef) : base(data) { thing = sourcething; + sidedef = sourcesidedef; // New effect added: This sector needs an update! if(data.Mode.VisualSectorExists(data.Sector)) @@ -35,78 +37,31 @@ namespace CodeImp.DoomBuilder.BuilderModes ThingData td = data.Mode.GetThingData(thing); Thing t = thing; + Linedef ld = sidedef.Line; - // Find the tagged line - Linedef ld = null; - foreach(Linedef l in General.Map.Map.Linedefs) - { - if(l.Tags.Contains(t.Args[0])) - { - ld = l; - break; - } - } - if(ld != null) { if(t.Type == 9500) { - // Slope the floor from the linedef to thing - t.DetermineSector(data.Mode.BlockMap); - if(t.Sector != null) - { - Vector3D v3 = new Vector3D(t.Position.x, t.Position.y, t.Position.z + t.Sector.FloorHeight); - if(ld.SideOfLine(t.Position) < 0.0f) - { - Vector3D v1 = new Vector3D(ld.Start.Position.x, ld.Start.Position.y, ld.Front.Sector.FloorHeight); - Vector3D v2 = new Vector3D(ld.End.Position.x, ld.End.Position.y, ld.Front.Sector.FloorHeight); - SectorData sd = data.Mode.GetSectorData(ld.Front.Sector); - sd.AddUpdateSector(data.Sector, true); - if(!sd.Updated) sd.Update(); - td.AddUpdateSector(ld.Front.Sector, true); - sd.Floor.plane = new Plane(v1, v2, v3, true); - } - else - { - Vector3D v1 = new Vector3D(ld.Start.Position.x, ld.Start.Position.y, ld.Back.Sector.FloorHeight); - Vector3D v2 = new Vector3D(ld.End.Position.x, ld.End.Position.y, ld.Back.Sector.FloorHeight); - SectorData sd = data.Mode.GetSectorData(ld.Back.Sector); - sd.AddUpdateSector(data.Sector, true); - if(!sd.Updated) sd.Update(); - td.AddUpdateSector(ld.Back.Sector, true); - sd.Floor.plane = new Plane(v2, v1, v3, true); - } - } + SectorData sd = data.Mode.GetSectorData(sidedef.Sector); + Vector3D v1 = new Vector3D(ld.Start.Position.x, ld.Start.Position.y, sd.Floor.plane.GetZ(ld.Start.Position)); + Vector3D v2 = new Vector3D(ld.End.Position.x, ld.End.Position.y, sd.Floor.plane.GetZ(ld.End.Position)); + Vector3D v3 = new Vector3D(t.Position.x, t.Position.y, t.Position.z + sd.Floor.plane.GetZ(t.Position)); + sd.AddUpdateSector(data.Sector, true); + if (!sd.Updated) sd.Update(); + td.AddUpdateSector(sidedef.Sector, true); + sd.Floor.plane = new Plane(v1, v2, v3, true); } else if(t.Type == 9501) { - // Slope the ceiling from the linedef to thing - t.DetermineSector(data.Mode.BlockMap); - if(t.Sector != null) - { - td.AddUpdateSector(t.Sector, true); - Vector3D v3 = new Vector3D(t.Position.x, t.Position.y, t.Position.z + t.Sector.CeilHeight); - if(ld.SideOfLine(t.Position) < 0.0f) - { - Vector3D v1 = new Vector3D(ld.Start.Position.x, ld.Start.Position.y, ld.Front.Sector.CeilHeight); - Vector3D v2 = new Vector3D(ld.End.Position.x, ld.End.Position.y, ld.Front.Sector.CeilHeight); - SectorData sd = data.Mode.GetSectorData(ld.Front.Sector); - sd.AddUpdateSector(data.Sector, true); - td.AddUpdateSector(ld.Front.Sector, true); - if(!sd.Updated) sd.Update(); - sd.Ceiling.plane = new Plane(v1, v2, v3, false); - } - else - { - Vector3D v1 = new Vector3D(ld.Start.Position.x, ld.Start.Position.y, ld.Back.Sector.CeilHeight); - Vector3D v2 = new Vector3D(ld.End.Position.x, ld.End.Position.y, ld.Back.Sector.CeilHeight); - SectorData sd = data.Mode.GetSectorData(ld.Back.Sector); - sd.AddUpdateSector(data.Sector, true); - td.AddUpdateSector(ld.Back.Sector, true); - if(!sd.Updated) sd.Update(); - sd.Ceiling.plane = new Plane(v2, v1, v3, false); - } - } + SectorData sd = data.Mode.GetSectorData(sidedef.Sector); + Vector3D v1 = new Vector3D(ld.Start.Position.x, ld.Start.Position.y, sd.Ceiling.plane.GetZ(ld.Start.Position)); + Vector3D v2 = new Vector3D(ld.End.Position.x, ld.End.Position.y, sd.Ceiling.plane.GetZ(ld.End.Position)); + Vector3D v3 = new Vector3D(t.Position.x, t.Position.y, t.Position.z + sd.Ceiling.plane.GetZ(t.Position)); + sd.AddUpdateSector(data.Sector, true); + if (!sd.Updated) sd.Update(); + td.AddUpdateSector(sidedef.Sector, true); + sd.Ceiling.plane = new Plane(v1, v2, v3, false); } } } diff --git a/Source/Plugins/BuilderModes/VisualModes/SectorData.cs b/Source/Plugins/BuilderModes/VisualModes/SectorData.cs index 5e889091..126aee3c 100755 --- a/Source/Plugins/BuilderModes/VisualModes/SectorData.cs +++ b/Source/Plugins/BuilderModes/VisualModes/SectorData.cs @@ -177,9 +177,9 @@ namespace CodeImp.DoomBuilder.BuilderModes } // Thing line slope effect - public void AddEffectThingLineSlope(Thing sourcething) + public void AddEffectThingLineSlope(Thing sourcething, Sidedef sourcesidedef) { - EffectThingLineSlope e = new EffectThingLineSlope(this, sourcething); + EffectThingLineSlope e = new EffectThingLineSlope(this, sourcething, sourcesidedef); alleffects.Add(e); } From 8fe66886b8a750fdba55a1968a58ffcd4365cfc3 Mon Sep 17 00:00:00 2001 From: biwa Date: Mon, 7 Oct 2019 19:07:22 +0200 Subject: [PATCH 11/34] - The Updater is now x64 in the x64 build and can update the x64 version of GZDB-BF --- .../ChangelogMaker/ChangelogMaker.csproj | 30 +++++++++++ Source/Tools/Tools.sln | 54 ++++++++++++------- Source/Tools/Updater/Updater.csproj | 45 ++++++++++++++++ .../VersionFromEXE/VersionFromEXE.csproj | 30 +++++++++++ .../VersionFromSVN/VersionFromGIT.csproj | 30 +++++++++++ build_git_generic.cmd | 12 ++++- 6 files changed, 182 insertions(+), 19 deletions(-) diff --git a/Source/Tools/ChangelogMaker/ChangelogMaker.csproj b/Source/Tools/ChangelogMaker/ChangelogMaker.csproj index cf55c5e8..0eeea2d9 100755 --- a/Source/Tools/ChangelogMaker/ChangelogMaker.csproj +++ b/Source/Tools/ChangelogMaker/ChangelogMaker.csproj @@ -35,6 +35,36 @@ prompt 4 + + bin\x64\Debug\ + DEBUG;TRACE + x64 + prompt + MinimumRecommendedRules.ruleset + + + bin\x64\Release\ + TRACE + true + x64 + prompt + MinimumRecommendedRules.ruleset + + + bin\x86\Debug\ + DEBUG;TRACE + x86 + prompt + MinimumRecommendedRules.ruleset + + + bin\x86\Release\ + TRACE + true + x86 + prompt + MinimumRecommendedRules.ruleset + 3.5 diff --git a/Source/Tools/Tools.sln b/Source/Tools/Tools.sln index 00c38bfa..6e77027a 100755 --- a/Source/Tools/Tools.sln +++ b/Source/Tools/Tools.sln @@ -13,26 +13,44 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChangelogMaker", "Changelog EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {2A0BA1B2-A0F1-479F-9083-2EC11D6B70DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2A0BA1B2-A0F1-479F-9083-2EC11D6B70DF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2A0BA1B2-A0F1-479F-9083-2EC11D6B70DF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2A0BA1B2-A0F1-479F-9083-2EC11D6B70DF}.Release|Any CPU.Build.0 = Release|Any CPU - {72734EB9-2733-4C05-A091-7FA591AF53C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {72734EB9-2733-4C05-A091-7FA591AF53C3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {72734EB9-2733-4C05-A091-7FA591AF53C3}.Release|Any CPU.ActiveCfg = Release|Any CPU - {72734EB9-2733-4C05-A091-7FA591AF53C3}.Release|Any CPU.Build.0 = Release|Any CPU - {58D7AB05-5FA0-47EE-8F74-463AC2AED47C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {58D7AB05-5FA0-47EE-8F74-463AC2AED47C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {58D7AB05-5FA0-47EE-8F74-463AC2AED47C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {58D7AB05-5FA0-47EE-8F74-463AC2AED47C}.Release|Any CPU.Build.0 = Release|Any CPU - {5023F443-E5D2-4252-9691-19700622349E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5023F443-E5D2-4252-9691-19700622349E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5023F443-E5D2-4252-9691-19700622349E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5023F443-E5D2-4252-9691-19700622349E}.Release|Any CPU.Build.0 = Release|Any CPU + {2A0BA1B2-A0F1-479F-9083-2EC11D6B70DF}.Debug|x64.ActiveCfg = Debug|x64 + {2A0BA1B2-A0F1-479F-9083-2EC11D6B70DF}.Debug|x64.Build.0 = Debug|x64 + {2A0BA1B2-A0F1-479F-9083-2EC11D6B70DF}.Debug|x86.ActiveCfg = Debug|x86 + {2A0BA1B2-A0F1-479F-9083-2EC11D6B70DF}.Debug|x86.Build.0 = Debug|x86 + {2A0BA1B2-A0F1-479F-9083-2EC11D6B70DF}.Release|x64.ActiveCfg = Release|x64 + {2A0BA1B2-A0F1-479F-9083-2EC11D6B70DF}.Release|x64.Build.0 = Release|x64 + {2A0BA1B2-A0F1-479F-9083-2EC11D6B70DF}.Release|x86.ActiveCfg = Release|x86 + {2A0BA1B2-A0F1-479F-9083-2EC11D6B70DF}.Release|x86.Build.0 = Release|x86 + {72734EB9-2733-4C05-A091-7FA591AF53C3}.Debug|x64.ActiveCfg = Debug|x64 + {72734EB9-2733-4C05-A091-7FA591AF53C3}.Debug|x64.Build.0 = Debug|x64 + {72734EB9-2733-4C05-A091-7FA591AF53C3}.Debug|x86.ActiveCfg = Debug|x86 + {72734EB9-2733-4C05-A091-7FA591AF53C3}.Debug|x86.Build.0 = Debug|x86 + {72734EB9-2733-4C05-A091-7FA591AF53C3}.Release|x64.ActiveCfg = Release|x64 + {72734EB9-2733-4C05-A091-7FA591AF53C3}.Release|x64.Build.0 = Release|x64 + {72734EB9-2733-4C05-A091-7FA591AF53C3}.Release|x86.ActiveCfg = Release|x86 + {72734EB9-2733-4C05-A091-7FA591AF53C3}.Release|x86.Build.0 = Release|x86 + {58D7AB05-5FA0-47EE-8F74-463AC2AED47C}.Debug|x64.ActiveCfg = Debug|x64 + {58D7AB05-5FA0-47EE-8F74-463AC2AED47C}.Debug|x64.Build.0 = Debug|x64 + {58D7AB05-5FA0-47EE-8F74-463AC2AED47C}.Debug|x86.ActiveCfg = Debug|x86 + {58D7AB05-5FA0-47EE-8F74-463AC2AED47C}.Debug|x86.Build.0 = Debug|x86 + {58D7AB05-5FA0-47EE-8F74-463AC2AED47C}.Release|x64.ActiveCfg = Release|x64 + {58D7AB05-5FA0-47EE-8F74-463AC2AED47C}.Release|x64.Build.0 = Release|x64 + {58D7AB05-5FA0-47EE-8F74-463AC2AED47C}.Release|x86.ActiveCfg = Release|x86 + {58D7AB05-5FA0-47EE-8F74-463AC2AED47C}.Release|x86.Build.0 = Release|x86 + {5023F443-E5D2-4252-9691-19700622349E}.Debug|x64.ActiveCfg = Debug|x64 + {5023F443-E5D2-4252-9691-19700622349E}.Debug|x64.Build.0 = Debug|x64 + {5023F443-E5D2-4252-9691-19700622349E}.Debug|x86.ActiveCfg = Debug|x86 + {5023F443-E5D2-4252-9691-19700622349E}.Debug|x86.Build.0 = Debug|x86 + {5023F443-E5D2-4252-9691-19700622349E}.Release|x64.ActiveCfg = Release|x64 + {5023F443-E5D2-4252-9691-19700622349E}.Release|x64.Build.0 = Release|x64 + {5023F443-E5D2-4252-9691-19700622349E}.Release|x86.ActiveCfg = Release|x86 + {5023F443-E5D2-4252-9691-19700622349E}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Source/Tools/Updater/Updater.csproj b/Source/Tools/Updater/Updater.csproj index 5e6f14f6..c9c59960 100755 --- a/Source/Tools/Updater/Updater.csproj +++ b/Source/Tools/Updater/Updater.csproj @@ -57,6 +57,48 @@ false true + + true + bin\x64\Debug\ + DEBUG;TRACE + true + full + x64 + false + prompt + MinimumRecommendedRules.ruleset + + + bin\x64\Release\ + TRACE + true + true + x64 + false + prompt + MinimumRecommendedRules.ruleset + + + true + bin\x86\Debug\ + DEBUG;TRACE + true + full + x86 + false + prompt + MinimumRecommendedRules.ruleset + + + bin\x86\Release\ + TRACE + true + true + x86 + false + prompt + MinimumRecommendedRules.ruleset + False @@ -146,6 +188,9 @@ + + copy $(TargetPath) $(ProjectDir)..\..\..\Build + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Source/Plugins/3DFloorMode/Controls/ThreeDFloorTooltipControl.Designer.cs b/Source/Plugins/3DFloorMode/Controls/ThreeDFloorTooltipControl.Designer.cs new file mode 100644 index 00000000..d100853d --- /dev/null +++ b/Source/Plugins/3DFloorMode/Controls/ThreeDFloorTooltipControl.Designer.cs @@ -0,0 +1,165 @@ +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + partial class ThreeDFloorHelperTooltipElementControl + { + /// + /// Erforderliche Designervariable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Verwendete Ressourcen bereinigen. + /// + /// True, wenn verwaltete Ressourcen gelöscht werden sollen; andernfalls False. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Vom Komponenten-Designer generierter Code + + /// + /// Erforderliche Methode für die Designerunterstützung. + /// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden. + /// + private void InitializeComponent() + { + this.sectorTopFlat = new System.Windows.Forms.Panel(); + this.sectorBorderTexture = new System.Windows.Forms.Panel(); + this.sectorBottomFlat = new System.Windows.Forms.Panel(); + this.label3 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.label1 = new System.Windows.Forms.Label(); + this.bottomHeight = new System.Windows.Forms.Label(); + this.topHeight = new System.Windows.Forms.Label(); + this.borderHeight = new System.Windows.Forms.Label(); + this.SuspendLayout(); + // + // sectorTopFlat + // + this.sectorTopFlat.BackColor = System.Drawing.SystemColors.AppWorkspace; + this.sectorTopFlat.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; + this.sectorTopFlat.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; + this.sectorTopFlat.Location = new System.Drawing.Point(12, 16); + this.sectorTopFlat.Name = "sectorTopFlat"; + this.sectorTopFlat.Size = new System.Drawing.Size(65, 65); + this.sectorTopFlat.TabIndex = 22; + // + // sectorBorderTexture + // + this.sectorBorderTexture.BackColor = System.Drawing.SystemColors.AppWorkspace; + this.sectorBorderTexture.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; + this.sectorBorderTexture.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; + this.sectorBorderTexture.Location = new System.Drawing.Point(83, 16); + this.sectorBorderTexture.Name = "sectorBorderTexture"; + this.sectorBorderTexture.Size = new System.Drawing.Size(65, 65); + this.sectorBorderTexture.TabIndex = 21; + // + // sectorBottomFlat + // + this.sectorBottomFlat.BackColor = System.Drawing.SystemColors.AppWorkspace; + this.sectorBottomFlat.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; + this.sectorBottomFlat.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; + this.sectorBottomFlat.Location = new System.Drawing.Point(154, 16); + this.sectorBottomFlat.Name = "sectorBottomFlat"; + this.sectorBottomFlat.Size = new System.Drawing.Size(65, 65); + this.sectorBottomFlat.TabIndex = 20; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.BackColor = System.Drawing.Color.Transparent; + this.label3.Location = new System.Drawing.Point(80, 0); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(38, 13); + this.label3.TabIndex = 19; + this.label3.Text = "Border"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.BackColor = System.Drawing.Color.Transparent; + this.label2.Location = new System.Drawing.Point(151, 0); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(40, 13); + this.label2.TabIndex = 18; + this.label2.Text = "Bottom"; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.BackColor = System.Drawing.Color.Transparent; + this.label1.Location = new System.Drawing.Point(9, 0); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(26, 13); + this.label1.TabIndex = 17; + this.label1.Text = "Top"; + // + // bottomHeight + // + this.bottomHeight.BackColor = System.Drawing.Color.Transparent; + this.bottomHeight.Location = new System.Drawing.Point(189, 0); + this.bottomHeight.Name = "bottomHeight"; + this.bottomHeight.Size = new System.Drawing.Size(30, 13); + this.bottomHeight.TabIndex = 23; + this.bottomHeight.Text = "X"; + this.bottomHeight.TextAlign = System.Drawing.ContentAlignment.TopRight; + // + // topHeight + // + this.topHeight.BackColor = System.Drawing.Color.Transparent; + this.topHeight.Location = new System.Drawing.Point(47, 0); + this.topHeight.Name = "topHeight"; + this.topHeight.Size = new System.Drawing.Size(30, 13); + this.topHeight.TabIndex = 24; + this.topHeight.Text = "X"; + this.topHeight.TextAlign = System.Drawing.ContentAlignment.TopRight; + // + // borderHeight + // + this.borderHeight.BackColor = System.Drawing.Color.Transparent; + this.borderHeight.Location = new System.Drawing.Point(114, 0); + this.borderHeight.Name = "borderHeight"; + this.borderHeight.Size = new System.Drawing.Size(30, 13); + this.borderHeight.TabIndex = 25; + this.borderHeight.Text = "X"; + this.borderHeight.TextAlign = System.Drawing.ContentAlignment.TopRight; + // + // ThreeDFloorHelperTooltipElementControl + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.borderHeight); + this.Controls.Add(this.topHeight); + this.Controls.Add(this.bottomHeight); + this.Controls.Add(this.sectorTopFlat); + this.Controls.Add(this.sectorBorderTexture); + this.Controls.Add(this.sectorBottomFlat); + this.Controls.Add(this.label3); + this.Controls.Add(this.label2); + this.Controls.Add(this.label1); + this.Name = "ThreeDFloorHelperTooltipElementControl"; + this.Size = new System.Drawing.Size(222, 82); + this.Paint += new System.Windows.Forms.PaintEventHandler(this.ThreeDFloorHelperTooltipElementControl_Paint); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label label1; + public System.Windows.Forms.Panel sectorBorderTexture; + public System.Windows.Forms.Panel sectorTopFlat; + public System.Windows.Forms.Panel sectorBottomFlat; + public System.Windows.Forms.Label bottomHeight; + public System.Windows.Forms.Label topHeight; + public System.Windows.Forms.Label borderHeight; + } +} diff --git a/Source/Plugins/3DFloorMode/Controls/ThreeDFloorTooltipControl.cs b/Source/Plugins/3DFloorMode/Controls/ThreeDFloorTooltipControl.cs new file mode 100644 index 00000000..99fb7fe8 --- /dev/null +++ b/Source/Plugins/3DFloorMode/Controls/ThreeDFloorTooltipControl.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Data; +using System.Linq; +using System.Text; +using System.Windows.Forms; + +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + public partial class ThreeDFloorHelperTooltipElementControl : UserControl + { + private bool highlighted; + + public bool Highlighted { get { return highlighted; } set { highlighted = value; } } + + public ThreeDFloorHelperTooltipElementControl() + { + highlighted = false; + + InitializeComponent(); + } + + private void ThreeDFloorHelperTooltipElementControl_Paint(object sender, PaintEventArgs e) + { + Color c = Color.FromArgb(0, 192, 0); // Color.FromArgb(255, Color.Green); + + ControlPaint.DrawBorder( + e.Graphics, + this.ClientRectangle, + c, // leftColor + 5, // leftWidth + highlighted ? ButtonBorderStyle.Solid : ButtonBorderStyle.None, // leftStyle + c, // topColor + 0, // topWidth + ButtonBorderStyle.None, // topStyle + c, // rightColor + 0, // rightWidth + ButtonBorderStyle.None, // rightStyle + c, // bottomColor + 0, // bottomWidth + ButtonBorderStyle.None // bottomStyle + ); + } + } +} diff --git a/Source/Plugins/3DFloorMode/Controls/ThreeDFloorTooltipControl.resx b/Source/Plugins/3DFloorMode/Controls/ThreeDFloorTooltipControl.resx new file mode 100644 index 00000000..d58980a3 --- /dev/null +++ b/Source/Plugins/3DFloorMode/Controls/ThreeDFloorTooltipControl.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Source/Plugins/3DFloorMode/DrawSlopesMode.cs b/Source/Plugins/3DFloorMode/DrawSlopesMode.cs new file mode 100644 index 00000000..2539aa12 --- /dev/null +++ b/Source/Plugins/3DFloorMode/DrawSlopesMode.cs @@ -0,0 +1,892 @@ + +#region ================== Copyright (c) 2007 Pascal vd Heiden + +/* + * Copyright (c) 2007 Pascal vd Heiden, www.codeimp.com + * 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.Globalization; +using System.Text; +using System.Windows.Forms; +using System.IO; +using System.Reflection; +using System.Linq; +using CodeImp.DoomBuilder.Windows; +using CodeImp.DoomBuilder.IO; +using CodeImp.DoomBuilder.Map; +using CodeImp.DoomBuilder.Rendering; +using CodeImp.DoomBuilder.Types; +using CodeImp.DoomBuilder.Geometry; +using System.Drawing; +using CodeImp.DoomBuilder.Editing; +using CodeImp.DoomBuilder.Actions; + +#endregion + +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + enum SlopeDrawingMode { Floor, Ceiling, FloorAndCeiling }; + + [EditMode(DisplayName = "Draw Slopes Mode", + SwitchAction = "drawslopesmode", + ButtonImage = "DrawSlopeModeIcon.png", // Image resource name for the button + ButtonOrder = int.MinValue + 501, // Position of the button (lower is more to the left) + ButtonGroup = "000_editing", + AllowCopyPaste = false, + SupportedMapFormats = new[] { "UniversalMapSetIO" }, + Volatile = true, + UseByDefault = true, + Optional = false)] + + public class DrawSlopesMode : ClassicMode + { + #region ================== Constants + + private const float LINE_THICKNESS = 0.8f; + + #endregion + + #region ================== Variables + + // Drawing points + private List points; + + // Keep track of view changes + private float lastoffsetx; + private float lastoffsety; + private float lastscale; + + // Options + private bool snaptogrid; // SHIFT to toggle + private bool snaptonearest; // CTRL to enable + + private FlatVertex[] overlayGeometry; + private List labels; + + private static SlopeDrawingMode slopedrawingmode = SlopeDrawingMode.Floor; + + #endregion + + #region ================== Properties + + // Just keep the base mode button checked + public override string EditModeButtonName { get { return General.Editing.PreviousStableMode.Name; } } + + #endregion + + #region ================== Constructor / Disposer + + // Constructor + public DrawSlopesMode() + { + // Initialize + points = new List(); + + // No selection in this mode + //General.Map.Map.ClearAllSelected(); + //General.Map.Map.ClearAllMarks(false); + + // We have no destructor + GC.SuppressFinalize(this); + } + + // Disposer + public override void Dispose() + { + // Not already disposed? + if (!isdisposed) + { + // Dispose old labels + if (labels != null) + foreach (TextLabel l in labels) + l.Dispose(); + + // Done + base.Dispose(); + } + } + + #endregion + + #region ================== Methods + + // This checks if the view offset/zoom changed and updates the check + protected bool CheckViewChanged() + { + bool viewchanged = false; + + // View changed? + if (renderer.OffsetX != lastoffsetx) viewchanged = true; + if (renderer.OffsetY != lastoffsety) viewchanged = true; + if (renderer.Scale != lastscale) viewchanged = true; + + // Keep view information + lastoffsetx = renderer.OffsetX; + lastoffsety = renderer.OffsetY; + lastscale = renderer.Scale; + + // Return result + return viewchanged; + } + + // This sets up new labels + /* + private void SetupLabels() + { + if (labels != null) + { + // Dispose old labels + foreach (KeyValuePair lbl in labels) + foreach (TextLabel l in lbl.Value) l.Dispose(); + } + + // Make text labels for sectors + labels = new Dictionary(General.Map.Map.Sectors.Count); + foreach (Sector s in General.Map.Map.Sectors) + { + // Setup labels + TextLabel[] labelarray = new TextLabel[s.Labels.Count]; + for (int i = 0; i < s.Labels.Count; i++) + { + Vector2D v = s.Labels[i].position; + labelarray[i] = new TextLabel(20); + labelarray[i].TransformCoords = true; + labelarray[i].Rectangle = new RectangleF(v.x, v.y, 0.0f, 0.0f); + labelarray[i].AlignX = TextAlignmentX.Center; + labelarray[i].AlignY = TextAlignmentY.Middle; + labelarray[i].Scale = 14f; + labelarray[i].Color = General.Colors.Highlight.WithAlpha(255); + labelarray[i].Backcolor = General.Colors.Background.WithAlpha(255); + } + labels.Add(s, labelarray); + } + } + */ + + private void SetupLabels() + { + labels = new List(); + PixelColor white = new PixelColor(255, 255, 255, 255); + + foreach (SlopeVertexGroup svg in BuilderPlug.Me.SlopeVertexGroups) + { + for (int i = 0; i < svg.Vertices.Count; i++) + { + if (BuilderPlug.Me.SlopeVertexLabelDisplayOption == LabelDisplayOption.Always || General.Interface.AltState == true) + { + SlopeVertex sv = svg.Vertices[i]; + float scale = 1 / renderer.Scale; + float x = sv.Pos.x; + float y = sv.Pos.y - 14 * scale; + string value = String.Format("Z: {0}", sv.Z); + bool showlabel = true; + + // Rearrange labels if they'd be (exactly) on each other + foreach (TextLabel l in labels) + { + if (l.Location.x == x && l.Location.y == y) { + // Reduce visual clutter by de-duping stacked labels, when "show all labels" is enabled + if (l.Text == value) { + showlabel = false; //dedupe + } else { + // Adjust the label position down one line + y -= l.TextSize.Height * scale; + } + } + } + + // Only proceed if the label was not deduped + if (showlabel) + { + TextLabel label = new TextLabel(); + label.TransformCoords = true; + label.Location = new Vector2D(x, y); + label.AlignX = TextAlignmentX.Center; + label.AlignY = TextAlignmentY.Middle; + label.BackColor = General.Colors.Background.WithAlpha(128); + label.Text = value; + label.Color = white; + + labels.Add(label); + } + } + } + } + } + + // This updates the dragging + private void Update() + { + PixelColor stitchcolor = General.Colors.Highlight; + PixelColor losecolor = General.Colors.Selection; + PixelColor color; + + snaptogrid = General.Interface.ShiftState ^ General.Interface.SnapToGrid; + snaptonearest = General.Interface.CtrlState ^ General.Interface.AutoMerge; + + DrawnVertex lastp = new DrawnVertex(); + DrawnVertex curp = GetCurrentPosition(); + float vsize = ((float)renderer.VertexSize + 1.0f) / renderer.Scale; + float vsizeborder = ((float)renderer.VertexSize + 3.0f) / renderer.Scale; + + SetupLabels(); + + // Render drawing lines + if (renderer.StartOverlay(true)) + { + float size = 9 / renderer.Scale; + + if (BuilderPlug.Me.UseHighlight) + { + renderer.RenderHighlight(overlayGeometry, General.Colors.Selection.WithAlpha(64).ToInt()); + } + + List vertices = new List(); + + // Store all slope vertices and draw the lines between them + foreach (SlopeVertexGroup svg in BuilderPlug.Me.SlopeVertexGroups) + { + for (int i = 0; i < svg.Vertices.Count; i++) + { + vertices.Add(svg.Vertices[i]); + + if (i < svg.Vertices.Count - 1) + renderer.RenderLine(svg.Vertices[0].Pos, svg.Vertices[i + 1].Pos, 1, new PixelColor(255, 255, 255, 255), true); + } + } + + // Sort the slope vertex list and draw them. The sorting ensures that selected vertices are always drawn on top + foreach (SlopeVertex sv in vertices.OrderBy(o => o.Selected)) + { + PixelColor c = General.Colors.Indication; + Vector3D v = sv.Pos; + + renderer.RenderRectangleFilled(new RectangleF(v.x - size / 2, v.y - size / 2, size, size), General.Colors.Background, true); + renderer.RenderRectangle(new RectangleF(v.x - size / 2, v.y - size / 2, size, size), 2, c, true); + } + + + // Go for all points to draw lines + if (points.Count > 0) + { + // Render lines + lastp = points[0]; + for (int i = 1; i < points.Count; i++) + { + // Determine line color + if (lastp.stitchline && points[i].stitchline) color = stitchcolor; + else color = losecolor; + + // Render line + renderer.RenderLine(points[0].pos, points[i].pos, LINE_THICKNESS, color, true); + lastp = points[i]; + } + + // Determine line color + if (lastp.stitchline && snaptonearest) color = stitchcolor; + else color = losecolor; + + // Render line to cursor + renderer.RenderLine(points[0].pos, curp.pos, LINE_THICKNESS, color, true); + + // Render vertices + for (int i = 0; i < points.Count; i++) + { + // Determine vertex color + if (points[i].stitch) color = stitchcolor; + else color = losecolor; + + // Render vertex + //renderer.RenderRectangleFilled(new RectangleF(points[i].pos.x - vsize, points[i].pos.y - vsize, vsize * 2.0f, vsize * 2.0f), color, true); + renderer.RenderRectangleFilled(new RectangleF(points[i].pos.x - size / 2, points[i].pos.y - size / 2, size, size), General.Colors.Background, true); + renderer.RenderRectangle(new RectangleF(points[i].pos.x - size / 2, points[i].pos.y - size / 2, size, size), 2, General.Colors.Indication, true); + } + } + + foreach (TextLabel l in labels) + renderer.RenderText(l); + + // Determine point color + if (snaptonearest) color = stitchcolor; + else color = losecolor; + + // Render vertex at cursor + //renderer.RenderRectangleFilled(new RectangleF(curp.pos.x - vsize, curp.pos.y - vsize, vsize * 2.0f, vsize * 2.0f), color, true); + + renderer.RenderRectangleFilled(new RectangleF(curp.pos.x - size / 2, curp.pos.y - size / 2, size, size), General.Colors.Background, true); + renderer.RenderRectangle(new RectangleF(curp.pos.x - size / 2, curp.pos.y - size / 2, size, size), 2, General.Colors.Indication, true); + + // Done + renderer.Finish(); + } + + // Done + renderer.Present(); + } + + private void updateOverlaySurfaces() + { + ICollection orderedselection = General.Map.Map.GetSelectedSectors(true); + List vertsList = new List(); + + // Go for all selected sectors + foreach (Sector s in orderedselection) vertsList.AddRange(s.FlatVertices); + overlayGeometry = vertsList.ToArray(); + } + + // This returns the aligned and snapped draw position + public static DrawnVertex GetCurrentPosition(Vector2D mousemappos, bool snaptonearest, bool snaptogrid, IRenderer2D renderer, List points) + { + DrawnVertex p = new DrawnVertex(); + Vector2D vm = mousemappos; + float vrange = BuilderPlug.Me.StitchRange / renderer.Scale; + + // Snap to nearest? + if (snaptonearest) + { + // Go for all drawn points + foreach (DrawnVertex v in points) + { + if (Vector2D.DistanceSq(mousemappos, v.pos) < (vrange * vrange)) + { + p.pos = v.pos; + p.stitch = true; + p.stitchline = true; + return p; + } + } + + // Try the nearest vertex + Vertex nv = General.Map.Map.NearestVertexSquareRange(mousemappos, vrange); + if (nv != null) + { + p.pos = nv.Position; + p.stitch = true; + p.stitchline = true; + return p; + } + + // Try the nearest linedef + Linedef nl = General.Map.Map.NearestLinedefRange(mousemappos, BuilderPlug.Me.StitchRange / renderer.Scale); + if (nl != null) + { + // Snap to grid? + if (snaptogrid) + { + // Get grid intersection coordinates + List coords = nl.GetGridIntersections(); + + // Find nearest grid intersection + bool found = false; + float found_distance = float.MaxValue; + Vector2D found_coord = new Vector2D(); + foreach (Vector2D v in coords) + { + Vector2D delta = mousemappos - v; + if (delta.GetLengthSq() < found_distance) + { + found_distance = delta.GetLengthSq(); + found_coord = v; + found = true; + } + } + + if (found) + { + // Align to the closest grid intersection + p.pos = found_coord; + p.stitch = true; + p.stitchline = true; + return p; + } + } + else + { + // Aligned to line + p.pos = nl.NearestOnLine(mousemappos); + p.stitch = true; + p.stitchline = true; + return p; + } + } + } + else + { + // Always snap to the first drawn vertex so that the user can finish a complete sector without stitching + if (points.Count > 0) + { + if (Vector2D.DistanceSq(mousemappos, points[0].pos) < (vrange * vrange)) + { + p.pos = points[0].pos; + p.stitch = true; + p.stitchline = false; + return p; + } + } + } + + // if the mouse cursor is outside the map bondaries check if the line between the last set point and the + // mouse cursor intersect any of the boundary lines. If it does, set the position to this intersection + if (points.Count > 0 && + (mousemappos.x < General.Map.Config.LeftBoundary || mousemappos.x > General.Map.Config.RightBoundary || + mousemappos.y > General.Map.Config.TopBoundary || mousemappos.y < General.Map.Config.BottomBoundary)) + { + Line2D dline = new Line2D(mousemappos, points[points.Count - 1].pos); + bool foundintersection = false; + float u = 0.0f; + List blines = new List(); + + // lines for left, top, right and bottom bondaries + blines.Add(new Line2D(General.Map.Config.LeftBoundary, General.Map.Config.BottomBoundary, General.Map.Config.LeftBoundary, General.Map.Config.TopBoundary)); + blines.Add(new Line2D(General.Map.Config.LeftBoundary, General.Map.Config.TopBoundary, General.Map.Config.RightBoundary, General.Map.Config.TopBoundary)); + blines.Add(new Line2D(General.Map.Config.RightBoundary, General.Map.Config.TopBoundary, General.Map.Config.RightBoundary, General.Map.Config.BottomBoundary)); + blines.Add(new Line2D(General.Map.Config.RightBoundary, General.Map.Config.BottomBoundary, General.Map.Config.LeftBoundary, General.Map.Config.BottomBoundary)); + + // check for intersections with boundaries + for (int i = 0; i < blines.Count; i++) + { + if (!foundintersection) + { + // only check for intersection if the last set point is not on the + // line we are checking against + if (blines[i].GetSideOfLine(points[points.Count - 1].pos) != 0.0f) + { + foundintersection = blines[i].GetIntersection(dline, out u); + } + } + } + + // if there was no intersection set the position to the last set point + if (!foundintersection) + vm = points[points.Count - 1].pos; + else + vm = dline.GetCoordinatesAt(u); + + } + + + // Snap to grid? + if (snaptogrid) + { + // Aligned to grid + p.pos = General.Map.Grid.SnappedToGrid(vm); + + // special handling + if (p.pos.x > General.Map.Config.RightBoundary) p.pos.x = General.Map.Config.RightBoundary; + if (p.pos.y < General.Map.Config.BottomBoundary) p.pos.y = General.Map.Config.BottomBoundary; + p.stitch = snaptonearest; + p.stitchline = snaptonearest; + return p; + } + else + { + // Normal position + p.pos = vm; + p.stitch = snaptonearest; + p.stitchline = snaptonearest; + return p; + } + } + + // This gets the aligned and snapped draw position + private DrawnVertex GetCurrentPosition() + { + return GetCurrentPosition(mousemappos, snaptonearest, snaptogrid, renderer, points); + } + + // This draws a point at a specific location + public bool DrawPointAt(DrawnVertex p) + { + return DrawPointAt(p.pos, p.stitch, p.stitchline); + } + + // This draws a point at a specific location + public bool DrawPointAt(Vector2D pos, bool stitch, bool stitchline) + { + if (pos.x < General.Map.Config.LeftBoundary || pos.x > General.Map.Config.RightBoundary || + pos.y > General.Map.Config.TopBoundary || pos.y < General.Map.Config.BottomBoundary) + return false; + + DrawnVertex newpoint = new DrawnVertex(); + newpoint.pos = pos; + newpoint.stitch = stitch; + newpoint.stitchline = stitchline; + points.Add(newpoint); + updateOverlaySurfaces(); + Update(); + + if (points.Count == 3) + FinishDraw(); + + return true; + } + + private bool IsControlSector(Sector s) + { + //Determine whether or not the sector is actually a control sector for a 3D floor + foreach (Sidedef sd in s.Sidedefs) + { + if (sd.Line.Action == 160) + return true; + } + return false; + } + + #endregion + + #region ================== Events + + public override void OnHelp() + { + General.ShowHelp("e_drawgeometry.html"); + } + + // Engaging + public override void OnEngage() + { + base.OnEngage(); + + if (BuilderPlug.Me.SlopeDataSector == null || BuilderPlug.Me.SlopeDataSector.IsDisposed) + { + General.Map.UndoRedo.CreateUndo("Set up slope data sector"); + + SlopeDataSectorDialog sdsd = new SlopeDataSectorDialog(); + DialogResult dr = sdsd.ShowDialog(); + + if (dr == DialogResult.Cancel) + { + General.Map.UndoRedo.WithdrawUndo(); + General.Editing.CancelMode(); + return; + } + + if (dr == DialogResult.OK) + { + BuilderPlug.Me.SlopeDataSector = General.Map.Map.GetMarkedSectors(true)[0]; + BuilderPlug.Me.StoreSlopeVertexGroupsInSector(); + } + } + else + { + BuilderPlug.Me.LoadSlopeVertexGroupsFromSector(); + } + + EnableAutoPanning(); + renderer.SetPresentation(Presentation.Standard); + + // Convert geometry selection to sectors only + General.Map.Map.ConvertSelection(SelectionType.Sectors); + + General.Interface.AddButton(BuilderPlug.Me.MenusForm.FloorSlope); + General.Interface.AddButton(BuilderPlug.Me.MenusForm.CeilingSlope); + General.Interface.AddButton(BuilderPlug.Me.MenusForm.FloorAndCeilingSlope); + + BuilderPlug.Me.MenusForm.FloorSlope.Checked = false; + BuilderPlug.Me.MenusForm.CeilingSlope.Checked = false; + BuilderPlug.Me.MenusForm.FloorAndCeilingSlope.Checked = false; + + if (slopedrawingmode == SlopeDrawingMode.Floor) + BuilderPlug.Me.MenusForm.FloorSlope.Checked = true; + else if (slopedrawingmode == SlopeDrawingMode.Ceiling) + BuilderPlug.Me.MenusForm.CeilingSlope.Checked = true; + else + BuilderPlug.Me.MenusForm.FloorAndCeilingSlope.Checked = true; + + // Make text labels for sectors + SetupLabels(); + updateOverlaySurfaces(); + Update(); + + // Set cursor + General.Interface.SetCursor(Cursors.Cross); + } + + // Disengaging + public override void OnDisengage() + { + base.OnDisengage(); + + General.Interface.RemoveButton(BuilderPlug.Me.MenusForm.FloorSlope); + General.Interface.RemoveButton(BuilderPlug.Me.MenusForm.CeilingSlope); + General.Interface.RemoveButton(BuilderPlug.Me.MenusForm.FloorAndCeilingSlope); + + DisableAutoPanning(); + } + + // Cancelled + public override void OnCancel() + { + // Cancel base class + base.OnCancel(); + + // Return to previous stable mode + General.Editing.ChangeMode(General.Editing.PreviousStableMode.Name); + } + + // Accepted + public override void OnAccept() + { + Cursor.Current = Cursors.AppStarting; + + General.Settings.FindDefaultDrawSettings(); + + // When points have been drawn + if (points.Count > 1) + { + // Make undo for the draw + General.Map.UndoRedo.CreateUndo("Draw slope"); + + List sv_floor = new List(); + List sv_ceiling = new List(); + + // Fills the slope vertex list for both floor and ceiling slopes. Alos tried + // to determine the default z position of the vertex + List selected = (List)General.Map.Map.GetSelectedSectors(true); + if (selected.Count == 1 && IsControlSector(selected[0])) + { + //If a 3D floor control sector is selected, then just use the height of it directly + float zf = selected[0].FloorHeight; + float zc = selected[0].CeilHeight; + for (int i = 0; i < points.Count; i++) + { + sv_floor.Add(new SlopeVertex(points[i].pos, zf)); + sv_ceiling.Add(new SlopeVertex(points[i].pos, zc)); + } + } else { + //For normal sectors, grab the height of the sector each control handle lies within + for (int i = 0; i < points.Count; i++) + { + float zf = 0; + float zc = 0; + Sector s = General.Map.Map.GetSectorByCoordinates(points[i].pos); + + if (s != null) + { + foreach (Sidedef sd in s.Sidedefs) + { + if (sd.Line.Line.GetSideOfLine(points[i].pos) == 0) + { + if (sd.Line.Back != null && !selected.Contains(sd.Line.Back.Sector)) + { + zf = sd.Line.Back.Sector.FloorHeight; + zc = sd.Line.Back.Sector.CeilHeight; + } + else + { + zf = sd.Line.Front.Sector.FloorHeight; + zc = sd.Line.Front.Sector.CeilHeight; + } + } + } + } + + sv_floor.Add(new SlopeVertex(points[i].pos, zf)); + sv_ceiling.Add(new SlopeVertex(points[i].pos, zc)); + } + } + + // Create the floor slope vertex group and add it to all selected sectors + if (slopedrawingmode == SlopeDrawingMode.Floor || slopedrawingmode == SlopeDrawingMode.FloorAndCeiling) + { + int id = -1; + SlopeVertexGroup svg = BuilderPlug.Me.AddSlopeVertexGroup(sv_floor, out id); + + svg.Sectors.Clear(); + + foreach (Sector s in selected) + { + // Make sure the field work with undo/redo + s.Fields.BeforeFieldsChange(); + + if (s.Fields.ContainsKey("user_floorplane_id")) + s.Fields.Remove("user_floorplane_id"); + + s.Fields.Add("user_floorplane_id", new UniValue(UniversalType.Integer, id)); + + // svg.Sectors.Add(s); + + svg.AddSector(s, PlaneType.Floor); + } + } + + // Create the ceiling slope vertex group and add it to all selected sectors + if (slopedrawingmode == SlopeDrawingMode.Ceiling || slopedrawingmode == SlopeDrawingMode.FloorAndCeiling) + { + int id = -1; + SlopeVertexGroup svg = BuilderPlug.Me.AddSlopeVertexGroup(sv_ceiling, out id); + + svg.Sectors.Clear(); + + foreach (Sector s in selected) + { + // Make sure the field work with undo/redo + s.Fields.BeforeFieldsChange(); + + if (s.Fields.ContainsKey("user_ceilingplane_id")) + s.Fields.Remove("user_ceilingplane_id"); + + s.Fields.Add("user_ceilingplane_id", new UniValue(UniversalType.Integer, id)); + + // svg.Sectors.Add(s); + svg.AddSector(s, PlaneType.Ceiling); + } + } + + BuilderPlug.Me.StoreSlopeVertexGroupsInSector(); + + // BuilderPlug.Me.UpdateSlopes(); + + // Clear selection + General.Map.Map.ClearAllSelected(); + + // Update cached values + General.Map.Map.Update(); + + // Map is changed + General.Map.IsChanged = true; + } + + // Done + Cursor.Current = Cursors.Default; + + // Return to original mode + General.Editing.ChangeMode(General.Editing.PreviousStableMode.Name); + } + + // This redraws the display + public override void OnRedrawDisplay() + { + renderer.RedrawSurface(); + + // Render lines + if (renderer.StartPlotter(true)) + { + renderer.PlotLinedefSet(General.Map.Map.Linedefs); + renderer.PlotVerticesSet(General.Map.Map.Vertices); + renderer.Finish(); + } + + // Render things + if (renderer.StartThings(true)) + { + renderer.RenderThingSet(General.Map.Map.Things, 1.0f); + renderer.Finish(); + } + + // Normal update + updateOverlaySurfaces(); + Update(); + } + + // Mouse moving + public override void OnMouseMove(MouseEventArgs e) + { + base.OnMouseMove(e); + updateOverlaySurfaces(); + Update(); + } + + // When a key is released + public override void OnKeyUp(KeyEventArgs e) + { + base.OnKeyUp(e); + if ((snaptogrid != (General.Interface.ShiftState ^ General.Interface.SnapToGrid)) || + (snaptonearest != (General.Interface.CtrlState ^ General.Interface.AutoMerge))) Update(); + } + + // When a key is pressed + public override void OnKeyDown(KeyEventArgs e) + { + base.OnKeyDown(e); + if ((snaptogrid != (General.Interface.ShiftState ^ General.Interface.SnapToGrid)) || + (snaptonearest != (General.Interface.CtrlState ^ General.Interface.AutoMerge))) Update(); + } + + #endregion + + #region ================== Actions + + [BeginAction("drawfloorslope")] + public void DrawFloorSlope() + { + slopedrawingmode = SlopeDrawingMode.Floor; + + BuilderPlug.Me.MenusForm.CeilingSlope.Checked = false; + BuilderPlug.Me.MenusForm.FloorSlope.Checked = true; + BuilderPlug.Me.MenusForm.FloorAndCeilingSlope.Checked = false; + + General.Interface.DisplayStatus(StatusType.Info, "Applying drawn slope to floor"); + } + + [BeginAction("drawceilingslope")] + public void DrawCeilingSlope() + { + slopedrawingmode = SlopeDrawingMode.Ceiling; + + BuilderPlug.Me.MenusForm.CeilingSlope.Checked = true; + BuilderPlug.Me.MenusForm.FloorSlope.Checked = false; + BuilderPlug.Me.MenusForm.FloorAndCeilingSlope.Checked = false; + + General.Interface.DisplayStatus(StatusType.Info, "Applying drawn slope to ceiling"); + } + + [BeginAction("drawfloorandceilingslope")] + public void DrawFloorAndCeilingSlope() + { + slopedrawingmode = SlopeDrawingMode.FloorAndCeiling; + + BuilderPlug.Me.MenusForm.CeilingSlope.Checked = false; + BuilderPlug.Me.MenusForm.FloorSlope.Checked = false; + BuilderPlug.Me.MenusForm.FloorAndCeilingSlope.Checked = true; + + General.Interface.DisplayStatus(StatusType.Info, "Applying drawn slope to floor and ceiling"); + } + + // Drawing a point + [BeginAction("drawslopepoint")] + public void DrawPoint() + { + // Mouse inside window? + if (General.Interface.MouseInDisplay) + { + DrawnVertex newpoint = GetCurrentPosition(); + + if (!DrawPointAt(newpoint)) General.Interface.DisplayStatus(StatusType.Warning, "Failed to draw point: outside of map boundaries."); + } + } + + // Remove a point + //[BeginAction("removepoint")] + public void RemovePoint() + { + if (points.Count > 0) points.RemoveAt(points.Count - 1); + + updateOverlaySurfaces(); + Update(); + } + + // Finish drawing + [BeginAction("finishslopedraw")] + public void FinishDraw() + { + // Accept the changes + General.Editing.AcceptMode(); + } + + #endregion + } +} diff --git a/Source/Plugins/3DFloorMode/Interface/PreferencesForm.Designer.cs b/Source/Plugins/3DFloorMode/Interface/PreferencesForm.Designer.cs new file mode 100644 index 00000000..d425c21c --- /dev/null +++ b/Source/Plugins/3DFloorMode/Interface/PreferencesForm.Designer.cs @@ -0,0 +1,163 @@ +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + partial class PreferencesForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.tabs = new System.Windows.Forms.TabControl(); + this.tabPage1 = new System.Windows.Forms.TabPage(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.label1 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.sectorlabels = new System.Windows.Forms.ComboBox(); + this.slopevertexlabels = new System.Windows.Forms.ComboBox(); + this.label3 = new System.Windows.Forms.Label(); + this.tabs.SuspendLayout(); + this.tabPage1.SuspendLayout(); + this.groupBox1.SuspendLayout(); + this.SuspendLayout(); + // + // tabs + // + this.tabs.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.tabs.Controls.Add(this.tabPage1); + this.tabs.Location = new System.Drawing.Point(12, 12); + this.tabs.Name = "tabs"; + this.tabs.SelectedIndex = 0; + this.tabs.Size = new System.Drawing.Size(677, 454); + this.tabs.TabIndex = 0; + // + // tabPage1 + // + this.tabPage1.Controls.Add(this.groupBox1); + this.tabPage1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.tabPage1.Location = new System.Drawing.Point(4, 22); + this.tabPage1.Name = "tabPage1"; + this.tabPage1.Padding = new System.Windows.Forms.Padding(3); + this.tabPage1.Size = new System.Drawing.Size(669, 428); + this.tabPage1.TabIndex = 0; + this.tabPage1.Text = "3D Floor Plugin"; + this.tabPage1.UseVisualStyleBackColor = true; + // + // groupBox1 + // + this.groupBox1.Controls.Add(this.label3); + this.groupBox1.Controls.Add(this.slopevertexlabels); + this.groupBox1.Controls.Add(this.sectorlabels); + this.groupBox1.Controls.Add(this.label2); + this.groupBox1.Controls.Add(this.label1); + this.groupBox1.Location = new System.Drawing.Point(6, 6); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(305, 94); + this.groupBox1.TabIndex = 0; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "Slope Mode"; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(34, 22); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(99, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Show sector labels:"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(6, 49); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(127, 13); + this.label2.TabIndex = 1; + this.label2.Text = "Show slope vertex labels:"; + // + // sectorlabels + // + this.sectorlabels.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.sectorlabels.FormattingEnabled = true; + this.sectorlabels.Items.AddRange(new object[] { + "Always", + "Never", + "On slope vertex highlight"}); + this.sectorlabels.Location = new System.Drawing.Point(139, 19); + this.sectorlabels.Name = "sectorlabels"; + this.sectorlabels.Size = new System.Drawing.Size(155, 21); + this.sectorlabels.TabIndex = 2; + // + // slopevertexlabels + // + this.slopevertexlabels.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.slopevertexlabels.FormattingEnabled = true; + this.slopevertexlabels.Items.AddRange(new object[] { + "Always", + "Never", + "On slope vertex highlight"}); + this.slopevertexlabels.Location = new System.Drawing.Point(139, 46); + this.slopevertexlabels.Name = "slopevertexlabels"; + this.slopevertexlabels.Size = new System.Drawing.Size(155, 21); + this.slopevertexlabels.TabIndex = 3; + // + // label3 + // + this.label3.Dock = System.Windows.Forms.DockStyle.Bottom; + this.label3.Location = new System.Drawing.Point(3, 68); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(299, 23); + this.label3.TabIndex = 4; + this.label3.Text = "Holding the Alt key will always show the labels"; + this.label3.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // PreferencesForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(701, 478); + this.Controls.Add(this.tabs); + this.Name = "PreferencesForm"; + this.Text = "PreferencesForm"; + this.tabs.ResumeLayout(false); + this.tabPage1.ResumeLayout(false); + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.TabControl tabs; + private System.Windows.Forms.TabPage tabPage1; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.ComboBox slopevertexlabels; + private System.Windows.Forms.ComboBox sectorlabels; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label label3; + } +} \ No newline at end of file diff --git a/Source/Plugins/3DFloorMode/Interface/PreferencesForm.cs b/Source/Plugins/3DFloorMode/Interface/PreferencesForm.cs new file mode 100644 index 00000000..28843c84 --- /dev/null +++ b/Source/Plugins/3DFloorMode/Interface/PreferencesForm.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using CodeImp.DoomBuilder.Windows; + +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + public partial class PreferencesForm : DelayedForm + { + public PreferencesForm() + { + InitializeComponent(); + + sectorlabels.SelectedIndex = (int)BuilderPlug.Me.SectorLabelDisplayOption; + slopevertexlabels.SelectedIndex = (int)BuilderPlug.Me.SlopeVertexLabelDisplayOption; + } + + #region ================== Methods + + // When OK is pressed on the preferences dialog + public void OnAccept(PreferencesController controller) + { + // Write preferred settings + General.Settings.WritePluginSetting("sectorlabeldisplayoption", sectorlabels.SelectedIndex); + General.Settings.WritePluginSetting("slopevertexlabeldisplayoption", slopevertexlabels.SelectedIndex); + } + + // This sets up the form with the preferences controller + public void Setup(PreferencesController controller) + { + // Add tab pages + foreach (TabPage p in tabs.TabPages) + { + controller.AddTab(p); + } + + // Bind events + controller.OnAccept += OnAccept; + } + + #endregion + } +} diff --git a/Source/Plugins/3DFloorMode/Interface/PreferencesForm.resx b/Source/Plugins/3DFloorMode/Interface/PreferencesForm.resx new file mode 100644 index 00000000..7080a7d1 --- /dev/null +++ b/Source/Plugins/3DFloorMode/Interface/PreferencesForm.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Source/Plugins/3DFloorMode/Interface/ThreeDFloorPanel.Designer.cs b/Source/Plugins/3DFloorMode/Interface/ThreeDFloorPanel.Designer.cs new file mode 100644 index 00000000..e98d1482 --- /dev/null +++ b/Source/Plugins/3DFloorMode/Interface/ThreeDFloorPanel.Designer.cs @@ -0,0 +1,63 @@ +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + partial class ThreeDFloorPanel + { + /// + /// Erforderliche Designervariable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Verwendete Ressourcen bereinigen. + /// + /// True, wenn verwaltete Ressourcen gelöscht werden sollen; andernfalls False. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Vom Komponenten-Designer generierter Code + + /// + /// Erforderliche Methode für die Designerunterstützung. + /// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden. + /// + private void InitializeComponent() + { + this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel(); + this.SuspendLayout(); + // + // flowLayoutPanel1 + // + this.flowLayoutPanel1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.flowLayoutPanel1.BackColor = System.Drawing.SystemColors.ControlLightLight; + this.flowLayoutPanel1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.flowLayoutPanel1.FlowDirection = System.Windows.Forms.FlowDirection.TopDown; + this.flowLayoutPanel1.Location = new System.Drawing.Point(4, 4); + this.flowLayoutPanel1.Name = "flowLayoutPanel1"; + this.flowLayoutPanel1.Size = new System.Drawing.Size(242, 593); + this.flowLayoutPanel1.TabIndex = 0; + // + // ThreeDFloorPanel + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.flowLayoutPanel1); + this.Name = "ThreeDFloorPanel"; + this.Size = new System.Drawing.Size(249, 600); + this.ResumeLayout(false); + + } + + #endregion + + public System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1; + + } +} diff --git a/Source/Plugins/3DFloorMode/Interface/ThreeDFloorPanel.cs b/Source/Plugins/3DFloorMode/Interface/ThreeDFloorPanel.cs new file mode 100644 index 00000000..a2d47692 --- /dev/null +++ b/Source/Plugins/3DFloorMode/Interface/ThreeDFloorPanel.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Data; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using CodeImp.DoomBuilder.Windows; +using CodeImp.DoomBuilder.IO; +using CodeImp.DoomBuilder.Map; +using CodeImp.DoomBuilder.Rendering; +using CodeImp.DoomBuilder.Geometry; +using CodeImp.DoomBuilder.Editing; +using CodeImp.DoomBuilder.Plugins; +using CodeImp.DoomBuilder.Actions; +using CodeImp.DoomBuilder.Types; +using CodeImp.DoomBuilder.Config; +using CodeImp.DoomBuilder.Data; + +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + public partial class ThreeDFloorPanel : UserControl + { + public ThreeDFloorPanel() + { + InitializeComponent(); + } + } +} diff --git a/Source/Plugins/3DFloorMode/Interface/ThreeDFloorPanel.resx b/Source/Plugins/3DFloorMode/Interface/ThreeDFloorPanel.resx new file mode 100644 index 00000000..19dc0dd8 --- /dev/null +++ b/Source/Plugins/3DFloorMode/Interface/ThreeDFloorPanel.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Source/Plugins/3DFloorMode/MergePoint.cs b/Source/Plugins/3DFloorMode/MergePoint.cs new file mode 100644 index 00000000..462a097e --- /dev/null +++ b/Source/Plugins/3DFloorMode/MergePoint.cs @@ -0,0 +1,79 @@ +#region ================== Copyright (c) 2014 Boris Iwanski + +/* + * Copyright (c) 2014 Boris Iwanski + * This program is released under GNU General Public License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#endregion + +using System.Collections.Generic; +using CodeImp.DoomBuilder.Geometry; +using CodeImp.DoomBuilder.Map; + +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + public class MergePoint + { + private Vector2D position; + private int floorheight; + private int ceilingheight; + private string floortexture; + private string ceilingtexture; + private List threedfloors; + + public Vector2D Position { get { return position; } set { position = value; } } + public int FloorHeight { get { return floorheight; } set { floorheight = value; } } + public int CeilingHeight { get { return ceilingheight; } set { ceilingheight = value; } } + public string FloorTexture { get { return floortexture; } set { floortexture = value; } } + public string CeilingTexture { get { return ceilingtexture; } set { ceilingtexture = value; } } + public List ThreeDFloors { get { return threedfloors; } } + + public MergePoint(Vector2D position) + { + this.position = position; + threedfloors = new List(); + } + + public void Update() + { + List sectors = new List(); + + foreach (Sector s in General.Map.Map.Sectors) + { + if (s.Intersect(position)) + sectors.Add(s); + } + + if (sectors.Count == 0) + return; + + floorheight = sectors[0].FloorHeight; + ceilingheight = sectors[0].CeilHeight; + + floortexture = sectors[0].FloorTexture; + ceilingtexture = sectors[0].CeilTexture; + + foreach (Sector s in sectors) + { + if (s.FloorHeight < floorheight) + { + floorheight = s.FloorHeight; + floortexture = s.FloorTexture; + } + + if (s.CeilHeight > ceilingheight) + { + ceilingheight = s.CeilHeight; + ceilingtexture = s.CeilTexture; + } + } + } + } +} \ No newline at end of file diff --git a/Source/Plugins/3DFloorMode/Properties/AssemblyInfo.cs b/Source/Plugins/3DFloorMode/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..d0a90d4f --- /dev/null +++ b/Source/Plugins/3DFloorMode/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// Allgemeine Informationen über eine Assembly werden über die folgenden +// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, +// die mit einer Assembly verknüpft sind. +[assembly: AssemblyTitle("ThreeDFloorMode")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("ThreeDFloorMode")] +[assembly: AssemblyCopyright("Copyright © 2013")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar +// für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von +// COM zugreifen müssen, legen Sie das ComVisible-Attribut für diesen Typ auf "true" fest. +[assembly: ComVisible(false)] + +// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird +[assembly: Guid("626ea88b-7e0f-4486-acca-32027c4133de")] + +// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: +// +// Hauptversion +// Nebenversion +// Buildnummer +// Revision +// +// Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern +// übernehmen, indem Sie "*" eingeben: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("0.1.0.0")] diff --git a/Source/Plugins/3DFloorMode/Properties/Resources.Designer.cs b/Source/Plugins/3DFloorMode/Properties/Resources.Designer.cs new file mode 100644 index 00000000..8baf4b91 --- /dev/null +++ b/Source/Plugins/3DFloorMode/Properties/Resources.Designer.cs @@ -0,0 +1,93 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace ThreeDFloorMode.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ThreeDFloorMode.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap Ceiling { + get { + object obj = ResourceManager.GetObject("Ceiling", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap Floor { + get { + object obj = ResourceManager.GetObject("Floor", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap FloorAndCeiling { + get { + object obj = ResourceManager.GetObject("FloorAndCeiling", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/Source/Plugins/3DFloorMode/Properties/Resources.resx b/Source/Plugins/3DFloorMode/Properties/Resources.resx new file mode 100644 index 00000000..c8365524 --- /dev/null +++ b/Source/Plugins/3DFloorMode/Properties/Resources.resx @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\Ceiling.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Floor.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\FloorAndCeiling.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/Source/Plugins/3DFloorMode/Resources/Actions.cfg b/Source/Plugins/3DFloorMode/Resources/Actions.cfg new file mode 100644 index 00000000..e5a23f6c --- /dev/null +++ b/Source/Plugins/3DFloorMode/Resources/Actions.cfg @@ -0,0 +1,156 @@ +// +// This file defines which actions there are, what description they have and +// some behaviour options. The Doom Builder core will bind to these actions +// with delegates (function pointers) where you use the BeginAction and +// EndAction attributes. This file must be named Actions.cfg and must be +// included in the plugin project as "Embedded Resource". +// + +// +// Options: +// +// allowkeys: Allows the user to bind standard keys to this action. +// allowmouse: Allows the user to bind mouse buttons to this action. +// allowscroll: Allows the user to bind the scrollwheel to this action. +// disregardshift: This action will trigger regardless if Shift or Control is used. +// repeat: BeginAction will be called for automatic key repetition. +// default: Default key is only used when the action is loaded for the first +// time and the default key is not used by any other action. +// +// allowkeys and allowmouse are true by default, the others are false by default. +// + +categories +{ + threedfloorplugin = "3D Floor Plugin"; +} + +threedfloorhelpermode +{ + title = "3D floor editing mode"; + category = "threedfloorplugin"; + description = "Edits 3D floors"; + allowkeys = true; + allowmouse = true; + allowscroll = true; +} + +threedslopemode +{ + title = "Slope mode"; + category = "threedfloorplugin"; + description = "Edits slope vertex groups"; + allowkeys = true; + allowmouse = true; + allowscroll = true; +} + +drawslopesmode +{ + title = "Draw slope mode"; + category = "threedfloorplugin"; + description = "Draws a slope vertex group"; + allowkeys = true; + allowmouse = true; + allowscroll = true; +} + +drawslopepoint +{ + title = "Draw slope vertex"; + category = "threedfloorplugin"; + description = "Draws a slope vertex at the mousecursor position."; + allowkeys = true; + allowmouse = true; + allowscroll = true; + disregardshift = true; + disregardcontrol = true; +} + +drawfloorslope +{ + title = "Draw Floor Slope"; + category = "threedfloorplugin"; + description = "The drawn slope will be applied to the floor"; + allowkeys = true; + allowmouse = true; + allowscroll = true; +} + +drawceilingslope +{ + title = "Draw Ceiling Slope"; + category = "threedfloorplugin"; + description = "The drawn slope will be applied to the ceiling"; + allowkeys = true; + allowmouse = true; + allowscroll = true; +} + +drawfloorandceilingslope +{ + title = "Draw Floor and Ceiling Slope"; + category = "threedfloorplugin"; + description = "The drawn slope will be applied to the floor and ceiling"; + allowkeys = true; + allowmouse = true; + allowscroll = true; +} + +finishslopedraw +{ + title = "Finish Slope Drawing"; + category = "threedfloorplugin"; + description = "Finishes the slope drawing."; + allowkeys = true; + allowmouse = true; + allowscroll = true; +} + +threedflipslope +{ + title = "Flip 3D slope"; + category = "threedfloorplugin"; +} + +cyclehighlighted3dfloorup +{ + title = "Cycle highlighted 3D floor up"; + category = "threedfloorplugin"; + description = "Cycles up through the 3D floors of the currently highlighted sector"; + allowkeys = true; + allowmouse = true; + allowscroll = true; + default = 131066; +} + +cyclehighlighted3dfloordown +{ + title = "Cycle highlighted 3D floor down"; + category = "threedfloorplugin"; + description = "Cycles down through the 3D floors of the currently highlighted sector"; + allowkeys = true; + allowmouse = true; + allowscroll = true; + default = 131067; +} + +relocate3dfloorcontrolsectors +{ + title = "Relocate 3D floor control sectors"; + category = "threedfloorplugin"; + description = "Relocates the managed 3D floor control sectors to the current position of the control sector area"; + allowkeys = true; + allowmouse = true; + allowscroll = true; +} + +select3dfloorcontrolsector +{ + title = "Select 3D floor control sector"; + category = "threedfloorplugin"; + description = "Selects the control sector of the currently highlighted 3D floor. Removes all other selections"; + allowkeys = true; + allowmouse = true; + allowscroll = true; +} \ No newline at end of file diff --git a/Source/Plugins/3DFloorMode/Resources/Ceiling.png b/Source/Plugins/3DFloorMode/Resources/Ceiling.png new file mode 100644 index 0000000000000000000000000000000000000000..274d42c7a4293923a20226ce445385bc17112847 GIT binary patch literal 224 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmSN`?>!lvI6;>1s;*b z3=DjSK$uZf!>a)(C{^MbQ4*Y=R#Ki=l*$m0n3-3i=jR%tP-d)Ws%L2E{@KYKs4B+O z#WBRf|8CDkt^)=f%)kHJzb#7^yT~K<&Fo=UoM)IzjguFq|Kvh|uE{-7<{!7nZZvZfpo(lNC8_ q(B5ry#!+m_8txBOt&s)ox4CyryCPw7yrvmwD}$%2pUXO@geCyz$X18| literal 0 HcmV?d00001 diff --git a/Source/Plugins/3DFloorMode/Resources/Floor.png b/Source/Plugins/3DFloorMode/Resources/Floor.png new file mode 100644 index 0000000000000000000000000000000000000000..b996c1acf91ca8dae1b4075f4a57135289382f80 GIT binary patch literal 242 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1qucL8%hgh?3y^w370~qEv=}#LT=BJwMkFg)(D3 zQ$0gN_s>q|KvjvJE{-7<{%d;}`5Fv3j(q#?zj(W6(;7V^)l9vTH?wBeGNrOk5sjEP z>qL2yP;B4h+c}~d%0V+dODy~3?Oh|(^b literal 0 HcmV?d00001 diff --git a/Source/Plugins/3DFloorMode/Resources/FloorAndCeiling.png b/Source/Plugins/3DFloorMode/Resources/FloorAndCeiling.png new file mode 100644 index 0000000000000000000000000000000000000000..693789abe83620f06a93a4cb7f5229c8508a9bed GIT binary patch literal 254 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmSN`?>!lvI6;>1s;*b z3=DjSK$uZf!>a)(C{^MbQ4*Y=R#Ki=l*$m0n3-3i=jR%tP-d)Ws%L2E{@KYKsH)1- z#WBRfe`yyZUxNY<^UwdwFB+YnV%d2_b-QEr+VB6mjqWVuDeowq$0e?vpCVEzpkVza zc;#!2E{iJPcj}D>n_nf*Wcbze-O6u`cfux*`JV-QQ<+|H-+OJbQLJgf^%uO4r6W07 vL@jvU#WwxR-_ibiLYd}a*;5~^_sX8Rx}fIuu0Tq|KvkKZE{-7<{!7mW@-YbVxCZXtoVxq<4nd))RnH!$+%lK*bg46R_Salm zcWX^umB#ZquWyuXAKWgn$FM$25Lz_f5@;!dr>mdKI;Vst0Ae~&D*ylh literal 0 HcmV?d00001 diff --git a/Source/Plugins/3DFloorMode/Resources/ThreeDFloorIcon.png b/Source/Plugins/3DFloorMode/Resources/ThreeDFloorIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..ae79ea256a141f542638985a5600c487ed7288da GIT binary patch literal 290 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmSN`?>!lvI6;>1s;*b z3=DjSK$uZf!>a)(C{^MbQ4*Y=R#Ki=l*$m0n3-3i=jR%tP-d)Ws%L2E{@KYKsA`_4 zi(`m||JvY2-UA98k4yYN8>_L1Xj@J1X>ny=8!&Ok%nO+k+f%vwWjG(k)i+oM9N1-c zzDWHAOGt@<`X}bc2i+g^ah$&PZB6>oD^XYPCTYvcoYq)6!9vJ&!BNrm5kL1ZZe%+D z-<^5KA%Ce9-5qAPEhn@rWu3ofZp8}66XvQ9e|@;u&&*m}YumZE%cJ1psb3$Am{eY! hO4I-DQXpK-@TtbCrsZ|iKA=k(JYD@<);T3K0RS(KX|4bO literal 0 HcmV?d00001 diff --git a/Source/Plugins/3DFloorMode/SectorLabelInfo.cs b/Source/Plugins/3DFloorMode/SectorLabelInfo.cs new file mode 100644 index 00000000..a93d44c7 --- /dev/null +++ b/Source/Plugins/3DFloorMode/SectorLabelInfo.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using CodeImp.DoomBuilder.Map; +using CodeImp.DoomBuilder.Rendering; +using CodeImp.DoomBuilder.Geometry; + +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + class SectorLabelInfo + { + public bool Floor { get { return (planetypes & PlaneType.Floor) == PlaneType.Floor; } } + public bool Ceiling { get { return (planetypes & PlaneType.Ceiling) == PlaneType.Ceiling; } } + public bool Bottom { get { return (planetypes & PlaneType.Bottom) == PlaneType.Bottom; } } + public bool Top { get { return (planetypes & PlaneType.Top) == PlaneType.Top; } } + + private PlaneType planetypes; + private Dictionary> slopevertexgroups; + + public SectorLabelInfo() + { + planetypes = 0; + slopevertexgroups = new Dictionary>(); + + foreach (PlaneType pt in Enum.GetValues(typeof(PlaneType))) + slopevertexgroups.Add(pt, new List()); + } + + public void AddSlopeVertexGroup(PlaneType pt, SlopeVertexGroup svg) + { + if (!slopevertexgroups[pt].Contains(svg)) + slopevertexgroups[pt].Add(svg); + + planetypes |= pt; + } + + public TextLabel[] CreateLabels(Sector sector, SlopeVertex slopevertex, float scale) + { + int numlabels = 0; + int loopcounter = 0; + PixelColor white = new PixelColor(255, 255, 255, 255); + + // Count how many actual labels we have to create at each label position + foreach (PlaneType pt in Enum.GetValues(typeof(PlaneType))) + if ((planetypes & pt) == pt) + numlabels++; + + // Split sectors can have multiple label positions, so we have to create + // numlabels labels for each position + TextLabel[] labels = new TextLabel[sector.Labels.Count * numlabels]; + + foreach (PlaneType pt in Enum.GetValues(typeof(PlaneType))) + { + if ((planetypes & pt) != pt) + continue; + + bool highlighted = false; + + foreach (SlopeVertexGroup svg in slopevertexgroups[pt]) + if (svg.Vertices.Contains(slopevertex)) + highlighted = true; + + for (int i = 0; i < sector.Labels.Count; i++) + { + int apos = sector.Labels.Count * loopcounter + i; + Vector2D location = sector.Labels[i].position; + + location.x += ((-6 * (numlabels-1)) + (loopcounter * 12)) * (1/scale); + + labels[apos] = new TextLabel(); + labels[apos].TransformCoords = true; + labels[apos].AlignX = TextAlignmentX.Center; + labels[apos].AlignY = TextAlignmentY.Middle; + labels[apos].BackColor = General.Colors.Background.WithAlpha(128); + labels[apos].Location = location; + + if (highlighted) + labels[apos].Color = General.Colors.Highlight.WithAlpha(255); + else + labels[apos].Color = white; + + if (pt == PlaneType.Floor) + labels[apos].Text = "F"; + else if (pt == PlaneType.Ceiling) + labels[apos].Text = "C"; + else if (pt == PlaneType.Bottom) + labels[apos].Text = "B"; + else if (pt == PlaneType.Top) + labels[apos].Text = "T"; + } + + loopcounter++; + } + + return labels; + } + + } +} diff --git a/Source/Plugins/3DFloorMode/SlopeMode.cs b/Source/Plugins/3DFloorMode/SlopeMode.cs new file mode 100644 index 00000000..babf15c7 --- /dev/null +++ b/Source/Plugins/3DFloorMode/SlopeMode.cs @@ -0,0 +1,1372 @@ + +#region ================== Copyright (c) 2007 Pascal vd Heiden + +/* + * Copyright (c) 2007 Pascal vd Heiden, www.codeimp.com + * Copyright (c) 2014 Boris Iwanski + * This program is released under GNU General Public License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#endregion + +#region ================== Namespaces + +using System; +using System.Collections; +using System.Drawing; +using System.Collections.Generic; +using System.Globalization; +using System.Text; +using System.Windows.Forms; +using System.IO; +using System.Reflection; +using System.Linq; +using System.Diagnostics; +using CodeImp.DoomBuilder.Windows; +using CodeImp.DoomBuilder.Data; +using CodeImp.DoomBuilder.IO; +using CodeImp.DoomBuilder.Map; +using CodeImp.DoomBuilder.Rendering; +using CodeImp.DoomBuilder.Geometry; +using CodeImp.DoomBuilder.Editing; +using CodeImp.DoomBuilder.Actions; +using CodeImp.DoomBuilder.Config; +using CodeImp.DoomBuilder.Types; +using CodeImp.DoomBuilder.BuilderModes; +// using CodeImp.DoomBuilder.GZBuilder.Geometry; + +#endregion + +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + public class SlopeObject + { + private ThreeDFloor threedfloor; + private Vector2D position; + private int v; + + public ThreeDFloor ThreeDFloor { get { return threedfloor; } set { threedfloor = value; } } + public Vector2D Position { get { return position; } set { position = value; } } + public int V { get { return v; } set { v = value; } } + } + + [EditMode(DisplayName = "Slope Mode", + SwitchAction = "threedslopemode", // Action name used to switch to this mode + ButtonImage = "SlopeModeIcon.png", // Image resource name for the button + ButtonOrder = int.MinValue + 501, // Position of the button (lower is more to the left) + ButtonGroup = "000_editing", + SupportedMapFormats = new[] { "UniversalMapSetIO" }, + UseByDefault = true, + SafeStartMode = true)] + + public class SlopeMode : ClassicMode + { + #region ================== Constants + + #endregion + + #region ================== Variables + + // Highlighted item + private SlopeVertex highlightedslope; + private Sector highlightedsector; + private Association[] association = new Association[Thing.NUM_ARGS]; + private List copyslopevertexgroups; + + private List threedfloors; + bool dragging = false; + + private List labels; + private FlatVertex[] overlaygeometry; + private FlatVertex[] overlaytaggedgeometry; + private FlatVertex[] selectedsectorgeometry; + + private Vector2D dragstartmappos; + private List oldpositions; + + private bool contextmenuclosing = false; + + #endregion + + #region ================== Properties + + public Sector HighlightedSector { get { return highlightedsector; } } + public bool ContextMenuClosing { get { return contextmenuclosing; } set { contextmenuclosing = value; } } + + #endregion + + #region ================== Constructor / Disposer + + #endregion + + #region ================== Methods + + public override void OnHelp() + { + General.ShowHelp("e_things.html"); + } + + // Cancel mode + public override void OnCancel() + { + base.OnCancel(); + + // Return to previous stable mode + General.Editing.ChangeMode(General.Editing.PreviousStableMode.Name); + } + + // Mode engages + public override void OnEngage() + { + base.OnEngage(); + + if (BuilderPlug.Me.SlopeDataSector == null || BuilderPlug.Me.SlopeDataSector.IsDisposed) + { + General.Map.UndoRedo.CreateUndo("Set up slope data sector"); + + SlopeDataSectorDialog sdsd = new SlopeDataSectorDialog(); + DialogResult dr = sdsd.ShowDialog(); + + if (dr == DialogResult.Cancel) + { + General.Map.UndoRedo.WithdrawUndo(); + General.Editing.CancelMode(); + return; + } + + if (dr == DialogResult.OK) + { + BuilderPlug.Me.SlopeDataSector = General.Map.Map.GetMarkedSectors(true)[0]; + BuilderPlug.Me.StoreSlopeVertexGroupsInSector(); + } + } + else + { + BuilderPlug.Me.LoadSlopeVertexGroupsFromSector(); + } + + renderer.SetPresentation(Presentation.Things); + + General.Interface.AddButton(BuilderPlug.Me.MenusForm.UpdateSlopes); + + // Convert geometry selection to sectors + General.Map.Map.ConvertSelection(SelectionType.Sectors); + + // Get all 3D floors in the map + threedfloors = BuilderPlug.GetThreeDFloors(General.Map.Map.Sectors.ToList()); + + SetupLabels(); + + foreach (SlopeVertexGroup svg in BuilderPlug.Me.SlopeVertexGroups) + { + svg.FindSectors(); + } + + // Update overlay surfaces, so that selected sectors are drawn correctly + updateOverlaySurfaces(); + } + + // Mode disengages + public override void OnDisengage() + { + base.OnDisengage(); + + General.Interface.RemoveButton(BuilderPlug.Me.MenusForm.UpdateSlopes); + + // Hide highlight info + General.Interface.HideInfo(); + } + + // This redraws the display + public override void OnRedrawDisplay() + { + renderer.RedrawSurface(); + + // Render lines and vertices + if(renderer.StartPlotter(true)) + { + renderer.PlotLinedefSet(General.Map.Map.Linedefs); + renderer.PlotVerticesSet(General.Map.Map.Vertices); + + foreach (Sector s in General.Map.Map.GetSelectedSectors(true).ToList()) + renderer.PlotSector(s, General.Colors.Selection); + + if ((highlightedsector != null) && !highlightedsector.IsDisposed) + renderer.PlotSector(highlightedsector, General.Colors.Highlight); + + renderer.Finish(); + } + + // Render things + if(renderer.StartThings(true)) + { + renderer.RenderThingSet(General.Map.ThingsFilter.HiddenThings, Presentation.THINGS_HIDDEN_ALPHA); + renderer.RenderThingSet(General.Map.ThingsFilter.VisibleThings, 1.0f); + + renderer.Finish(); + } + + UpdateOverlay(); + + renderer.Present(); + } + + private void SetupLabels() + { + Dictionary sectorlabels = new Dictionary(); + PixelColor white = new PixelColor(255, 255, 255, 255); + + if (labels != null) + { + // Dispose old labels + foreach (TextLabel l in labels) + l.Dispose(); + + labels.Clear(); + } + else + { + labels = new List(); + } + + // Go through all sectors that belong to a SVG and set which SVG their floor and + // ceiling belongs to + foreach (SlopeVertexGroup svg in BuilderPlug.Me.SlopeVertexGroups) + { + // Process all directly affected sectors + foreach (Sector s in svg.Sectors) + { + if(!sectorlabels.ContainsKey(s)) + sectorlabels.Add(s, new SectorLabelInfo()); + + if ((svg.SectorPlanes[s] & PlaneType.Floor) == PlaneType.Floor) + sectorlabels[s].AddSlopeVertexGroup(PlaneType.Floor, svg); + + if ((svg.SectorPlanes[s] & PlaneType.Ceiling) == PlaneType.Ceiling) + sectorlabels[s].AddSlopeVertexGroup(PlaneType.Ceiling, svg); + } + + // Process all tagged sectors + foreach(Sector s in svg.TaggedSectors) + { + if (!sectorlabels.ContainsKey(s)) + sectorlabels.Add(s, new SectorLabelInfo()); + + // Bottom and Top are just virtual, the control sector has Floor and Ceiling + if ((svg.SectorPlanes[s] & PlaneType.Floor) == PlaneType.Floor) + sectorlabels[s].AddSlopeVertexGroup(PlaneType.Bottom, svg); + + if ((svg.SectorPlanes[s] & PlaneType.Ceiling) == PlaneType.Ceiling) + sectorlabels[s].AddSlopeVertexGroup(PlaneType.Top, svg); + } + } + + // Create the labels for each sector and add them to the label list + if (BuilderPlug.Me.SectorLabelDisplayOption != LabelDisplayOption.Never || General.Interface.AltState == true) + { + foreach (Sector s in sectorlabels.Keys) + { + bool showlabel = true; + + if (BuilderPlug.Me.SectorLabelDisplayOption == LabelDisplayOption.WhenHighlighted && General.Interface.AltState == false) + { + showlabel = false; + foreach (SlopeVertexGroup svg in BuilderPlug.Me.SlopeVertexGroups) + if ((svg.Sectors.Contains(s) || svg.TaggedSectors.Contains(s)) && svg.Vertices.Contains(highlightedslope)) + showlabel = true; + } + + if(showlabel) + labels.AddRange(sectorlabels[s].CreateLabels(s, highlightedslope, renderer.Scale)); + } + } + + // Z position labels for slope vertices + if (BuilderPlug.Me.SlopeVertexLabelDisplayOption != LabelDisplayOption.Never || General.Interface.AltState == true) + { + foreach (SlopeVertexGroup svg in BuilderPlug.Me.SlopeVertexGroups) + { + for (int i = 0; i < svg.Vertices.Count; i++) + { + if (BuilderPlug.Me.SlopeVertexLabelDisplayOption == LabelDisplayOption.Always || General.Interface.AltState == true || svg.Vertices.Contains(highlightedslope)) + { + SlopeVertex sv = svg.Vertices[i]; + float scale = 1 / renderer.Scale; + float x = sv.Pos.x; + float y = sv.Pos.y - 14 * scale; + string value = String.Format("Z: {0}", sv.Z); + bool showlabel = true; + + // Rearrange labels if they'd be (exactly) on each other + // TODO: do something like that also for overlapping labels + foreach (TextLabel l in labels) + { + if (l.Location.x == x && l.Location.y == y) { + // Reduce visual clutter by de-duping stacked labels, when "show all labels" is enabled + if (l.Text == value) { + showlabel = false; //dedupe + + // If any of the shared label lines are highlighted/selected, then override the color + if (svg.Vertices.Contains(highlightedslope)) + l.Color = General.Colors.Highlight.WithAlpha(255); + else if (sv.Selected) + l.Color = General.Colors.Selection.WithAlpha(255); + } else { + // Adjust the label position down one line + y -= l.TextSize.Height * scale; + } + } + } + + // Only proceed if the label was not deduped + if (showlabel) + { + TextLabel label = new TextLabel(); + label.TransformCoords = true; + label.Location = new Vector2D(x, y); + label.AlignX = TextAlignmentX.Center; + label.AlignY = TextAlignmentY.Middle; + label.BackColor = General.Colors.Background.WithAlpha(128); + label.Text = value; + + if (svg.Vertices.Contains(highlightedslope)) + label.Color = General.Colors.Highlight.WithAlpha(255); + else if (sv.Selected) + label.Color = General.Colors.Selection.WithAlpha(255); + else + label.Color = white; + + labels.Add(label); + } + } + } + } + } + } + + // This updates the overlay + private void UpdateOverlay() + { + float size = 9 / renderer.Scale; + + SetupLabels(); + + if (renderer.StartOverlay(true)) + { + if(overlaygeometry != null) + renderer.RenderHighlight(overlaygeometry, General.Colors.ModelWireframe.WithAlpha(64).ToInt()); + + if (overlaytaggedgeometry != null) + renderer.RenderHighlight(overlaytaggedgeometry, General.Colors.Vertices.WithAlpha(64).ToInt()); + + if (selectedsectorgeometry != null) + renderer.RenderHighlight(selectedsectorgeometry, General.Colors.Selection.WithAlpha(64).ToInt()); + + if (BuilderPlug.Me.UseHighlight && highlightedsector != null) + { + renderer.RenderHighlight(highlightedsector.FlatVertices, General.Colors.Highlight.WithAlpha(64).ToInt()); + } + + List vertices = new List(); + List highlightlines = new List(); + + // TMP + foreach(Line3D l in BuilderPlug.Me.drawlines) + { + renderer.RenderLine( + new Vector2D(l.Start.x, l.Start.z), + new Vector2D(l.End.x, l.End.z), + 1, new PixelColor(255, 255, 255, 255), true + ); + } + + foreach(Vector3D v in BuilderPlug.Me.drawpoints) + { + renderer.RenderLine( + new Vector2D(v.x, v.z+2), + new Vector2D(v.x, v.z-2), + 1, new PixelColor(255, 255, 0, 0), true); + } + + // Store all slope vertices and draw the lines between them. If the lines connect highlighted slope vertices + // draw them later, so they are on top + foreach (SlopeVertexGroup svg in BuilderPlug.Me.SlopeVertexGroups) + { + bool highlighted = svg.Vertices.Where(o => o == highlightedslope).Count() > 0; + + for (int i = 0; i < svg.Vertices.Count; i++) + { + vertices.Add(svg.Vertices[i]); + + if (i < svg.Vertices.Count - 1) + { + if (highlighted) + highlightlines.Add(new Line2D(svg.Vertices[0].Pos, svg.Vertices[i + 1].Pos)); + else + renderer.RenderLine(svg.Vertices[0].Pos, svg.Vertices[i + 1].Pos, 1, new PixelColor(255, 255, 255, 255), true); + } + } + } + + // Draw highlighted lines + foreach (Line2D line in highlightlines) + renderer.RenderLine(line.v1, line.v2, 1, General.Colors.Highlight, true); + + // Sort the slope vertex list and draw them. The sorting ensures that selected vertices are always drawn on top + foreach(SlopeVertex sv in vertices.OrderBy(o=>o.Selected)) + { + PixelColor c = General.Colors.Indication; + Vector3D v = sv.Pos; + + if (sv.Selected) + c = General.Colors.Selection; + + renderer.RenderRectangleFilled(new RectangleF(v.x - size / 2, v.y - size / 2, size, size), General.Colors.Background, true); + renderer.RenderRectangle(new RectangleF(v.x - size / 2, v.y - size / 2, size, size), 2, c, true); + } + + // Draw highlighted slope vertex + if (highlightedslope != null) + { + renderer.RenderRectangleFilled(new RectangleF(highlightedslope.Pos.x - size / 2, highlightedslope.Pos.y - size / 2, size, size), General.Colors.Background, true); + renderer.RenderRectangle(new RectangleF(highlightedslope.Pos.x - size / 2, highlightedslope.Pos.y - size / 2, size, size), 2, General.Colors.Highlight, true); + } + + foreach (TextLabel l in labels) + renderer.RenderText(l); + + if (selecting) + RenderMultiSelection(); + + renderer.Finish(); + } + } + + private void updateOverlaySurfaces() + { + string[] fieldnames = new string[] { "user_floorplane_id", "user_ceilingplane_id" }; + ICollection orderedselection = General.Map.Map.GetSelectedSectors(true); + List vertslist = new List(); + List highlightedsectors = new List(); + List highlightedtaggedsectors = new List(); + + // Highlighted slope + if (highlightedslope != null) + { + SlopeVertexGroup svg = BuilderPlug.Me.GetSlopeVertexGroup(highlightedslope); + + // All sectors the slope applies to + foreach (Sector s in svg.Sectors) + { + if (s != null && !s.IsDisposed) + { + vertslist.AddRange(s.FlatVertices); + highlightedsectors.Add(s); + } + } + + overlaygeometry = vertslist.ToArray(); + + // All sectors that are tagged because of 3D floors + vertslist = new List(); + + foreach (Sector s in svg.TaggedSectors) + { + if (s != null && !s.IsDisposed) + { + vertslist.AddRange(s.FlatVertices); + highlightedtaggedsectors.Add(s); + } + } + + overlaytaggedgeometry = vertslist.ToArray(); + } + else + { + overlaygeometry = new FlatVertex[0]; + overlaytaggedgeometry = new FlatVertex[0]; + } + + // Selected sectors + vertslist = new List(); + + foreach (Sector s in orderedselection) + if(!highlightedsectors.Contains(s)) + vertslist.AddRange(s.FlatVertices); + + selectedsectorgeometry = vertslist.ToArray(); + } + + // This highlights a new item + protected void HighlightSector(Sector s) + { + // Update display + + highlightedsector = s; + /* + if (renderer.StartPlotter(false)) + { + // Undraw previous highlight + if ((highlightedsector != null) && !highlightedsector.IsDisposed) + renderer.PlotSector(highlightedsector); + + // Set new highlight + highlightedsector = s; + + // Render highlighted item + if ((highlightedsector != null) && !highlightedsector.IsDisposed) + renderer.PlotSector(highlightedsector, General.Colors.Highlight); + + // Done + renderer.Finish(); + } + + UpdateOverlay(); + renderer.Present(); + */ + General.Interface.RedrawDisplay(); + + // Show highlight info + if ((highlightedsector != null) && !highlightedsector.IsDisposed) + General.Interface.ShowSectorInfo(highlightedsector); + else + General.Interface.HideInfo(); + } + + // This selectes or deselects a sector + protected void SelectSector(Sector s, bool selectstate) + { + bool selectionchanged = false; + + if (!s.IsDisposed) + { + // Select the sector? + if (selectstate && !s.Selected) + { + s.Selected = true; + selectionchanged = true; + } + // Deselect the sector? + else if (!selectstate && s.Selected) + { + s.Selected = false; + selectionchanged = true; + } + + // Selection changed? + if (selectionchanged) + { + // Make update lines selection + foreach (Sidedef sd in s.Sidedefs) + { + bool front, back; + if (sd.Line.Front != null) front = sd.Line.Front.Sector.Selected; else front = false; + if (sd.Line.Back != null) back = sd.Line.Back.Sector.Selected; else back = false; + sd.Line.Selected = front | back; + } + + //mxd. Also (de)select things? + if (General.Interface.AltState) + { + foreach (Thing t in General.Map.ThingsFilter.VisibleThings) + { + t.DetermineSector(); + if (t.Sector != s) continue; + t.Selected = s.Selected; + } + } + } + } + } + + public void ResetHighlightedSector() + { + HighlightSector(null); + } + + // Selection + protected override void OnSelectBegin() + { + // Item highlighted? + if(highlightedslope != null) + { + // Flip selection + highlightedslope.Selected = !highlightedslope.Selected; + + updateOverlaySurfaces(); + UpdateOverlay(); + } + + base.OnSelectBegin(); + } + + // End selection + protected override void OnSelectEnd() + { + // Not ending from a multi-selection? + if(!selecting) + { + // Item highlighted? + if (highlightedslope != null) + { + updateOverlaySurfaces(); + UpdateOverlay(); + } + + if (highlightedsector != null) + { + if (!contextmenuclosing) + { + SelectSector(highlightedsector, !highlightedsector.Selected); + + updateOverlaySurfaces(); + General.Interface.RedrawDisplay(); + } + } + + contextmenuclosing = false; + } + + base.OnSelectEnd(); + } + + // Done editing + protected override void OnEditEnd() + { + base.OnEditEnd(); + + if (dragging) return; + + if (highlightedslope != null) + { + SlopeVertex sv = highlightedslope; + + List vertices = GetSelectedSlopeVertices(); + + if (!vertices.Contains(highlightedslope)) + vertices.Add(highlightedslope); + + SlopeVertexEditForm svef = new SlopeVertexEditForm(); + svef.Setup(vertices); + + DialogResult result = svef.ShowDialog((Form)General.Interface); + + if (result == DialogResult.OK) + { + General.Map.IsChanged = true; + + BuilderPlug.Me.UpdateSlopes(); + } + + highlightedslope = null; + } + else if(highlightedsector != null) + { + if (General.Map.Map.SelectedSectorsCount == 0) + { + BuilderPlug.Me.MenusForm.AddSectorsContextMenu.Tag = new List() { highlightedsector }; + } + else + { + BuilderPlug.Me.MenusForm.AddSectorsContextMenu.Tag = General.Map.Map.GetSelectedSectors(true).ToList(); + } + + BuilderPlug.Me.MenusForm.AddSectorsContextMenu.Show(Cursor.Position); + } + + updateOverlaySurfaces(); + UpdateOverlay(); + + General.Interface.RedrawDisplay(); + } + + //Build a list of the closest svs, that share the same distance away from the mouse cursor + private List GetVertexStack() + { + List stack = new List(); + float d, last = float.MaxValue; + + foreach(SlopeVertexGroup svg in BuilderPlug.Me.SlopeVertexGroups) { + foreach(SlopeVertex sv in svg.Vertices) + { + d = Vector2D.Distance(sv.Pos, mousemappos); + if (d <= BuilderModes.BuilderPlug.Me.HighlightRange / renderer.Scale) { + if (d > last) + continue; //discard + else if (d < last) + stack.Clear(); + + stack.Add(sv); + last = d; + } + } + } + + return stack; + } + + // Mouse moves + public override void OnMouseMove(MouseEventArgs e) + { + base.OnMouseMove(e); + + if (selectpressed && !editpressed && !selecting) + { + // Check if moved enough pixels for multiselect + Vector2D delta = mousedownpos - mousepos; + if ((Math.Abs(delta.x) > 2) || (Math.Abs(delta.y) > 2)) + { + // Start multiselecting + StartMultiSelection(); + } + } + else if(e.Button == MouseButtons.None) + { + SlopeVertex oldhighlight = highlightedslope; + Sector oldhighlightedsector = highlightedsector; + + //select the closest handle within grabbing distance + List stack = GetVertexStack(); + if (stack.Count > 0) { + SlopeVertex sv = stack[0]; + if (sv != highlightedslope) + { + //if the "closest" handle is the same distance away as the already highlighted handle, then do nothing + if (highlightedslope == null || (Vector2D.Distance(sv.Pos, mousemappos) != Vector2D.Distance(highlightedslope.Pos, mousemappos))) { + highlightedslope = sv; + } + } + } else { + //nothing within distance, so reset the highlight + highlightedslope = null; + } + + // If no slope vertex is highlighted, check if a sector should be + if (highlightedslope == null) + { + // Find the nearest linedef within highlight range + Linedef l = General.Map.Map.NearestLinedef(mousemappos); + if (l != null) + { + // Check on which side of the linedef the mouse is + float side = l.SideOfLine(mousemappos); + if (side > 0) + { + // Is there a sidedef here? + if (l.Back != null) + { + // Highlight if not the same + if (l.Back.Sector != highlightedsector) HighlightSector(l.Back.Sector); + } + else + { + // Highlight nothing + if (highlightedsector != null) HighlightSector(null); + } + } + else + { + // Is there a sidedef here? + if (l.Front != null) + { + // Highlight if not the same + if (l.Front.Sector != highlightedsector) HighlightSector(l.Front.Sector); + } + else + { + // Highlight nothing + if (highlightedsector != null) HighlightSector(null); + } + } + } + } + else + { + HighlightSector(null); + } + + if (highlightedslope != oldhighlight) + { + updateOverlaySurfaces(); + UpdateOverlay(); + General.Interface.RedrawDisplay(); + } + } + else if (dragging && highlightedslope != null) + { + Vector2D newpos = SnapToNearest(mousemappos); + Vector2D offset = highlightedslope.Pos - newpos; + + foreach (SlopeVertex sl in GetSelectedSlopeVertices()) + sl.Pos -= offset; + + highlightedslope.Pos = newpos; + + General.Map.IsChanged = true; + + updateOverlaySurfaces(); + UpdateOverlay(); + General.Interface.RedrawDisplay(); + } + else if (selecting) + { + UpdateOverlay(); + General.Interface.RedrawDisplay(); + } + } + + // Mouse leaves + public override void OnMouseLeave(EventArgs e) + { + base.OnMouseLeave(e); + + // Highlight nothing + highlightedslope = null; + } + + public override void OnKeyDown(KeyEventArgs e) + { + base.OnKeyDown(e); + + if (e.Alt) + { + General.Interface.RedrawDisplay(); + } + } + + public override void OnKeyUp(KeyEventArgs e) + { + base.OnKeyUp(e); + + if (!e.Alt) + { + General.Interface.RedrawDisplay(); + } + } + + // Mouse wants to drag + protected override void OnDragStart(MouseEventArgs e) + { + base.OnDragStart(e); + + if (e.Button == MouseButtons.Right) + { + dragging = true; + dragstartmappos = mousemappos; + + oldpositions = new List(); + + foreach(SlopeVertex sl in GetSelectedSlopeVertices()) + if(sl.Selected) + oldpositions.Add(sl.Pos); + + + if(highlightedslope != null) + oldpositions.Add(highlightedslope.Pos); + } + } + //retrieves the current mouse position on the grid, snapped as necessary + private Vector2D SnapToNearest(Vector2D vm) + { + float vrange = 20f / renderer.Scale; + bool snaptogrid = General.Interface.ShiftState ^ General.Interface.SnapToGrid; //allow temporary disable of snap by holding shift + + if (General.Interface.AutoMerge) //only snap to geometry if the option is enabled + { + // Try the nearest slope vertex + SlopeVertex nh = NearestSlopeVertexSquareRange(vm, vrange); + if (nh != null) + return nh.Pos; + + // Try the nearest map vertex + Vertex nv = General.Map.Map.NearestVertexSquareRange(vm, vrange); + if (nv != null) + return nv.Position; + + // Try the nearest linedef + Linedef nl = General.Map.Map.NearestLinedefRange(vm, vrange); + if (nl != null) + { + // Snap to grid? + if (snaptogrid) + { + // Get grid intersection coordinates + List coords = nl.GetGridIntersections(); + + // Find nearest grid intersection + bool found = false; + float found_distance = float.MaxValue; + Vector2D found_coord = new Vector2D(); + foreach (Vector2D v in coords) + { + Vector2D delta = vm - v; + if (delta.GetLengthSq() < found_distance) + { + found_distance = delta.GetLengthSq(); + found_coord = v; + found = true; + } + } + + if (found) + return found_coord; + } + else + { + return nl.NearestOnLine(vm); + } + } + } + + //Just get the current mouse location instead + if (snaptogrid) + return General.Map.Grid.SnappedToGrid(vm); + return vm; + } + + /// This finds the thing closest to the specified position. + public SlopeVertex NearestSlopeVertexSquareRange(Vector2D pos, float maxrange) + { + List verts = GetUnSelectedSlopeVertices(); + if (highlightedslope != null) + verts.Remove(highlightedslope); + + return NearestSlopeVertexSquareRange(verts, pos, maxrange); + } + + /// This finds the slope vertex closest to the specified position. + public SlopeVertex NearestSlopeVertexSquareRange(ICollection selection, Vector2D pos, float maxrange) + { + RectangleF range = RectangleF.FromLTRB(pos.x - maxrange, pos.y - maxrange, pos.x + maxrange, pos.y + maxrange); + SlopeVertex closest = null; + float distance = float.MaxValue; + + // Go for all vertices in selection + foreach (SlopeVertex v in selection) + { + float px = v.Pos.x; + float py = v.Pos.y; + + //mxd. Within range? + if ((v.Pos.x < range.Left) || (v.Pos.x > range.Right) + || (v.Pos.y < range.Top) || (v.Pos.y > range.Bottom)) + continue; + + // Close than previous find? + float d = Math.Abs(px - pos.x) + Math.Abs(py - pos.y); + if (d < distance) + { + // This one is closer + closest = v; + distance = d; + } + } + + // Return result + return closest; + } + + // Mouse wants to drag + protected override void OnDragStop(MouseEventArgs e) + { + base.OnDragStop(e); + + General.Map.UndoRedo.CreateUndo("Drag slope vertex"); + + BuilderPlug.Me.StoreSlopeVertexGroupsInSector(); + General.Map.Map.Update(); + + BuilderPlug.Me.UpdateSlopes(); + + dragging = false; + } + + + // This is called wheh selection ends + protected override void OnEndMultiSelection() + { + bool selectionvolume = ((Math.Abs(base.selectionrect.Width) > 0.1f) && (Math.Abs(base.selectionrect.Height) > 0.1f)); + + if(BuilderPlug.Me.AutoClearSelection && !selectionvolume) + General.Map.Map.ClearSelectedThings(); + + if(selectionvolume) + { + if(General.Interface.ShiftState ^ BuilderPlug.Me.AdditiveSelect) + { + // Go for all slope vertices + foreach (SlopeVertex sl in GetAllSlopeVertices()) + { + sl.Selected |= ((sl.Pos.x >= selectionrect.Left) && + (sl.Pos.y >= selectionrect.Top) && + (sl.Pos.x <= selectionrect.Right) && + (sl.Pos.y <= selectionrect.Bottom)); + } + } + else + { + // Go for all slope vertices + foreach (SlopeVertex sl in GetAllSlopeVertices()) + { + sl.Selected |= ((sl.Pos.x >= selectionrect.Left) && + (sl.Pos.y >= selectionrect.Top) && + (sl.Pos.x <= selectionrect.Right) && + (sl.Pos.y <= selectionrect.Bottom)); + } + } + } + + base.OnEndMultiSelection(); + + // Clear overlay + if(renderer.StartOverlay(true)) renderer.Finish(); + + // Redraw + General.Interface.RedrawDisplay(); + } + + // This is called when the selection is updated + protected override void OnUpdateMultiSelection() + { + base.OnUpdateMultiSelection(); + + UpdateOverlay(); + } + + public override bool OnCopyBegin() + { + copyslopevertexgroups = new List(); + + foreach (SlopeVertexGroup svg in BuilderPlug.Me.SlopeVertexGroups) + { + bool copy = false; + + // Check if the current SVG has to be copied + foreach (SlopeVertex sv in svg.Vertices) + { + if (sv.Selected) + { + copy = true; + break; + } + } + + if (copy) + { + List newsv = new List(); + + foreach (SlopeVertex sv in svg.Vertices) + newsv.Add(new SlopeVertex(sv.Pos, sv.Z)); + + // Use -1 for id, since a real id will be assigned when pasting + copyslopevertexgroups.Add(new SlopeVertexGroup(-1, newsv)); + } + } + + return true; + } + + public override bool OnPasteBegin(PasteOptions options) + { + if (copyslopevertexgroups == null || copyslopevertexgroups.Count == 0) + return false; + + // Unselect all slope vertices, so the pasted vertices can be selected + foreach (SlopeVertexGroup svg in BuilderPlug.Me.SlopeVertexGroups) + svg.SelectVertices(false); + + float l = copyslopevertexgroups[0].Vertices[0].Pos.x; + float r = copyslopevertexgroups[0].Vertices[0].Pos.x; + float t = copyslopevertexgroups[0].Vertices[0].Pos.y; + float b = copyslopevertexgroups[0].Vertices[0].Pos.y; + + // Find the outer dimensions of all SVGs to paste + foreach (SlopeVertexGroup svg in copyslopevertexgroups) + { + foreach (SlopeVertex sv in svg.Vertices) + { + if (sv.Pos.x < l) l = sv.Pos.x; + if (sv.Pos.x > r) r = sv.Pos.x; + if (sv.Pos.y > t) t = sv.Pos.y; + if (sv.Pos.y < b) b = sv.Pos.y; + } + } + + Vector2D center = new Vector2D(l + ((r - l) / 2), b + ((t - b) / 2)); + Vector2D diff = center - General.Map.Grid.SnappedToGrid(mousemappos); + + foreach (SlopeVertexGroup svg in copyslopevertexgroups) + { + int id; + List newsv = new List(); + + foreach (SlopeVertex sv in svg.Vertices) + { + newsv.Add(new SlopeVertex(new Vector2D(sv.Pos.x - diff.x, sv.Pos.y - diff.y), sv.Z)); + } + + SlopeVertexGroup newsvg = BuilderPlug.Me.AddSlopeVertexGroup(newsv, out id); + newsvg.SelectVertices(true); + } + + // Redraw the display, so that pasted SVGs are shown immediately + General.Interface.RedrawDisplay(); + + // Don't go into the standard process for pasting, so tell the core that + // pasting should not proceed + return false; + } + + public List GetSelectedSlopeVertices() + { + List selected = new List(); + + foreach (SlopeVertexGroup svg in BuilderPlug.Me.SlopeVertexGroups) + { + foreach (SlopeVertex sv in svg.Vertices) + { + if (sv.Selected) + selected.Add(sv); + } + } + + return selected; + } + + public List GetUnSelectedSlopeVertices() + { + List notselected = new List(); + + foreach (SlopeVertexGroup svg in BuilderPlug.Me.SlopeVertexGroups) + { + foreach (SlopeVertex sv in svg.Vertices) + { + if (!sv.Selected) + notselected.Add(sv); + } + } + + return notselected; + } + + public List GetAllSlopeVertices() + { + List selected = new List(); + + foreach (SlopeVertexGroup svg in BuilderPlug.Me.SlopeVertexGroups) + { + foreach (SlopeVertex sv in svg.Vertices) + { + selected.Add(sv); + } + } + + return selected; + } + + public List GetSelectedSlopeVertexGroups() + { + List svgs = new List(); + + foreach (SlopeVertex sv in GetSelectedSlopeVertices()) + { + SlopeVertexGroup svg = BuilderPlug.Me.GetSlopeVertexGroup(sv); + + if (!svgs.Contains(svg)) + svgs.Add(svg); + } + + return svgs; + } + + #endregion + + #region ================== Actions + + [BeginAction("drawfloorslope")] + public void DrawFloorSlope() + { + BuilderPlug.Me.MenusForm.CeilingSlope.Checked = false; + BuilderPlug.Me.MenusForm.FloorSlope.Checked = true; + BuilderPlug.Me.MenusForm.FloorAndCeilingSlope.Checked = false; + + General.Interface.DisplayStatus(StatusType.Info, "Applying drawn slope to floor"); + } + + [BeginAction("drawceilingslope")] + public void DrawCeilingSlope() + { + BuilderPlug.Me.MenusForm.CeilingSlope.Checked = true; + BuilderPlug.Me.MenusForm.FloorSlope.Checked = false; + BuilderPlug.Me.MenusForm.FloorAndCeilingSlope.Checked = false; + + General.Interface.DisplayStatus(StatusType.Info, "Applying drawn slope to ceiling"); + } + + [BeginAction("drawfloorandceilingslope")] + public void DrawFloorAndCeilingSlope() + { + BuilderPlug.Me.MenusForm.CeilingSlope.Checked = false; + BuilderPlug.Me.MenusForm.FloorSlope.Checked = false; + BuilderPlug.Me.MenusForm.FloorAndCeilingSlope.Checked = true; + + General.Interface.DisplayStatus(StatusType.Info, "Applying drawn slope to floor and ceiling"); + } + + [BeginAction("threedflipslope")] + public void FlipSlope() + { + if (highlightedslope == null) + return; + + MessageBox.Show("Flipping temporarily removed"); + + /* + if (highlightedslope.IsOrigin) + { + origin = highlightedslope.ThreeDFloor.Slope.Origin + highlightedslope.ThreeDFloor.Slope.Direction; + direction = highlightedslope.ThreeDFloor.Slope.Direction * (-1); + } + else + { + origin = highlightedslope.ThreeDFloor.Slope.Origin + highlightedslope.ThreeDFloor.Slope.Direction; + direction = highlightedslope.ThreeDFloor.Slope.Direction * (-1); + } + + highlightedslope.ThreeDFloor.Slope.Origin = origin; + highlightedslope.ThreeDFloor.Slope.Direction = direction; + + highlightedslope.ThreeDFloor.Rebuild = true; + + BuilderPlug.ProcessThreeDFloors(new List { highlightedslope.ThreeDFloor }, highlightedslope.ThreeDFloor.TaggedSectors); + + UpdateSlopeObjects(); + + // Redraw + General.Interface.RedrawDisplay(); + */ + } + + // This clears the selection + [BeginAction("clearselection", BaseAction = true)] + public void ClearSelection() + { + int numselected = 0; + // Clear selection + foreach (SlopeVertexGroup svg in BuilderPlug.Me.SlopeVertexGroups) + { + foreach (SlopeVertex sv in svg.Vertices) + { + if (sv.Selected) + { + sv.Selected = false; + numselected++; + } + + } + } + + // Clear selected sectors when no SVGs are selected + if (numselected == 0) + General.Map.Map.ClearAllSelected(); + + // Redraw + updateOverlaySurfaces(); + UpdateOverlay(); + General.Interface.RedrawDisplay(); + } + + + [BeginAction("deleteitem", BaseAction = true)] + public void DeleteItem() + { + // Make list of selected things + List selected = new List(GetSelectedSlopeVertices()); + + if(highlightedslope != null) + { + selected.Add(highlightedslope); + } + + // Anything to do? + if(selected.Count > 0) + { + List groups = new List(); + + General.Map.UndoRedo.CreateUndo("Delete slope"); + + foreach (SlopeVertex sv in selected) + { + SlopeVertexGroup svg = BuilderPlug.Me.GetSlopeVertexGroup(sv); + + if (!groups.Contains(svg)) + groups.Add(svg); + } + + foreach (SlopeVertexGroup svg in groups) + { + svg.RemovePlanes(); + svg.RemoveUndoRedoUDMFFields(BuilderPlug.Me.SlopeDataSector); + + BuilderPlug.Me.SlopeVertexGroups.Remove(svg); + } + + General.Map.IsChanged = true; + + // Invoke a new mousemove so that the highlighted item updates + MouseEventArgs e = new MouseEventArgs(MouseButtons.None, 0, (int)mousepos.x, (int)mousepos.y, 0); + OnMouseMove(e); + + // Redraw screen + General.Interface.RedrawDisplay(); + } + } + + + [BeginAction("cyclehighlighted3dfloorup")] + public void CycleHighlighted3DFloorUp() + { + if (highlightedslope == null) + return; + List stack = GetVertexStack(); + if (stack.Count == 0) + return; + + int idx = stack.IndexOf(highlightedslope) + 1; + if (idx >= stack.Count) + idx = 0; + highlightedslope = stack[idx]; + + updateOverlaySurfaces(); + UpdateOverlay(); + General.Interface.RedrawDisplay(); + } + + [BeginAction("cyclehighlighted3dfloordown")] + public void CycleHighlighted3DFloorDown() + { + if (highlightedslope == null) + return; + List stack = GetVertexStack(); + if (stack.Count == 0) + return; + + int idx = stack.IndexOf(highlightedslope) - 1; + if (idx < 0) + idx = stack.Count - 1; + highlightedslope = stack[idx]; + + updateOverlaySurfaces(); + UpdateOverlay(); + General.Interface.RedrawDisplay(); + } + + #endregion + } +} diff --git a/Source/Plugins/3DFloorMode/SlopeVertex.cs b/Source/Plugins/3DFloorMode/SlopeVertex.cs new file mode 100644 index 00000000..bb755f60 --- /dev/null +++ b/Source/Plugins/3DFloorMode/SlopeVertex.cs @@ -0,0 +1,99 @@ +#region ================== Namespaces + +using System; +using System.Reflection; +using System.Collections.Generic; +using CodeImp.DoomBuilder.Geometry; +using CodeImp.DoomBuilder.Map; +using CodeImp.DoomBuilder.Types; + +#endregion + +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + public class SlopeVertex + { + #region ================== Variables + + // private Vector2D pos; + private float x; + private float y; + private float z; + private bool selected; + + #endregion + + #region ================== Constructors + + public SlopeVertex(Sector sector, int svgid, int vertexid) + { + string identifier; + List list = new List { "x", "y", "z" }; + Type type = typeof(SlopeVertex); + + this.x = 0; + this.y = 0; + this.z = 0; + this.selected = false; + + // Read the x, y and z values + foreach (string str in list) + { + identifier = String.Format("user_svg{0}_v{1}_{2}", svgid, vertexid, str); + + // Use reflection to set the variable to the value + type.GetField(str, BindingFlags.Instance | BindingFlags.NonPublic).SetValue(this, sector.Fields.GetValue(identifier, 0.0f)); + } + } + + public SlopeVertex(Vector2D p, float z) + { + // this.pos = new Vector2D(p); + this.x = p.x; + this.y = p.y; + this.z = z; + this.selected = false; + } + + #endregion + + #region ================== Properties + + public Vector2D Pos { get { return new Vector2D(x, y); } set { x = value.x; y = value.y; } } + public float Z { get { return z; } set { z = value; } } + public bool Selected { get { return selected; } set { selected = value; } } + + #endregion + + #region ================== Methods + + public void StoreInSector(Sector sector, int svgid, int vertexid) + { + string identifier; + + Dictionary dict = new Dictionary + { + { "x", x }, + { "y", y }, + { "z", z } + }; + + // Make sure the field work with undo/redo + sector.Fields.BeforeFieldsChange(); + + // Process the x, y and z fields + foreach (KeyValuePair kvp in dict) + { + identifier = String.Format("user_svg{0}_v{1}_{2}", svgid, vertexid, kvp.Key); + + // Add or update the vertex field + if (sector.Fields.ContainsKey(identifier)) + sector.Fields[identifier] = new UniValue(UniversalType.Float, kvp.Value); + else + sector.Fields.Add(identifier, new UniValue(UniversalType.Float, kvp.Value)); + } + } + + #endregion + } +} \ No newline at end of file diff --git a/Source/Plugins/3DFloorMode/SlopeVertexGroup.cs b/Source/Plugins/3DFloorMode/SlopeVertexGroup.cs new file mode 100644 index 00000000..608fa806 --- /dev/null +++ b/Source/Plugins/3DFloorMode/SlopeVertexGroup.cs @@ -0,0 +1,477 @@ +#region ================== Namespaces + +using System; +using System.Reflection; +using System.Runtime.Serialization; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System.Linq; +using System.Diagnostics; +using CodeImp.DoomBuilder.Geometry; +using CodeImp.DoomBuilder.Map; +using CodeImp.DoomBuilder.Types; + +#endregion + +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + public class SlopeVertexGroup + { + #region ================== Variables + private List vertices; + private List sectors; + private Dictionary sectorplanes; + private List taggedsectors; // For highlighting 3D floors + private int id; + private int height; + private Vertex anchorvertex; + private Vector2D anchor; + private bool reposition; + private bool spline; + + #endregion + + #region ================== Enums + + #endregion + + #region ================== Properties + + public List Vertices { get { return vertices; } set { vertices = value; ComputeHeight(); } } + public List Sectors { get { return sectors; } set { sectors = value; } } + public Dictionary SectorPlanes { get { return sectorplanes; } } + public List TaggedSectors { get { return taggedsectors; } set { taggedsectors = value; } } + public int Id { get { return id; } } + public int Height { get { return height; } set { height = value; } } + public bool Reposition { get { return reposition; } set { reposition = value; } } + public bool Spline { get { return spline; }set { spline = value; } } + + #endregion + + #region ================== Constructors + + public SlopeVertexGroup(int id, Sector sector) + { + List list = new List { "floor", "ceiling" }; + Type type = typeof(SlopeVertexGroup); + + this.id = id; + sectors = new List(); + sectorplanes = new Dictionary(); + taggedsectors = new List(); + vertices = new List(); + anchorvertex = null; + + // There will always be at least two slope vertices, so add them here + vertices.Add(new SlopeVertex(sector, id, 0)); + vertices.Add(new SlopeVertex(sector, id, 1)); + + // Check if there's a third slope vertex, and add it if there is + string vertexidentifier = String.Format("user_svg{0}_v2_x", id); + + foreach (KeyValuePair kvp in sector.Fields) + { + if (kvp.Key == vertexidentifier) + { + vertices.Add(new SlopeVertex(sector, id, 2)); + break; + } + } + + // Get reposition value + reposition = sector.Fields.GetValue(String.Format("user_svg{0}_reposition", id), true); + + // Get spline value + spline = sector.Fields.GetValue(String.Format("user_svg{0}_spline", id), false); + + spline = false; + + ComputeHeight(); + FindSectors(); + } + + public SlopeVertexGroup(int id, List vertices) + { + this.vertices = vertices; + this.id = id; + sectors = new List(); + sectorplanes = new Dictionary(); + taggedsectors = new List(); + anchorvertex = null; + height = 0; + + ComputeHeight(); + } + + #endregion + + #region ================== Methods + + public void FindSectors() + { + if (sectors == null) + sectors = new List(); + else + sectors.Clear(); + + if (taggedsectors == null) + taggedsectors = new List(); + else + taggedsectors.Clear(); + + sectorplanes.Clear(); + + foreach (Sector s in General.Map.Map.Sectors) + { + bool onfloor = s.Fields.GetValue("user_floorplane_id", -1) == id; + bool onceiling = s.Fields.GetValue("user_ceilingplane_id", -1) == id; + PlaneType pt = 0; + + if (!onfloor && !onceiling) + continue; + + sectors.Add(s); + + if (onfloor && onceiling) + pt = PlaneType.Floor | PlaneType.Ceiling; + else if (onfloor) + pt = PlaneType.Floor; + else if (onceiling) + pt = PlaneType.Ceiling; + + sectorplanes.Add(s, pt); + + GetTaggesSectors(s, pt); + } + } + + public void RemovePlanes() + { + foreach (Sector s in sectors.ToList()) + { + RemoveSector(s, this.sectorplanes[s]); + } + } + + public void RemoveFromSectors() + { + foreach (Sector s in sectors.ToList()) + { + RemoveSector(s, PlaneType.Floor); + RemoveSector(s, PlaneType.Ceiling); + } + } + + private void GetTaggesSectors(Sector s, PlaneType pt) + { + // Check if the current sector is a 3D floor control sector. If that's the case also store the + // tagged sector(s). They will be used for highlighting in slope mode + foreach (Sidedef sd in s.Sidedefs) + { + if (sd.Line.Action == 160) + { + foreach (Sector ts in General.Map.Map.GetSectorsByTag(sd.Line.Args[0])) + { + if (!taggedsectors.Contains(ts)) + taggedsectors.Add(ts); + + if(!sectorplanes.ContainsKey(ts)) + sectorplanes.Add(ts, pt); + } + } + } + } + + public void AddSector(Sector s, PlaneType pt) + { + if (sectorplanes.ContainsKey(s)) + { + pt |= sectorplanes[s]; + sectorplanes.Remove(s); + } + + if (sectors.Contains(s)) + sectors.Remove(s); + + sectorplanes.Add(s, pt); + sectors.Add(s); + + GetTaggesSectors(s, pt); + + ApplyToSectors(); + } + + public void RemoveSector(Sector s, PlaneType pt) + { + Debug.WriteLine("Removing from Sector " + s.Index.ToString() + ": " + pt.ToString()); + + if (sectorplanes.ContainsKey(s)) + { + if (sectors.Contains(s) && sectorplanes[s] == pt) + { + sectors.Remove(s); + sectorplanes.Remove(s); + } + else + sectorplanes[s] &= ~pt; + } + + if ((pt & PlaneType.Floor) == PlaneType.Floor) + { + s.FloorSlope = new Vector3D(); + s.FloorSlopeOffset = 0; + s.Fields.Remove("user_floorplane_id"); + } + + if ((pt & PlaneType.Ceiling) == PlaneType.Ceiling) + { + s.CeilSlope = new Vector3D(); + s.CeilSlopeOffset = 0; + s.Fields.Remove("user_ceilingplane_id"); + } + } + + public void RemoveUndoRedoUDMFFields(Sector s) + { + string fieldname = ""; + string[] comp = new string[] { "x", "y", "z" }; + + if (s == null || s.IsDisposed) + return; + + s.Fields.BeforeFieldsChange(); + + for (int i = 0; i < 3; i++) + { + foreach (string c in comp) + { + fieldname = string.Format("user_svg{0}_v{1}_{2}", id, i, c); + + if (s.Fields.ContainsKey(fieldname)) + s.Fields.Remove(fieldname); + } + } + + // Remove reposition field + fieldname = string.Format("user_svg{0}_reposition", id); + if (s.Fields.ContainsKey(fieldname)) + s.Fields.Remove(fieldname); + } + + public void ApplyToSectors() + { + List removesectors = new List(); + + ComputeHeight(); + + foreach (Sector s in sectors) + { + bool hasplane = false; + + if (sectorplanes.ContainsKey(s) && (sectorplanes[s] & PlaneType.Floor) == PlaneType.Floor) + { + hasplane = true; + + if (s.Fields.ContainsKey("user_floorplane_id")) + s.Fields["user_floorplane_id"] = new UniValue(UniversalType.Integer, id); + else + s.Fields.Add("user_floorplane_id", new UniValue(UniversalType.Integer, id)); + } + else if (s.Fields.ContainsKey("user_floorplane_id") && s.Fields.GetValue("user_floorplane_id", -1) == id) + { + s.Fields.Remove("user_floorplane_id"); + } + + if (sectorplanes.ContainsKey(s) && (sectorplanes[s] & PlaneType.Ceiling) == PlaneType.Ceiling) + { + hasplane = true; + + if (s.Fields.ContainsKey("user_ceilingplane_id")) + s.Fields["user_ceilingplane_id"] = new UniValue(UniversalType.Integer, id); + else + s.Fields.Add("user_ceilingplane_id", new UniValue(UniversalType.Integer, id)); + } + else if (s.Fields.ContainsKey("user_ceilingplane_id") && s.Fields.GetValue("user_ceilingplane_id", -1) == id) + { + s.Fields.Remove("user_ceilingplane_id"); + } + + if (!hasplane) + removesectors.Add(s); + } + + foreach (Sector s in removesectors) + sectors.Remove(s); + + foreach (Sector s in sectors) + BuilderPlug.Me.UpdateSlopes(s); + } + + public void StoreInSector(Sector sector) + { + // Make sure the field work with undo/redo + sector.Fields.BeforeFieldsChange(); + + // Also store all slope vertices in the sector + for (int i = 0; i < vertices.Count; i++) + vertices[i].StoreInSector(sector, id, i); + + string identifier = String.Format("user_svg{0}_reposition", id); + + // Add, update, or delete the reposition field + if (reposition) + { + //default action + if (sector.Fields.ContainsKey(identifier)) + sector.Fields.Remove(identifier); + } + else + { + if (sector.Fields.ContainsKey(identifier)) + sector.Fields[identifier] = new UniValue(UniversalType.Boolean, reposition); + else + sector.Fields.Add(identifier, new UniValue(UniversalType.Boolean, reposition)); + } + + // Spline + identifier = String.Format("user_svg{0}_spline", id); + + if (!spline && sector.Fields.ContainsKey(identifier)) + sector.Fields.Remove(identifier); + else if (spline) + { + if (sector.Fields.ContainsKey(identifier)) + sector.Fields[identifier] = new UniValue(UniversalType.Boolean, spline); + else + sector.Fields.Add(identifier, new UniValue(UniversalType.Boolean, spline)); + } + } + + public void SelectVertices(bool select) + { + foreach (SlopeVertex sv in vertices) + sv.Selected = select; + } + + public bool GetAnchor() + { + anchorvertex = null; + + if (sectors.Count == 0) + return false; + + // Try to find a sector that contains a SV + /* + foreach (Sector s in sectors) + { + foreach (SlopeVertex sv in vertices) + { + if (s.Intersect(sv.Pos)) + { + anchorvertex = s.Sidedefs.First().Line.Start; + anchor = new Vector2D(anchorvertex.Position); + return true; + } + } + } + */ + + // Just grab the next best vertex + foreach (Sector s in sectors) + { + foreach (Sidedef sd in s.Sidedefs) + { + anchorvertex = sd.Line.Start; + anchor = new Vector2D(anchorvertex.Position); + return true; + } + } + + return false; + } + + public void RepositionByAnchor() + { + if (anchorvertex == null || !reposition) + return; + + Vector2D diff = anchorvertex.Position - anchor; + + if (diff.x == 0.0f && diff.y == 0.0f) + return; + + foreach (SlopeVertex sv in vertices) + { + sv.Pos += diff; + } + + anchorvertex = null; + } + + public void ComputeHeight() + { + List sp = new List(); + + for (int i = 0; i < vertices.Count; i++) + { + sp.Add(new Vector3D(vertices[i].Pos.x, vertices[i].Pos.y,vertices[i].Z)); + } + + if (vertices.Count == 2) + { + float z = sp[0].z; + Line2D line = new Line2D(sp[0], sp[1]); + Vector3D perpendicular = line.GetPerpendicular(); + + Vector2D v = sp[0] + perpendicular; + + sp.Add(new Vector3D(v.x, v.y, z)); + } + + Plane p = new Plane(sp[0], sp[1], sp[2], true); + + float fheight = p.GetZ(GetCircumcenter(sp)); + + // If something went wrong with computing the height use the height + // of the first vertex as a workaround + if (float.IsNaN(fheight)) + height = Convert.ToInt32(sp[0].z); + else + height = Convert.ToInt32(fheight); + } + + private Vector2D GetCircumcenter(List points) + { + float u_ray; + + Line2D line1 = new Line2D(points[0], points[1]); + Line2D line2 = new Line2D(points[2], points[0]); + + // Perpendicular bisectors + Line2D bisector1 = new Line2D(line1.GetCoordinatesAt(0.5f), line1.GetCoordinatesAt(0.5f) + line1.GetPerpendicular()); + Line2D bisector2 = new Line2D(line2.GetCoordinatesAt(0.5f), line2.GetCoordinatesAt(0.5f) + line2.GetPerpendicular()); + + bisector1.GetIntersection(bisector2, out u_ray); + + return bisector1.GetCoordinatesAt(u_ray); + } + + public bool VerticesAreValid() + { + if (vertices.Count == 2 && vertices[0].Pos == vertices[1].Pos) + return false; + + if (vertices.Count == 3) + { + float side = Line2D.GetSideOfLine(vertices[0].Pos, vertices[1].Pos, vertices[3].Pos); + + if (side == 0.0f) + return false; + } + + return true; + } + + #endregion + } +} \ No newline at end of file diff --git a/Source/Plugins/3DFloorMode/ThreeDFloor.cs b/Source/Plugins/3DFloorMode/ThreeDFloor.cs new file mode 100644 index 00000000..10ecad79 --- /dev/null +++ b/Source/Plugins/3DFloorMode/ThreeDFloor.cs @@ -0,0 +1,351 @@ +#region ================== Copyright (c) 2014 Boris Iwanski + +/* + * Copyright (c) 2014 Boris Iwanski + * This program is released under GNU General Public License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Drawing; +using System.Windows.Forms; +using CodeImp.DoomBuilder.Windows; +using CodeImp.DoomBuilder.IO; +using CodeImp.DoomBuilder.Map; +using CodeImp.DoomBuilder.Rendering; +using CodeImp.DoomBuilder.Geometry; +using CodeImp.DoomBuilder.Editing; +using CodeImp.DoomBuilder.Plugins; +using CodeImp.DoomBuilder.Actions; +using CodeImp.DoomBuilder.Types; +using CodeImp.DoomBuilder.Config; +using CodeImp.DoomBuilder.Data; + +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + public class ThreeDFloor + { + private Sector sector; + private List taggedsectors; + private List sectorstotag; + private List sectorstountag; + private string bordertexture; + private string topflat; + private string bottomflat; + private int type; + private int flags; + private int alpha; + private int brightness; + private int topheight; + private int bottomheight; + private bool isnew; + private bool rebuild; + private int udmftag; + private List tags; + + public static Rectangle controlsectorarea = new Rectangle(-512, 512, 512, -512); + + public Sector Sector { get { return sector; } } + public List TaggedSectors { get { return taggedsectors; } set { taggedsectors = value; } } + public List SectorsToTag { get { return sectorstotag; } set { sectorstotag = value; } } + public List SectorsToUntag { get { return sectorstountag; } set { sectorstountag = value; } } + public string BorderTexture { get { return bordertexture; } set { bordertexture = value; } } + public string TopFlat { get { return topflat; } set { topflat = value; } } + public string BottomFlat { get { return bottomflat; } set { bottomflat = value; } } + public int Type { get { return type; } set { type = value; } } + public int Flags { get { return flags; } set { flags = value; } } + public int Alpha { get { return alpha; } set { alpha = value; } } + public int Brightness { get { return brightness; }set { brightness = value; } } + public int TopHeight { get { return topheight; } set { topheight = value; } } + public int BottomHeight { get { return bottomheight; } set { bottomheight = value; } } + public bool IsNew { get { return isnew; } set { isnew = value; } } + public bool Rebuild { get { return rebuild; } set { rebuild = value; } } + public int UDMFTag { get { return udmftag; } set { udmftag = value; } } + public List Tags { get { return tags; } set { tags = value; } } + + public ThreeDFloor() + { + sector = null; + taggedsectors = new List(); + topflat = General.Settings.DefaultCeilingTexture; + bottomflat = General.Settings.DefaultFloorTexture; + topheight = General.Settings.DefaultCeilingHeight; + bottomheight = General.Settings.DefaultFloorHeight; + bordertexture = General.Settings.DefaultTexture; + type = 1; + flags = 0; + tags = new List(); + + alpha = 255; + } + + public ThreeDFloor(Sector sector) + { + if (sector == null) + throw new Exception("Sector can't be null"); + + this.sector = sector; + taggedsectors = new List(); + topflat = sector.CeilTexture; + bottomflat = sector.FloorTexture; + topheight = sector.CeilHeight; + bottomheight = sector.FloorHeight; + brightness = sector.Brightness; + tags = new List(); + + foreach (Sidedef sd in sector.Sidedefs) + { + if (sd.Line.Action == 160) + { + bordertexture = sd.MiddleTexture; + udmftag = sd.Line.Args[0]; + type = sd.Line.Args[1]; + flags = sd.Line.Args[2]; + alpha = sd.Line.Args[3]; + + foreach (Sector s in General.Map.Map.GetSectorsByTag(sd.Line.Args[0])) + { + if(!taggedsectors.Contains(s)) + taggedsectors.Add(s); + } + } + } + } + + public void BindTag(int tag) + { + Linedef line = null; + + // try to find an line without an action + foreach (Sidedef sd in sector.Sidedefs) + { + if (sd.Line.Action == 0 && sd.Line.Tag == 0 && line == null) + line = sd.Line; + + // if a line of the control sector already has the tag + // nothing has to be done + if (sd.Line.Args[0] == tag) + { + return; + } + } + + // no lines without an action, so a line has to get split + // find the longest line to split + if (line == null) + { + line = sector.Sidedefs.First().Line; + + foreach (Sidedef sd in sector.Sidedefs) + { + if (sd.Line.Length > line.Length) + line = sd.Line; + } + + // Lines may not have a length of less than 1 after splitting + if (line.Length / 2 < 1) + throw new Exception("Can't split more lines in Sector " + line.Front.Sector.Index.ToString() + "."); + + Vertex v = General.Map.Map.CreateVertex(line.Line.GetCoordinatesAt(0.5f)); + v.SnapToAccuracy(); + + line = line.Split(v); + + General.Map.Map.Update(); + General.Interface.RedrawDisplay(); + } + + line.Action = 160; + line.Args[0] = tag; + line.Args[1] = type; + line.Args[2] = flags; + line.Args[3] = alpha; + } + + public void UpdateGeometry() + { + if (sector == null) + throw new Exception("3D floor has no geometry"); + + sector.CeilHeight = topheight; + sector.FloorHeight = bottomheight; + sector.SetCeilTexture(topflat); + sector.SetFloorTexture(bottomflat); + sector.Brightness = brightness; + sector.Tags = tags; + + foreach (Sidedef sd in sector.Sidedefs) + { + sd.SetTextureMid(bordertexture); + + if (sd.Line.Action == 160) + { + sd.Line.Args[1] = type; + sd.Line.Args[2] = flags; + sd.Line.Args[3] = alpha; + } + } + } + + public bool CreateGeometry(List tagblacklist) + { + List drawnvertices = new List(); + List vertices = new List(); + Vector3D slopetopthingpos = new Vector3D(0, 0, 0); + Vector3D slopebottomthingpos = new Vector3D(0, 0, 0); + Line2D slopeline = new Line2D(0, 0, 0, 0); + + drawnvertices = BuilderPlug.Me.ControlSectorArea.GetNewControlSectorVertices(); + + if (Tools.DrawLines(drawnvertices) == false) + { + General.Interface.DisplayStatus(StatusType.Warning, "Could not draw new sector"); + return false; + } + + sector = General.Map.Map.GetMarkedSectors(true)[0]; + + sector.FloorHeight = bottomheight; + sector.CeilHeight = topheight; + sector.SetFloorTexture(bottomflat); + sector.SetCeilTexture(topflat); + + foreach (Sidedef sd in sector.Sidedefs) + { + sd.Line.Front.SetTextureMid(bordertexture); + } + + if (!sector.Fields.ContainsKey("user_managed_3d_floor")) + sector.Fields.Add("user_managed_3d_floor", new UniValue(UniversalType.Boolean, true)); + + sector.Fields["comment"] = new UniValue(UniversalType.String, "[!]DO NOT DELETE! This sector is managed by the 3D floor plugin."); + + // With multiple tag support in UDMF only one tag is needed, so bind it right away + if (General.Map.UDMF == true) + { + if(isnew) + udmftag = BuilderPlug.Me.ControlSectorArea.GetNewSectorTag(tagblacklist); + + BindTag(udmftag); + } + + // Snap to map format accuracy + General.Map.Map.SnapAllToAccuracy(); + + General.Map.Map.BeginAddRemove(); + //MapSet.JoinVertices(vertices, vertices, false, MapSet.STITCH_DISTANCE); + General.Map.Map.EndAddRemove(); + + // Update textures + General.Map.Data.UpdateUsedTextures(); + + // Update caches + General.Map.Map.Update(); + General.Interface.RedrawDisplay(); + General.Map.IsChanged = true; + + return true; + } + + public void Cleanup() + { + int taggedLines = 0; + + foreach (Sidedef sd in sector.Sidedefs) + { + if (sd.Line.Action == 160 && General.Map.Map.GetSectorsByTag(sd.Line.Args[0]).Count == 0) + { + sd.Line.Action = 0; + + for (int i = 0; i < 5; i++) + sd.Line.Args[i] = 0; + } + + if (sd.Line.Action != 0) + taggedLines++; + } + + if (taggedLines == 0) + { + DeleteControlSector(sector); + } + } + + private void DeleteControlSector(Sector sector) + { + if (sector == null) + return; + + General.Map.Map.BeginAddRemove(); + + // Get all the linedefs + List lines = new List(sector.Sidedefs.Count); + foreach (Sidedef side in sector.Sidedefs) lines.Add(side.Line); + + + // Dispose the sector + sector.Dispose(); + + // Check all the lines + for (int i = lines.Count - 1; i >= 0; i--) + { + // If the line has become orphaned, remove it + if ((lines[i].Front == null) && (lines[i].Back == null)) + { + // Remove line + lines[i].Dispose(); + } + else + { + // If the line only has a back side left, flip the line and sides + if ((lines[i].Front == null) && (lines[i].Back != null)) + { + lines[i].FlipVertices(); + lines[i].FlipSidedefs(); + } + + // Check textures. + if (lines[i].Front.MiddleRequired() && (lines[i].Front.MiddleTexture.Length == 0 || lines[i].Front.MiddleTexture == "-")) + { + if (lines[i].Front.HighTexture.Length > 0 && lines[i].Front.HighTexture != "-") + { + lines[i].Front.SetTextureMid(lines[i].Front.HighTexture); + } + else if (lines[i].Front.LowTexture.Length > 0 && lines[i].Front.LowTexture != "-") + { + lines[i].Front.SetTextureMid(lines[i].Front.LowTexture); + } + } + + // Do we still need high/low textures? + lines[i].Front.RemoveUnneededTextures(false); + + // Update sided flags + lines[i].ApplySidedFlags(); + } + } + + General.Map.Map.EndAddRemove(); + + // Update cache values + General.Map.IsChanged = true; + General.Map.Map.Update(); + + } + + public void DeleteControlSector() + { + DeleteControlSector(sector); + } + } +} diff --git a/Source/Plugins/3DFloorMode/ThreeDFloorMode.cs b/Source/Plugins/3DFloorMode/ThreeDFloorMode.cs new file mode 100644 index 00000000..3814af54 --- /dev/null +++ b/Source/Plugins/3DFloorMode/ThreeDFloorMode.cs @@ -0,0 +1,1380 @@ + +#region ================== Copyright (c) 2007 Pascal vd Heiden, 2014 Boris Iwanski + +/* + * Copyright (c) 2007 Pascal vd Heiden, www.codeimp.com + * Copyright (c) 2014 Boris Iwanski + * This program is released under GNU General Public License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#endregion + +#region ================== Namespaces + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.Text; +using System.Windows.Forms; +using System.IO; +using System.Reflection; +using System.Linq; +using System.Diagnostics; +using CodeImp.DoomBuilder.Windows; +using CodeImp.DoomBuilder.IO; +using CodeImp.DoomBuilder.Data; +using CodeImp.DoomBuilder.Map; +using CodeImp.DoomBuilder.Rendering; +using CodeImp.DoomBuilder.Geometry; +using CodeImp.DoomBuilder.Editing; +using System.Drawing; +using CodeImp.DoomBuilder.Actions; +using CodeImp.DoomBuilder.Types; +using CodeImp.DoomBuilder.BuilderModes; +using CodeImp.DoomBuilder.BuilderModes.Interface; +using CodeImp.DoomBuilder.Controls; +// using CodeImp.DoomBuilder.GZBuilder.Geometry; + +#endregion + +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + [EditMode(DisplayName = "3D Floor Mode", + SwitchAction = "threedfloorhelpermode", // Action name used to switch to this mode + ButtonImage = "ThreeDFloorIcon.png", // Image resource name for the button + ButtonOrder = int.MinValue + 501, // Position of the button (lower is more to the left) + ButtonGroup = "000_editing", + UseByDefault = true, + SafeStartMode = false, + Volatile = false)] + + public class ThreeDFloorHelperMode : ClassicMode + { + #region ================== Constants + + #endregion + + #region ================== Variables + + // Highlighted item + protected Sector highlighted; + protected ThreeDFloor highlighted3dfloor; + private Association highlightasso = new Association(); + private FlatVertex[] overlayGeometry; + private FlatVertex[] overlaygeometry3dfloors; + private FlatVertex[] overlaygeometry3dfloors_highlighted; + private FlatVertex[] overlaygeometry3dfloors_selected; + + // Interface + private ThreeDFloorPanel panel; + private Docker docker; + + // Labels + private Dictionary labels; + private Dictionary selected3Dfloorlabels; + private Dictionary unselected3Dfloorlabels; + + List tooltipelements; + + ControlSectorArea.Highlight csahighlight = ControlSectorArea.Highlight.None; + bool dragging = false; + + private List threedfloors; + + #endregion + + #region ================== Properties + + public override object HighlightedObject { get { return highlighted; } } + + #endregion + + #region ================== Constructor / Disposer + + // Constructor + public ThreeDFloorHelperMode() + { + threedfloors = BuilderPlug.GetThreeDFloors(General.Map.Map.Sectors.ToList()); + } + + // Disposer + public override void Dispose() + { + // Not already disposed? + if(!isdisposed) + { + // Dispose old labels + foreach(KeyValuePair lbl in labels) + foreach(TextLabel l in lbl.Value) l.Dispose(); + + // Dispose base + base.Dispose(); + } + } + + #endregion + + #region ================== Methods + + + + // This makes a CRC for the selection + public int CreateSelectionCRC() + { + CRC crc = new CRC(); + ICollection orderedselection = General.Map.Map.GetSelectedSectors(true); + crc.Add(orderedselection.Count); + foreach(Sector s in orderedselection) + { + crc.Add(s.FixedIndex); + } + return (int)(crc.Value & 0xFFFFFFFF); + } + + // This sets up new labels + private void SetupLabels() + { + if(labels != null) + { + // Dispose old labels + foreach(KeyValuePair lbl in labels) + foreach(TextLabel l in lbl.Value) l.Dispose(); + } + + // Make text labels for sectors + labels = new Dictionary(General.Map.Map.Sectors.Count); + foreach(Sector s in General.Map.Map.Sectors) + { + // Setup labels + TextLabel[] labelarray = new TextLabel[s.Labels.Count]; + for(int i = 0; i < s.Labels.Count; i++) + { + labelarray[i] = new TextLabel(); + labelarray[i].TransformCoords = true; + labelarray[i].Location = s.Labels[i].position; + labelarray[i].AlignX = TextAlignmentX.Center; + labelarray[i].AlignY = TextAlignmentY.Middle; + labelarray[i].Color = General.Colors.Highlight.WithAlpha(255); + labelarray[i].BackColor = General.Colors.Background.WithAlpha(128); + } + labels.Add(s, labelarray); + } + } + + // This updates the overlay + private void UpdateOverlay() + { + if(renderer.StartOverlay(true)) + { + if (BuilderPlug.Me.UseHighlight) + { + renderer.RenderHighlight(overlayGeometry, General.Colors.Selection.WithAlpha(64).ToInt()); + } + + if (BuilderPlug.Me.UseHighlight && highlighted != null) + { + renderer.RenderHighlight(highlighted.FlatVertices, General.Colors.Highlight.WithAlpha(64).ToInt()); + + if (highlighted3dfloor != null) + { + renderer.RenderHighlight(overlaygeometry3dfloors, General.Colors.ModelWireframe.WithAlpha(64).ToInt()); + + //show the selected sectors in a darker shade + PixelColor darker = General.Colors.ModelWireframe; + darker.r = (byte)(darker.r * 0.5); + darker.g = (byte)(darker.g * 0.5); + darker.b = (byte)(darker.b * 0.5); + renderer.RenderHighlight(overlaygeometry3dfloors_selected, darker.WithAlpha(64).ToInt()); + + //show the highlighted sectors in a lighter shade + PixelColor lighter = General.Colors.ModelWireframe; + lighter.r = (byte)(lighter.r + (0.5 * (255 - lighter.r))); + lighter.g = (byte)(lighter.g + (0.5 * (255 - lighter.g))); + lighter.b = (byte)(lighter.b + (0.5 * (255 - lighter.b))); + renderer.RenderHighlight(overlaygeometry3dfloors_highlighted, lighter.WithAlpha(64).ToInt()); + } + } + + if (BuilderModes.BuilderPlug.Me.ViewSelectionNumbers) + { + // Go for all selected sectors + ICollection orderedselection = General.Map.Map.GetSelectedSectors(true); + foreach(Sector s in orderedselection) + { + // Render labels + TextLabel[] labelarray = labels[s]; + for(int i = 0; i < s.Labels.Count; i++) + { + TextLabel l = labelarray[i]; + + // Render only when enough space for the label to see + float requiredsize = (l.TextSize.Height / 2) / renderer.Scale; + if(requiredsize < s.Labels[i].radius) renderer.RenderText(l); + } + } + } + + Render3DFloorLabels(unselected3Dfloorlabels); + + if (!BuilderModes.BuilderPlug.Me.ViewSelectionNumbers) + Render3DFloorLabels(selected3Dfloorlabels); + + BuilderPlug.Me.ControlSectorArea.Draw(renderer, csahighlight); + + renderer.Finish(); + } + } + + private void Render3DFloorLabels(Dictionary labelsgroup) + { + foreach (KeyValuePair group in labelsgroup) + { + // Render labels + TextLabel[] labelarray = labels[group.Key]; + for (int i = 0; i < group.Key.Labels.Count; i++) + { + TextLabel l = labelarray[i]; + l.Color = General.Colors.InfoLine; + + // Render only when enough space for the label to see + float requiredsize = (General.Interface.MeasureString(group.Value[0], l.Font).Width / 2) / renderer.Scale; + + if (requiredsize > group.Key.Labels[i].radius) + { + l.Text = group.Value[1]; + } + else + { + l.Text = group.Value[0]; + } + + renderer.RenderText(l); + } + } + } + + // Generates the tooltip for the 3D floors + private void UpdateDocker(Sector s) + { + List tdfs = new List(); + int count = 0; + + // Get all 3D floors that have the currently highlighted sector tagged. Also order them by their vertical position + foreach (ThreeDFloor tdf in threedfloors.Where(o => o.TaggedSectors.Contains(s)).OrderByDescending(o => o.TopHeight)) + tdfs.Add(tdf); + + // Hide all controls if no sector is selected or selected sector has no 3D floors + if (s == null || tdfs.Count == 0) + { + foreach (Control c in tooltipelements) + { + c.Visible = false; + } + + return; + } + + foreach (ThreeDFloor tdf in tdfs) + { + // Add another control if the list if full + if (count >= tooltipelements.Count) + { + var tte = new ThreeDFloorHelperTooltipElementControl(); + panel.flowLayoutPanel1.Controls.Add(tte); + tooltipelements.Add(tte); + } + + General.DisplayZoomedImage(tooltipelements[count].sectorBottomFlat, General.Map.Data.GetFlatImage(tdf.BottomFlat).GetPreview()); + General.DisplayZoomedImage(tooltipelements[count].sectorBorderTexture, General.Map.Data.GetFlatImage(tdf.BorderTexture).GetPreview()); + General.DisplayZoomedImage(tooltipelements[count].sectorTopFlat, General.Map.Data.GetFlatImage(tdf.TopFlat).GetPreview()); + + tooltipelements[count].bottomHeight.Text = tdf.BottomHeight.ToString(); + tooltipelements[count].topHeight.Text = tdf.TopHeight.ToString(); + tooltipelements[count].borderHeight.Text = (tdf.TopHeight - tdf.BottomHeight).ToString(); + + if (tdf == highlighted3dfloor) + // tooltipelements[count].BackColor = General.Colors.ModelWireframe.ToColor(); + tooltipelements[count].Highlighted = true; + else + // tooltipelements[count].BackColor = SystemColors.Control; + tooltipelements[count].Highlighted = false; + + tooltipelements[count].Refresh(); + tooltipelements[count].Visible = true; + + count++; + } + + // Hide superfluous controls + for (; count < tooltipelements.Count; count++) + { + tooltipelements[count].Visible = false; + } + } + + private void updateOverlaySurfaces() + { + ICollection orderedselection = General.Map.Map.GetSelectedSectors(true); + List vertsList = new List(); + List vertsList_highlighted = new List(); + List vertsList_selected = new List(); + + // Go for all selected sectors + foreach (Sector s in orderedselection) vertsList.AddRange(s.FlatVertices); + overlayGeometry = vertsList.ToArray(); + + if (highlighted3dfloor != null) + { + vertsList = new List(); + vertsList_highlighted = new List(); + vertsList_selected = new List(); + + foreach (Sector s in highlighted3dfloor.TaggedSectors) + { + //bin the verticies so that then can be properly colored + if (s == highlighted) + vertsList_highlighted.AddRange(s.FlatVertices); + else if (s.Selected) + vertsList_selected.AddRange(s.FlatVertices); + else + vertsList.AddRange(s.FlatVertices); + } + + overlaygeometry3dfloors = vertsList.ToArray(); + overlaygeometry3dfloors_highlighted = vertsList_highlighted.ToArray(); + overlaygeometry3dfloors_selected = vertsList_selected.ToArray(); + } + } + + // Support function for joining and merging sectors + private void JoinMergeSectors(bool removelines) + { + // Remove lines in betwen joining sectors? + if(removelines) + { + // Go for all selected linedefs + List selectedlines = new List(General.Map.Map.GetSelectedLinedefs(true)); + foreach(Linedef ld in selectedlines) + { + // Front and back side? + if((ld.Front != null) && (ld.Back != null)) + { + // Both a selected sector, but not the same? + if(ld.Front.Sector.Selected && ld.Back.Sector.Selected && + (ld.Front.Sector != ld.Back.Sector)) + { + // Remove this line + ld.Dispose(); + } + } + } + } + + // Find the first sector that is not disposed + List orderedselection = new List(General.Map.Map.GetSelectedSectors(true)); + Sector first = null; + foreach(Sector s in orderedselection) + if(!s.IsDisposed) { first = s; break; } + + // Join all selected sectors with the first + for(int i = 0; i < orderedselection.Count; i++) + if((orderedselection[i] != first) && !orderedselection[i].IsDisposed) + orderedselection[i].Join(first); + + // Clear selection + General.Map.Map.ClearAllSelected(); + + // Update + General.Map.Map.Update(); + + // Make text labels for sectors + SetupLabels(); + UpdateLabels(); + } + + // This highlights a new item + protected void Highlight(Sector s) + { + bool completeredraw = false; + + // Often we can get away by simply undrawing the previous + // highlight and drawing the new highlight. But if associations + // are or were drawn we need to redraw the entire display. + + // Previous association highlights something? + if((highlighted != null) && (highlighted.Tag > 0)) completeredraw = true; + + // Set highlight association + if (s != null) + { + Vector2D center = (s.Labels.Count > 0 ? s.Labels[0].position : new Vector2D(s.BBox.X + s.BBox.Width / 2, s.BBox.Y + s.BBox.Height / 2)); + highlightasso.Set(center, s.Tag, UniversalType.SectorTag); + } + else + highlightasso.Set(new Vector2D(), 0, 0); + + // New association highlights something? + if((s != null) && (s.Tag > 0)) completeredraw = true; + + // Change label color + if((highlighted != null) && !highlighted.IsDisposed) + { + TextLabel[] labelarray = labels[highlighted]; + foreach(TextLabel l in labelarray) l.Color = General.Colors.Selection; + } + + // Change label color + if((s != null) && !s.IsDisposed) + { + TextLabel[] labelarray = labels[s]; + foreach(TextLabel l in labelarray) l.Color = General.Colors.Highlight; + } + + // If we're changing associations, then we + // need to redraw the entire display + if(completeredraw) + { + // Set new highlight and redraw completely + highlighted = s; + highlighted3dfloor = null; + General.Interface.RedrawDisplay(); + } + else + { + // Update display + if(renderer.StartPlotter(false)) + { + // Undraw previous highlight + if((highlighted != null) && !highlighted.IsDisposed) + renderer.PlotSector(highlighted); + + // Set new highlight + highlighted = s; + + // Render highlighted item + if((highlighted != null) && !highlighted.IsDisposed) + renderer.PlotSector(highlighted, General.Colors.Highlight); + + // Done + renderer.Finish(); + } + + UpdateOverlay(); + renderer.Present(); + } + + // Update the panel with the 3D floors + UpdateDocker(s); + + // Show highlight info + if((highlighted != null) && !highlighted.IsDisposed) + General.Interface.ShowSectorInfo(highlighted); + else + General.Interface.HideInfo(); + } + + // This selectes or deselects a sector + protected void SelectSector(Sector s, bool selectstate, bool update) + { + bool selectionchanged = false; + + if(!s.IsDisposed) + { + // Select the sector? + if(selectstate && !s.Selected) + { + s.Selected = true; + selectionchanged = true; + + // Setup labels + ICollection orderedselection = General.Map.Map.GetSelectedSectors(true); + TextLabel[] labelarray = labels[s]; + foreach(TextLabel l in labelarray) + { + l.Text = orderedselection.Count.ToString(); + l.Color = General.Colors.Selection; + } + } + // Deselect the sector? + else if(!selectstate && s.Selected) + { + s.Selected = false; + selectionchanged = true; + + // Clear labels + TextLabel[] labelarray = labels[s]; + foreach(TextLabel l in labelarray) l.Text = ""; + } + + // Selection changed? + if(selectionchanged) + { + // Make update lines selection + foreach(Sidedef sd in s.Sidedefs) + { + bool front, back; + if(sd.Line.Front != null) front = sd.Line.Front.Sector.Selected; else front = false; + if(sd.Line.Back != null) back = sd.Line.Back.Sector.Selected; else back = false; + sd.Line.Selected = front | back; + } + + // Update all other labels + UpdateLabels(); + } + + if(update) + { + UpdateOverlay(); + renderer.Present(); + } + } + } + + private void UpdateLabels() + { + Update3DFloorLabels(); + + if (BuilderModes.BuilderPlug.Me.ViewSelectionNumbers) + UpdateSelectedLabels(); + } + + // This updates labels from the selected sectors + private void UpdateSelectedLabels() + { + // Go for all labels in all selected sectors + ICollection orderedselection = General.Map.Map.GetSelectedSectors(true); + int index = 0; + foreach(Sector s in orderedselection) + { + TextLabel[] labelarray = labels[s]; + foreach(TextLabel l in labelarray) + { + // Make sure the text and color are right + int labelnum = index + 1; + l.Text = labelnum.ToString(); + l.Color = General.Colors.Selection; + } + index++; + } + } + + // Update labels for 3D floors + private void Update3DFloorLabels() + { + Dictionary num3dfloors = new Dictionary(); + selected3Dfloorlabels = new Dictionary(); + unselected3Dfloorlabels = new Dictionary(); + + foreach (ThreeDFloor tdf in threedfloors) + { + foreach (Sector s in tdf.TaggedSectors) + { + if (num3dfloors.ContainsKey(s)) + num3dfloors[s]++; + else + num3dfloors.Add(s, 1); + } + } + + foreach (KeyValuePair group in num3dfloors) + { + if (group.Key.Selected) + selected3Dfloorlabels.Add(group.Key, new string[] { group.Value + (group.Value == 1 ? " floor" : " floors"), group.Value.ToString() }); + else + unselected3Dfloorlabels.Add(group.Key, new string[] { group.Value + (group.Value == 1 ? " floor" : " floors"), group.Value.ToString() }); + } + + /* + foreach (Sector s in General.Map.Map.GetSelectedSectors(true)) + { + List tdfs = BuilderPlug.GetThreeDFloors(new List { s }); + + if (tdfs.Count == 0) + selected3Dfloorlabels.Add(s, new string[] { "", "" }); + else + selected3Dfloorlabels.Add(s, new string[] { tdfs.Count + (tdfs.Count == 1 ? " floor" : " floors"), tdfs.Count.ToString() }); + } + + foreach (Sector s in General.Map.Map.GetSelectedSectors(false)) + { + List tdfs = BuilderPlug.GetThreeDFloors(new List { s }); + + if (tdfs.Count == 0) + unselected3Dfloorlabels.Add(s, new string[] { "", "" }); + else + unselected3Dfloorlabels.Add(s, new string[] { tdfs.Count + (tdfs.Count == 1 ? " floor" : " floors"), tdfs.Count.ToString() }); + } + */ + } + + #endregion + + #region ================== Events + + public override void OnHelp() + { + General.ShowHelp("e_sectors.html"); + } + + // Cancel mode + public override void OnCancel() + { + base.OnCancel(); + + // Return to this mode + General.Editing.ChangeMode(new SectorsMode()); + } + + // Mode engages + public override void OnEngage() + { + base.OnEngage(); + + renderer.SetPresentation(Presentation.Standard); + + tooltipelements = new List(); + + // Add docker + panel = new ThreeDFloorPanel(); + docker = new Docker("threedfloorhelper", "3D floors", panel); + General.Interface.AddDocker(docker); + General.Interface.SelectDocker(docker); + + // Add the view selection number button from BuilderModes. Also add a click event handler + // so we can update the labels when the button is pressed + General.Interface.AddButton(BuilderModes.BuilderPlug.Me.MenusForm.ViewSelectionNumbers); + BuilderModes.BuilderPlug.Me.MenusForm.ViewSelectionNumbers.Click += ViewSelectionNumbers_Click; + + General.Interface.AddButton(BuilderPlug.Me.MenusForm.RelocateControlSectors); + + // Convert geometry selection to sectors only + General.Map.Map.ConvertSelection(SelectionType.Sectors); + + // Make text labels for sectors + SetupLabels(); + + // Update + UpdateLabels(); + updateOverlaySurfaces(); + UpdateOverlay(); + } + + void ViewSelectionNumbers_Click(object sender, EventArgs e) + { + UpdateLabels(); + + OnRedrawDisplay(); + } + + // Mode disengages + public override void OnDisengage() + { + base.OnDisengage(); + + // Remove docker + General.Interface.RemoveDocker(docker); + + // Remove the button and event handler for view selection numbers + General.Interface.RemoveButton(BuilderModes.BuilderPlug.Me.MenusForm.ViewSelectionNumbers); + BuilderModes.BuilderPlug.Me.MenusForm.ViewSelectionNumbers.Click -= ViewSelectionNumbers_Click; + + General.Interface.RemoveButton(BuilderPlug.Me.MenusForm.RelocateControlSectors); + + // Keep only sectors selected + General.Map.Map.ClearSelectedLinedefs(); + + // Going to EditSelectionMode? + if(General.Editing.NewMode is EditSelectionMode) + { + // Not pasting anything? + EditSelectionMode editmode = (General.Editing.NewMode as EditSelectionMode); + if(!editmode.Pasting) + { + // No selection made? But we have a highlight! + if((General.Map.Map.GetSelectedSectors(true).Count == 0) && (highlighted != null)) + { + // Make the highlight the selection + SelectSector(highlighted, true, false); + } + } + } + + BuilderPlug.Me.ControlSectorArea.SaveConfig(); + + // Hide highlight info + General.Interface.HideInfo(); + } + + // This redraws the display + public override void OnRedrawDisplay() + { + renderer.RedrawSurface(); + + // Render lines and vertices + if(renderer.StartPlotter(true)) + { + renderer.PlotLinedefSet(General.Map.Map.Linedefs); + renderer.PlotVerticesSet(General.Map.Map.Vertices); + if((highlighted != null) && !highlighted.IsDisposed) + { + renderer.PlotSector(highlighted, General.Colors.Highlight); + // BuilderPlug.Me.PlotReverseAssociations(renderer, highlightasso); + } + + renderer.Finish(); + } + + // Render things + if(renderer.StartThings(true)) + { + renderer.RenderThingSet(General.Map.ThingsFilter.HiddenThings, Presentation.THINGS_HIDDEN_ALPHA); + renderer.RenderThingSet(General.Map.ThingsFilter.VisibleThings, 1.0f); + renderer.Finish(); + } + + // Render selection + if(renderer.StartOverlay(true)) + { + + // if((highlighted != null) && !highlighted.IsDisposed) BuilderPlug.Me.RenderReverseAssociations(renderer, highlightasso); + if(selecting) RenderMultiSelection(); + + renderer.Finish(); + } + + // Render overlay + UpdateOverlay(); + + renderer.Present(); + } + + // Selection + protected override void OnSelectBegin() + { + // Item highlighted? + if((highlighted != null) && !highlighted.IsDisposed) + { + // Flip selection + SelectSector(highlighted, !highlighted.Selected, true); + + // Update display + if(renderer.StartPlotter(false)) + { + // Redraw highlight to show selection + renderer.PlotSector(highlighted); + renderer.Finish(); + renderer.Present(); + } + } + + base.OnSelectBegin(); + } + + // End selection + protected override void OnSelectEnd() + { + // Not stopping from multiselection? + if(!selecting) + { + // Item highlighted? + if((highlighted != null) && !highlighted.IsDisposed) + { + // Update display + if(renderer.StartPlotter(false)) + { + // Render highlighted item + renderer.PlotSector(highlighted, General.Colors.Highlight); + renderer.Finish(); + renderer.Present(); + } + + // Update overlay + TextLabel[] labelarray = labels[highlighted]; + foreach(TextLabel l in labelarray) l.Color = General.Colors.Highlight; + updateOverlaySurfaces(); + UpdateOverlay(); + renderer.Present(); + } + } + + base.OnSelectEnd(); + } + + // Start editing + protected override void OnEditBegin() + { + // Item highlighted? + if (((highlighted != null) && !highlighted.IsDisposed) || csahighlight == ControlSectorArea.Highlight.Body) + { + // Edit pressed in this mode + editpressed = true; + + if (csahighlight != ControlSectorArea.Highlight.Body) + { + // Highlighted item not selected? + if (!highlighted.Selected && (BuilderPlug.Me.AutoClearSelection || (General.Map.Map.SelectedSectorsCount == 0))) + { + // Make this the only selection + General.Map.Map.ClearSelectedSectors(); + General.Map.Map.ClearSelectedLinedefs(); + SelectSector(highlighted, true, false); + updateOverlaySurfaces(); + General.Interface.RedrawDisplay(); + } + + // Update display + if (renderer.StartPlotter(false)) + { + // Redraw highlight to show selection + renderer.PlotSector(highlighted); + renderer.Finish(); + renderer.Present(); + } + } + } + + base.OnEditBegin(); + } + + // Done editing + protected override void OnEditEnd() + { + // Edit pressed in this mode? + if(editpressed && !dragging) + { + if (csahighlight == ControlSectorArea.Highlight.Body) + { + BuilderPlug.Me.ControlSectorArea.Edit(); + } + else + { + // Anything selected? + ICollection selected = General.Map.Map.GetSelectedSectors(true); + if (selected.Count > 0) + { + if (General.Interface.IsActiveWindow) + { + // Show sector edit dialog + // General.Interface.ShowEditSectors(selected); + DialogResult result = BuilderPlug.Me.ThreeDFloorEditor(); + + if (result == DialogResult.OK) + { + BuilderPlug.ProcessThreeDFloors(BuilderPlug.TDFEW.ThreeDFloors); + General.Map.Map.Update(); + + threedfloors = BuilderPlug.GetThreeDFloors(General.Map.Map.Sectors.ToList()); + } + + // When a single sector was selected, deselect it now + if (selected.Count == 1) + { + General.Map.Map.ClearSelectedSectors(); + General.Map.Map.ClearSelectedLinedefs(); + } + + SetupLabels(); + UpdateLabels(); + + // Update entire display + updateOverlaySurfaces(); + UpdateOverlay(); + General.Interface.RedrawDisplay(); + } + } + } + } + + editpressed = false; + base.OnEditEnd(); + } + + // Mouse moves + public override void OnMouseMove(MouseEventArgs e) + { + base.OnMouseMove(e); + + if (selectpressed && !editpressed && !selecting) + { + // Check if moved enough pixels for multiselect + Vector2D delta = mousedownpos - mousepos; + if ((Math.Abs(delta.x) > 2) || (Math.Abs(delta.y) > 2)) + { + // Start multiselecting + StartMultiSelection(); + } + } + else if (e.Button == MouseButtons.None) + { + csahighlight = BuilderPlug.Me.ControlSectorArea.CheckHighlight(mousemappos, renderer.Scale); + + if (csahighlight != ControlSectorArea.Highlight.None) + { + switch (csahighlight) + { + case ControlSectorArea.Highlight.OuterTop: + case ControlSectorArea.Highlight.OuterBottom: + General.Interface.SetCursor(Cursors.SizeNS); + break; + case ControlSectorArea.Highlight.OuterLeft: + case ControlSectorArea.Highlight.OuterRight: + General.Interface.SetCursor(Cursors.SizeWE); + break; + case ControlSectorArea.Highlight.OuterTopLeft: + case ControlSectorArea.Highlight.OuterBottomRight: + General.Interface.SetCursor(Cursors.SizeNWSE); + break; + case ControlSectorArea.Highlight.OuterTopRight: + case ControlSectorArea.Highlight.OuterBottomLeft: + General.Interface.SetCursor(Cursors.SizeNESW); + break; + case ControlSectorArea.Highlight.Body: + General.Interface.SetCursor(Cursors.Hand); + break; + } + + Highlight(null); + return; + } + + General.Interface.SetCursor(Cursors.Default); + + // Find the nearest linedef within highlight range + Linedef l = General.Map.Map.NearestLinedef(mousemappos); + if (l != null) + { + // Check on which side of the linedef the mouse is + float side = l.SideOfLine(mousemappos); + if (side > 0) + { + // Is there a sidedef here? + if (l.Back != null) + { + // Highlight if not the same + if (l.Back.Sector != highlighted) Highlight(l.Back.Sector); + } + else + { + // Highlight nothing + Highlight(null); + } + } + else + { + // Is there a sidedef here? + if (l.Front != null) + { + // Highlight if not the same + if (l.Front.Sector != highlighted) Highlight(l.Front.Sector); + } + else + { + // Highlight nothing + Highlight(null); + } + } + } + else + { + // Highlight nothing + Highlight(null); + } + } + else if (dragging && csahighlight != ControlSectorArea.Highlight.None) + { + BuilderPlug.Me.ControlSectorArea.SnapToGrid(csahighlight, mousemappos, renderer.DisplayToMap(mouselastpos)); + Highlight(null); + } + } + + // Mouse leaves + public override void OnMouseLeave(EventArgs e) + { + base.OnMouseLeave(e); + + // Highlight nothing + Highlight(null); + } + + // Mouse wants to drag + protected override void OnDragStart(MouseEventArgs e) + { + base.OnDragStart(e); + + if(e.Button == MouseButtons.Right) + dragging = true; + + } + + protected override void OnDragStop(MouseEventArgs e) + { + dragging = false; + + BuilderPlug.Me.ControlSectorArea.SaveConfig(); + } + + // This is called wheh selection ends + protected override void OnEndMultiSelection() + { + bool selectionvolume = ((Math.Abs(base.selectionrect.Width) > 0.1f) && (Math.Abs(base.selectionrect.Height) > 0.1f)); + + if(BuilderPlug.Me.AutoClearSelection && !selectionvolume) + { + General.Map.Map.ClearSelectedLinedefs(); + General.Map.Map.ClearSelectedSectors(); + } + + if(selectionvolume) + { + if(General.Interface.ShiftState ^ BuilderPlug.Me.AdditiveSelect) + { + // Go for all lines + foreach(Linedef l in General.Map.Map.Linedefs) + { + l.Selected |= ((l.Start.Position.x >= selectionrect.Left) && + (l.Start.Position.y >= selectionrect.Top) && + (l.Start.Position.x <= selectionrect.Right) && + (l.Start.Position.y <= selectionrect.Bottom) && + (l.End.Position.x >= selectionrect.Left) && + (l.End.Position.y >= selectionrect.Top) && + (l.End.Position.x <= selectionrect.Right) && + (l.End.Position.y <= selectionrect.Bottom)); + } + } + else + { + // Go for all lines + foreach(Linedef l in General.Map.Map.Linedefs) + { + l.Selected = ((l.Start.Position.x >= selectionrect.Left) && + (l.Start.Position.y >= selectionrect.Top) && + (l.Start.Position.x <= selectionrect.Right) && + (l.Start.Position.y <= selectionrect.Bottom) && + (l.End.Position.x >= selectionrect.Left) && + (l.End.Position.y >= selectionrect.Top) && + (l.End.Position.x <= selectionrect.Right) && + (l.End.Position.y <= selectionrect.Bottom)); + } + } + + // Go for all sectors + foreach(Sector s in General.Map.Map.Sectors) + { + // Go for all sidedefs + bool allselected = true; + foreach(Sidedef sd in s.Sidedefs) + { + if(!sd.Line.Selected) + { + allselected = false; + break; + } + } + + // Sector completely selected? + SelectSector(s, allselected, false); + } + + // Make sure all linedefs reflect selected sectors + foreach(Sidedef sd in General.Map.Map.Sidedefs) + if(!sd.Sector.Selected && ((sd.Other == null) || !sd.Other.Sector.Selected)) + sd.Line.Selected = false; + + updateOverlaySurfaces(); + } + + base.OnEndMultiSelection(); + if(renderer.StartOverlay(true)) renderer.Finish(); + General.Interface.RedrawDisplay(); + } + + // This is called when the selection is updated + protected override void OnUpdateMultiSelection() + { + base.OnUpdateMultiSelection(); + + // Render selection + if(renderer.StartOverlay(true)) + { + RenderMultiSelection(); + renderer.Finish(); + renderer.Present(); + } + } + + // When copying + public override bool OnCopyBegin() + { + // No selection made? But we have a highlight! + if((General.Map.Map.GetSelectedSectors(true).Count == 0) && (highlighted != null)) + { + // Make the highlight the selection + SelectSector(highlighted, true, true); + } + + return base.OnCopyBegin(); + } + + // When undo is used + public override bool OnUndoBegin() + { + // Clear ordered selection + General.Map.Map.ClearAllSelected(); + + return base.OnUndoBegin(); + } + + // When undo is performed + public override void OnUndoEnd() + { + // Get all 3D floors in case th undo did affect them + threedfloors = BuilderPlug.GetThreeDFloors(General.Map.Map.Sectors.ToList()); + + // Clear labels + SetupLabels(); + UpdateLabels(); + } + + // When redo is used + public override bool OnRedoBegin() + { + // Clear ordered selection + General.Map.Map.ClearAllSelected(); + + return base.OnRedoBegin(); + } + + // When redo is performed + public override void OnRedoEnd() + { + // Get all 3D floors in case th redo did affect them + threedfloors = BuilderPlug.GetThreeDFloors(General.Map.Map.Sectors.ToList()); + + // Clear labels + SetupLabels(); + UpdateLabels(); + } + + #endregion + + #region ================== Actions + + // This clears the selection + [BeginAction("clearselection", BaseAction = true)] + public void ClearSelection() + { + // Clear selection + General.Map.Map.ClearAllSelected(); + + // Clear labels + foreach (TextLabel[] labelarray in labels.Values) + foreach (TextLabel l in labelarray) l.Text = ""; + + SetupLabels(); + UpdateLabels(); + + updateOverlaySurfaces(); + + // Redraw + General.Interface.RedrawDisplay(); + } + + [BeginAction("cyclehighlighted3dfloorup")] + public void CycleHighlighted3DFloorUp() + { + if (highlighted == null) + return; + + List tdfs = new List(); + + // Get all 3D floors that have the currently highlighted sector tagged. Also order them by their vertical position + foreach (ThreeDFloor tdf in threedfloors.Where(o => o.TaggedSectors.Contains(highlighted)).OrderByDescending(o => o.TopHeight)) + tdfs.Add(tdf); + + if (tdfs.Count == 0) // Nothing to highlight + { + highlighted3dfloor = null; + } + else if (highlighted3dfloor == null) // No 3D floor currently highlighted? Just get the last one + { + highlighted3dfloor = tdfs.Last(); + } + else // Find the currently highlighted 3D floor in the list and take the next one + { + int i; + + for (i = tdfs.Count-1; i >= 0; i--) + { + if (tdfs[i] == highlighted3dfloor) + { + if (i > 0) + { + highlighted3dfloor = tdfs[i - 1]; + break; + } + } + } + + // Beginning of the list was reached, so don't highlight any 3D floor + if (i < 0) + highlighted3dfloor = null; + } + + UpdateDocker(highlighted); + + updateOverlaySurfaces(); + + General.Interface.RedrawDisplay(); + + } + + [BeginAction("cyclehighlighted3dfloordown")] + public void CycleHighlighted3DFloorDown() + { + if (highlighted == null) + return; + + List tdfs = new List(); + + // Get all 3D floors that have the currently highlighted sector tagged. Also order them by their vertical position + foreach (ThreeDFloor tdf in threedfloors.Where(o => o.TaggedSectors.Contains(highlighted)).OrderByDescending(o => o.TopHeight)) + tdfs.Add(tdf); + + if (tdfs.Count == 0) // Nothing to highlight + { + highlighted3dfloor = null; + } + else if (highlighted3dfloor == null) // No 3D floor currently highlighted? Just get the first one + { + highlighted3dfloor = tdfs[0]; + } + else // Find the currently highlighted 3D floor in the list and take the next one + { + int i; + + for (i = 0; i < tdfs.Count; i++) + { + if (tdfs[i] == highlighted3dfloor) + { + if (i < tdfs.Count-1) + { + highlighted3dfloor = tdfs[i + 1]; + break; + } + } + } + + // End of the list was reached, so don't highlight any 3D floor + if (i == tdfs.Count) + highlighted3dfloor = null; + } + + UpdateDocker(highlighted); + + updateOverlaySurfaces(); + + General.Interface.RedrawDisplay(); + } + + [BeginAction("relocate3dfloorcontrolsectors")] + public void RelocateControlSectors() + { + List positions; + + if (threedfloors.Count == 0) + { + General.Interface.DisplayStatus(StatusType.Warning, "There are no control sectors to relocate"); + return; + } + + try + { + positions = BuilderPlug.Me.ControlSectorArea.GetRelocatePositions(threedfloors.Count); + } + catch (Exception e) + { + General.Interface.DisplayStatus(StatusType.Warning, e.Message + ". Please increase the size of the control sector area"); + return; + } + + // Some sanity checks + if (positions.Count != threedfloors.Count) + { + General.Interface.DisplayStatus(StatusType.Warning, "Mismatch between number of relocation points and control sectors. Aborted"); + return; + } + + // Control sectors are not allowed to be bigger than what the CSA expects, otherwise sectors might overlap + // Abort relocation if one of the control sectors is too big (that should only happen if the user edited the + // sector manually + foreach (ThreeDFloor tdf in threedfloors) + { + if (tdf.Sector.BBox.Width > BuilderPlug.Me.ControlSectorArea.SectorSize || tdf.Sector.BBox.Height > BuilderPlug.Me.ControlSectorArea.SectorSize) + { + General.Interface.DisplayStatus(StatusType.Warning, string.Format("Control sector {0} exceeds horizontal or vertical dimenstion of {1}. Aborted", tdf.Sector.Index, BuilderPlug.Me.ControlSectorArea.SectorSize)); + return; + } + } + + General.Map.UndoRedo.CreateUndo("Relocate 3D floor control sectors"); + + // Counter for the new positions + int i = 0; + + // Move the control sectors + foreach (ThreeDFloor tdf in threedfloors) + { + Vector2D offset = new Vector2D(tdf.Sector.BBox.Left - positions[i].x, tdf.Sector.BBox.Bottom - positions[i].y); + HashSet vertices = new HashSet(); + + // Get all vertices + foreach (Sidedef sd in tdf.Sector.Sidedefs) + { + vertices.Add(sd.Line.Start); + vertices.Add(sd.Line.End); + } + + foreach (Vertex v in vertices) + v.Move(v.Position - offset); + + i++; + } + + General.Map.Map.Update(); + General.Interface.RedrawDisplay(); + } + + [BeginAction("select3dfloorcontrolsector")] + public void Select3DFloorControlSector() + { + //if there is no 3d floor highlighted, then try to select the first one from the top-down, if possible + if (highlighted3dfloor == null) + { + CycleHighlighted3DFloorDown(); + } + + if (highlighted3dfloor == null) + { + General.Interface.DisplayStatus(StatusType.Warning, "You have to highlight a 3D floor to select its control sector"); + return; + } + + SelectSector(highlighted3dfloor.Sector, true, true); + + updateOverlaySurfaces(); + + General.Interface.RedrawDisplay(); + + General.Interface.DisplayStatus(StatusType.Info, String.Format("3D floor control sector selected. {0} sector(s) selected.", General.Map.Map.GetSelectedSectors(true).Count)); + } + + #endregion + } +} diff --git a/Source/Plugins/3DFloorMode/ThreeDFloorMode.csproj b/Source/Plugins/3DFloorMode/ThreeDFloorMode.csproj new file mode 100644 index 00000000..dadcd62c --- /dev/null +++ b/Source/Plugins/3DFloorMode/ThreeDFloorMode.csproj @@ -0,0 +1,259 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {88CFD996-027B-4CBE-9828-26B2728B6127} + Library + Properties + ThreeDFloorMode + ThreeDFloorMode + v4.6.1 + 512 + + + + + 3.5 + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + + true + full + false + ..\..\..\Build\Plugins\ + DEBUG;TRACE + prompt + 4 + false + + + pdbonly + true + ..\..\..\Build\Plugins\ + TRACE + prompt + 4 + false + + + true + ..\..\..\Build\Plugins\ + DEBUG;TRACE + full + x86 + prompt + false + + + ..\..\..\Build\Plugins\ + TRACE + true + pdbonly + x86 + prompt + false + + + true + ..\..\..\Build\Plugins\ + DEBUG;TRACE + full + x64 + prompt + MinimumRecommendedRules.ruleset + + + ..\..\..\Build\Plugins\ + TRACE + true + pdbonly + x64 + prompt + MinimumRecommendedRules.ruleset + + + + + 3.5 + + + + + 3.5 + + + 3.5 + + + + + + + + + UserControl + + + ThreeDFloorTooltipControl.cs + + + + Form + + + PreferencesForm.cs + + + UserControl + + + ThreeDFloorPanel.cs + + + + UserControl + + + ThreeDFloorControl.cs + + + True + True + Resources.resx + + + + + + + + + Form + + + ControlSectorAreaConfig.cs + + + Form + + + MenusForm.cs + + + Form + + + SlopeDataSectorDialog.cs + + + Form + + + SlopeVertexEditForm.cs + + + Form + + + ThreeDFloorEditorWindow.cs + + + + + ThreeDFloorControl.cs + + + + + PreferencesForm.cs + + + + ThreeDFloorEditorWindow.cs + + + + + ThreeDFloorTooltipControl.cs + + + ThreeDFloorPanel.cs + + + + ControlSectorAreaConfig.cs + + + SlopeVertexEditForm.cs + + + + + + + + + MenusForm.cs + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + + SlopeDataSectorDialog.cs + + + + + False + .NET Framework 3.5 SP1 + true + + + + + {818b3d10-f791-4c3f-9af5-bb2d0079b63c} + Builder + False + + + {b859be0f-a992-476d-a642-fa8efe94aaa5} + BuilderEffects + + + {b42d5aa0-f9a6-4234-9c4b-a05b11a64851} + BuilderModes + + + + + \ No newline at end of file diff --git a/Source/Plugins/3DFloorMode/Windows/ControlSectorAreaConfig.Designer.cs b/Source/Plugins/3DFloorMode/Windows/ControlSectorAreaConfig.Designer.cs new file mode 100644 index 00000000..db103d37 --- /dev/null +++ b/Source/Plugins/3DFloorMode/Windows/ControlSectorAreaConfig.Designer.cs @@ -0,0 +1,161 @@ +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + partial class ControlSectorAreaConfig + { + /// + /// Erforderliche Designervariable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Verwendete Ressourcen bereinigen. + /// + /// True, wenn verwaltete Ressourcen gelöscht werden sollen; andernfalls False. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Vom Windows Form-Designer generierter Code + + /// + /// Erforderliche Methode für die Designerunterstützung. + /// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden. + /// + private void InitializeComponent() + { + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.label2 = new System.Windows.Forms.Label(); + this.label1 = new System.Windows.Forms.Label(); + this.lastTag = new CodeImp.DoomBuilder.Controls.NumericTextbox(); + this.firstTag = new CodeImp.DoomBuilder.Controls.NumericTextbox(); + this.useTagRange = new System.Windows.Forms.CheckBox(); + this.okButton = new System.Windows.Forms.Button(); + this.cancelButton = new System.Windows.Forms.Button(); + this.groupBox1.SuspendLayout(); + this.SuspendLayout(); + // + // groupBox1 + // + this.groupBox1.Controls.Add(this.label2); + this.groupBox1.Controls.Add(this.label1); + this.groupBox1.Controls.Add(this.lastTag); + this.groupBox1.Controls.Add(this.firstTag); + this.groupBox1.Controls.Add(this.useTagRange); + this.groupBox1.Location = new System.Drawing.Point(12, 12); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(225, 57); + this.groupBox1.TabIndex = 0; + this.groupBox1.TabStop = false; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(120, 27); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(27, 13); + this.label2.TabIndex = 4; + this.label2.Text = "Last"; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(6, 27); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(26, 13); + this.label1.TabIndex = 3; + this.label1.Text = "First"; + // + // lastTag + // + this.lastTag.AllowDecimal = false; + this.lastTag.AllowNegative = false; + this.lastTag.AllowRelative = false; + this.lastTag.Enabled = false; + this.lastTag.ImeMode = System.Windows.Forms.ImeMode.Off; + this.lastTag.Location = new System.Drawing.Point(153, 24); + this.lastTag.Name = "lastTag"; + this.lastTag.Size = new System.Drawing.Size(62, 20); + this.lastTag.TabIndex = 2; + // + // firstTag + // + this.firstTag.AllowDecimal = false; + this.firstTag.AllowNegative = false; + this.firstTag.AllowRelative = false; + this.firstTag.Enabled = false; + this.firstTag.ImeMode = System.Windows.Forms.ImeMode.Off; + this.firstTag.Location = new System.Drawing.Point(38, 24); + this.firstTag.Name = "firstTag"; + this.firstTag.Size = new System.Drawing.Size(62, 20); + this.firstTag.TabIndex = 1; + // + // useTagRange + // + this.useTagRange.AutoSize = true; + this.useTagRange.Location = new System.Drawing.Point(7, 1); + this.useTagRange.Name = "useTagRange"; + this.useTagRange.Size = new System.Drawing.Size(93, 17); + this.useTagRange.TabIndex = 0; + this.useTagRange.Text = "Use tag range"; + this.useTagRange.UseVisualStyleBackColor = true; + this.useTagRange.CheckedChanged += new System.EventHandler(this.useTagRange_CheckedChanged); + // + // okButton + // + this.okButton.Location = new System.Drawing.Point(47, 75); + this.okButton.Name = "okButton"; + this.okButton.Size = new System.Drawing.Size(75, 23); + this.okButton.TabIndex = 1; + this.okButton.Text = "OK"; + this.okButton.UseVisualStyleBackColor = true; + this.okButton.Click += new System.EventHandler(this.okButton_Click); + // + // cancelButton + // + this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.cancelButton.Location = new System.Drawing.Point(128, 75); + this.cancelButton.Name = "cancelButton"; + this.cancelButton.Size = new System.Drawing.Size(75, 23); + this.cancelButton.TabIndex = 2; + this.cancelButton.Text = "Cancel"; + this.cancelButton.UseVisualStyleBackColor = true; + this.cancelButton.Click += new System.EventHandler(this.cancelButton_Click); + // + // ControlSectorAreaConfig + // + this.AcceptButton = this.okButton; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.cancelButton; + this.ClientSize = new System.Drawing.Size(250, 109); + this.Controls.Add(this.cancelButton); + this.Controls.Add(this.okButton); + this.Controls.Add(this.groupBox1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.Name = "ControlSectorAreaConfig"; + this.ShowIcon = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Control Sector Area Configuration"; + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.GroupBox groupBox1; + private CodeImp.DoomBuilder.Controls.NumericTextbox firstTag; + private System.Windows.Forms.CheckBox useTagRange; + private CodeImp.DoomBuilder.Controls.NumericTextbox lastTag; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Button okButton; + private System.Windows.Forms.Button cancelButton; + } +} \ No newline at end of file diff --git a/Source/Plugins/3DFloorMode/Windows/ControlSectorAreaConfig.cs b/Source/Plugins/3DFloorMode/Windows/ControlSectorAreaConfig.cs new file mode 100644 index 00000000..9dec5fd6 --- /dev/null +++ b/Source/Plugins/3DFloorMode/Windows/ControlSectorAreaConfig.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Windows.Forms; + +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + public partial class ControlSectorAreaConfig : Form + { + private ControlSectorArea csa; + + public ControlSectorAreaConfig(ControlSectorArea csa) + { + this.csa = csa; + + InitializeComponent(); + + useTagRange.Checked = csa.UseCustomTagRnage; + firstTag.Text = csa.FirstTag.ToString(); + lastTag.Text = csa.LastTag.ToString(); + } + + private void useTagRange_CheckedChanged(object sender, EventArgs e) + { + if (useTagRange.Checked) + { + firstTag.Enabled = true; + lastTag.Enabled = true; + } + else + { + firstTag.Enabled = false; + lastTag.Enabled = false; + } + } + + private void cancelButton_Click(object sender, EventArgs e) + { + this.DialogResult = DialogResult.Cancel; + this.Close(); + } + + private void okButton_Click(object sender, EventArgs e) + { + if (useTagRange.Checked && int.Parse(lastTag.Text) < int.Parse(firstTag.Text)) + { + MessageBox.Show("Last tag of range must be bigger than first tag of range", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + + csa.UseCustomTagRnage = useTagRange.Checked; + + if (useTagRange.Checked) + { + csa.FirstTag = int.Parse(firstTag.Text); + csa.LastTag = int.Parse(lastTag.Text); + } + + this.DialogResult = DialogResult.OK; + this.Close(); + } + } +} diff --git a/Source/Plugins/3DFloorMode/Windows/ControlSectorAreaConfig.resx b/Source/Plugins/3DFloorMode/Windows/ControlSectorAreaConfig.resx new file mode 100644 index 00000000..19dc0dd8 --- /dev/null +++ b/Source/Plugins/3DFloorMode/Windows/ControlSectorAreaConfig.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Source/Plugins/3DFloorMode/Windows/MenusForm.Designer.cs b/Source/Plugins/3DFloorMode/Windows/MenusForm.Designer.cs new file mode 100644 index 00000000..aec62a1d --- /dev/null +++ b/Source/Plugins/3DFloorMode/Windows/MenusForm.Designer.cs @@ -0,0 +1,194 @@ +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + partial class MenusForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MenusForm)); + this.toolStrip1 = new System.Windows.Forms.ToolStrip(); + this.floorslope = new System.Windows.Forms.ToolStripButton(); + this.ceilingslope = new System.Windows.Forms.ToolStripButton(); + this.floorandceilingslope = new System.Windows.Forms.ToolStripButton(); + this.updateslopes = new System.Windows.Forms.ToolStripButton(); + this.addsectorscontextmenu = new System.Windows.Forms.ContextMenuStrip(this.components); + this.addslopeceiling = new System.Windows.Forms.ToolStripMenuItem(); + this.addslopefloor = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); + this.removeslopeceiling = new System.Windows.Forms.ToolStripMenuItem(); + this.removeslopefloor = new System.Windows.Forms.ToolStripMenuItem(); + this.relocatecontrolsectors = new System.Windows.Forms.ToolStripButton(); + this.toolStrip1.SuspendLayout(); + this.addsectorscontextmenu.SuspendLayout(); + this.SuspendLayout(); + // + // toolStrip1 + // + this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.floorslope, + this.ceilingslope, + this.floorandceilingslope, + this.updateslopes, + this.relocatecontrolsectors}); + this.toolStrip1.Location = new System.Drawing.Point(0, 0); + this.toolStrip1.Name = "toolStrip1"; + this.toolStrip1.Size = new System.Drawing.Size(442, 25); + this.toolStrip1.TabIndex = 0; + this.toolStrip1.Text = "toolStrip1"; + // + // floorslope + // + this.floorslope.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.floorslope.Image = global::ThreeDFloorMode.Properties.Resources.Floor; + this.floorslope.ImageTransparentColor = System.Drawing.Color.Magenta; + this.floorslope.Name = "floorslope"; + this.floorslope.Size = new System.Drawing.Size(23, 22); + this.floorslope.Tag = "drawfloorslope"; + this.floorslope.Text = "Apply drawn slope to floor"; + this.floorslope.Click += new System.EventHandler(this.floorslope_Click); + // + // ceilingslope + // + this.ceilingslope.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.ceilingslope.Image = global::ThreeDFloorMode.Properties.Resources.Ceiling; + this.ceilingslope.ImageTransparentColor = System.Drawing.Color.Magenta; + this.ceilingslope.Name = "ceilingslope"; + this.ceilingslope.Size = new System.Drawing.Size(23, 22); + this.ceilingslope.Tag = "drawceilingslope"; + this.ceilingslope.Text = "Apply drawn slope to ceiling"; + this.ceilingslope.Click += new System.EventHandler(this.ceilingslope_Click); + // + // floorandceilingslope + // + this.floorandceilingslope.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.floorandceilingslope.Image = global::ThreeDFloorMode.Properties.Resources.FloorAndCeiling; + this.floorandceilingslope.ImageTransparentColor = System.Drawing.Color.Magenta; + this.floorandceilingslope.Name = "floorandceilingslope"; + this.floorandceilingslope.Size = new System.Drawing.Size(23, 22); + this.floorandceilingslope.Tag = "drawfloorandceilingslope"; + this.floorandceilingslope.Text = "Apply drawn slope to floor and ceiling"; + this.floorandceilingslope.Click += new System.EventHandler(this.floorandceilingslope_Click); + // + // updateslopes + // + this.updateslopes.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text; + this.updateslopes.Image = ((System.Drawing.Image)(resources.GetObject("updateslopes.Image"))); + this.updateslopes.ImageTransparentColor = System.Drawing.Color.Magenta; + this.updateslopes.Name = "updateslopes"; + this.updateslopes.Size = new System.Drawing.Size(85, 22); + this.updateslopes.Text = "Update slopes"; + this.updateslopes.Click += new System.EventHandler(this.toolStripButton1_Click); + // + // addsectorscontextmenu + // + this.addsectorscontextmenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.addslopeceiling, + this.addslopefloor, + this.toolStripSeparator1, + this.removeslopeceiling, + this.removeslopefloor}); + this.addsectorscontextmenu.Name = "addsectorscontextmenu"; + this.addsectorscontextmenu.Size = new System.Drawing.Size(216, 98); + this.addsectorscontextmenu.Opening += new System.ComponentModel.CancelEventHandler(this.addsectorscontextmenu_Opening); + this.addsectorscontextmenu.Closing += new System.Windows.Forms.ToolStripDropDownClosingEventHandler(this.addsectorscontextmenu_Closing); + // + // addslopeceiling + // + this.addslopeceiling.Name = "addslopeceiling"; + this.addslopeceiling.Size = new System.Drawing.Size(215, 22); + this.addslopeceiling.Text = "Add slope to ceiling"; + this.addslopeceiling.Click += new System.EventHandler(this.ceilingToolStripMenuItem_Click); + // + // addslopefloor + // + this.addslopefloor.Name = "addslopefloor"; + this.addslopefloor.Size = new System.Drawing.Size(215, 22); + this.addslopefloor.Text = "Add slope to floor"; + this.addslopefloor.Click += new System.EventHandler(this.floorToolStripMenuItem_Click); + // + // toolStripSeparator1 + // + this.toolStripSeparator1.Name = "toolStripSeparator1"; + this.toolStripSeparator1.Size = new System.Drawing.Size(212, 6); + // + // removeslopeceiling + // + this.removeslopeceiling.Name = "removeslopeceiling"; + this.removeslopeceiling.Size = new System.Drawing.Size(215, 22); + this.removeslopeceiling.Text = "Remove slope from ceiling"; + this.removeslopeceiling.Click += new System.EventHandler(this.removeSlopeFromCeilingToolStripMenuItem_Click); + // + // removeslopefloor + // + this.removeslopefloor.Name = "removeslopefloor"; + this.removeslopefloor.Size = new System.Drawing.Size(215, 22); + this.removeslopefloor.Text = "Remove slope from floor"; + this.removeslopefloor.Click += new System.EventHandler(this.removeSlopeFromFloorToolStripMenuItem_Click); + // + // relocatecontrolsectors + // + this.relocatecontrolsectors.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text; + this.relocatecontrolsectors.Image = ((System.Drawing.Image)(resources.GetObject("relocatecontrolsectors.Image"))); + this.relocatecontrolsectors.ImageTransparentColor = System.Drawing.Color.Magenta; + this.relocatecontrolsectors.Name = "relocatecontrolsectors"; + this.relocatecontrolsectors.Size = new System.Drawing.Size(137, 22); + this.relocatecontrolsectors.Tag = "relocate3dfloorcontrolsectors"; + this.relocatecontrolsectors.Text = "Relocate control sectors"; + this.relocatecontrolsectors.Click += new System.EventHandler(this.relocatecontrolsectors_Click); + // + // MenusForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(442, 262); + this.Controls.Add(this.toolStrip1); + this.Name = "MenusForm"; + this.Text = "MenusForm"; + this.toolStrip1.ResumeLayout(false); + this.toolStrip1.PerformLayout(); + this.addsectorscontextmenu.ResumeLayout(false); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.ToolStrip toolStrip1; + private System.Windows.Forms.ToolStripButton floorslope; + private System.Windows.Forms.ToolStripButton ceilingslope; + private System.Windows.Forms.ToolStripButton floorandceilingslope; + private System.Windows.Forms.ToolStripButton updateslopes; + private System.Windows.Forms.ContextMenuStrip addsectorscontextmenu; + private System.Windows.Forms.ToolStripMenuItem addslopefloor; + private System.Windows.Forms.ToolStripMenuItem addslopeceiling; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator1; + private System.Windows.Forms.ToolStripMenuItem removeslopeceiling; + private System.Windows.Forms.ToolStripMenuItem removeslopefloor; + private System.Windows.Forms.ToolStripButton relocatecontrolsectors; + } +} \ No newline at end of file diff --git a/Source/Plugins/3DFloorMode/Windows/MenusForm.cs b/Source/Plugins/3DFloorMode/Windows/MenusForm.cs new file mode 100644 index 00000000..e7dc6822 --- /dev/null +++ b/Source/Plugins/3DFloorMode/Windows/MenusForm.cs @@ -0,0 +1,155 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using CodeImp.DoomBuilder.Windows; +using CodeImp.DoomBuilder.Map; + +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + public partial class MenusForm : Form + { + public ToolStripButton FloorSlope { get { return floorslope; } } + public ToolStripButton CeilingSlope { get { return ceilingslope; } } + public ToolStripButton FloorAndCeilingSlope { get { return floorandceilingslope; } } + public ToolStripButton UpdateSlopes { get { return updateslopes; } } + public ToolStripButton RelocateControlSectors { get { return relocatecontrolsectors; } } + public ContextMenuStrip AddSectorsContextMenu { get { return addsectorscontextmenu; } } + + public MenusForm() + { + InitializeComponent(); + } + + private void InvokeTaggedAction(object sender, EventArgs e) + { + General.Interface.InvokeTaggedAction(sender, e); + } + + private void floorslope_Click(object sender, EventArgs e) + { + if (floorslope.Checked) + return; + + General.Interface.InvokeTaggedAction(sender, e); + } + + private void ceilingslope_Click(object sender, EventArgs e) + { + if (ceilingslope.Checked) + return; + + General.Interface.InvokeTaggedAction(sender, e); + } + + private void floorandceilingslope_Click(object sender, EventArgs e) + { + if (floorandceilingslope.Checked) + return; + + General.Interface.InvokeTaggedAction(sender, e); + } + + private void toolStripButton1_Click(object sender, EventArgs e) + { + BuilderPlug.Me.UpdateSlopes(); + } + + private void floorToolStripMenuItem_Click(object sender, EventArgs e) + { + List svgs = ((SlopeMode)General.Editing.Mode).GetSelectedSlopeVertexGroups(); + + // Can only add sectors to one slope vertex group + if (svgs.Count != 1) + return; + + foreach (Sector s in (List)addsectorscontextmenu.Tag) + { + SlopeVertexGroup rsvg = BuilderPlug.Me.GetSlopeVertexGroup(s); + + if (rsvg != null) + rsvg.RemoveSector(s, PlaneType.Floor); + + svgs[0].AddSector(s, PlaneType.Floor); + BuilderPlug.Me.UpdateSlopes(s); + } + + General.Interface.RedrawDisplay(); + } + + private void removeSlopeFromFloorToolStripMenuItem_Click(object sender, EventArgs e) + { + foreach (Sector s in (List)addsectorscontextmenu.Tag) + { + SlopeVertexGroup svg = BuilderPlug.Me.GetSlopeVertexGroup(s); + + if (svg != null) + svg.RemoveSector(s, PlaneType.Floor); + } + + General.Interface.RedrawDisplay(); + } + + private void ceilingToolStripMenuItem_Click(object sender, EventArgs e) + { + List svgs = ((SlopeMode)General.Editing.Mode).GetSelectedSlopeVertexGroups(); + + // Can only add sectors to one slope vertex group + if (svgs.Count != 1) + return; + + foreach (Sector s in (List)addsectorscontextmenu.Tag) + { + SlopeVertexGroup rsvg = BuilderPlug.Me.GetSlopeVertexGroup(s); + + if (rsvg != null) + rsvg.RemoveSector(s, PlaneType.Ceiling); + + svgs[0].AddSector(s, PlaneType.Ceiling); + BuilderPlug.Me.UpdateSlopes(s); + } + + General.Interface.RedrawDisplay(); + } + + private void removeSlopeFromCeilingToolStripMenuItem_Click(object sender, EventArgs e) + { + foreach (Sector s in (List)addsectorscontextmenu.Tag) + { + SlopeVertexGroup svg = BuilderPlug.Me.GetSlopeVertexGroup(s); + + if(svg != null) + svg.RemoveSector(s, PlaneType.Ceiling); + } + + General.Interface.RedrawDisplay(); + } + + private void addsectorscontextmenu_Opening(object sender, CancelEventArgs e) + { + // Disable adding if more than one slope vertex group is selected, + // otherwise enable adding + List svgs = ((SlopeMode)General.Editing.Mode).GetSelectedSlopeVertexGroups(); + + addslopefloor.Enabled = svgs.Count == 1; + addslopeceiling.Enabled = svgs.Count == 1; + } + + private void addsectorscontextmenu_Closing(object sender, ToolStripDropDownClosingEventArgs e) + { + if( e.CloseReason != ToolStripDropDownCloseReason.ItemClicked && + e.CloseReason != ToolStripDropDownCloseReason.Keyboard && + e.CloseReason != ToolStripDropDownCloseReason.AppFocusChange) + ((SlopeMode)General.Editing.Mode).ContextMenuClosing = true; + } + + private void relocatecontrolsectors_Click(object sender, EventArgs e) + { + General.Interface.InvokeTaggedAction(sender, e); + } + } +} diff --git a/Source/Plugins/3DFloorMode/Windows/MenusForm.resx b/Source/Plugins/3DFloorMode/Windows/MenusForm.resx new file mode 100644 index 00000000..23345ded --- /dev/null +++ b/Source/Plugins/3DFloorMode/Windows/MenusForm.resx @@ -0,0 +1,157 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG + YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9 + 0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw + bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc + VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9 + c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32 + Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo + mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+ + kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D + TgDQASA1MVpwzwAAAABJRU5ErkJggg== + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG + YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9 + 0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw + bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc + VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9 + c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32 + Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo + mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+ + kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D + TgDQASA1MVpwzwAAAABJRU5ErkJggg== + + + + 122, 17 + + \ No newline at end of file diff --git a/Source/Plugins/3DFloorMode/Windows/SlopeDataSectorDialog.Designer.cs b/Source/Plugins/3DFloorMode/Windows/SlopeDataSectorDialog.Designer.cs new file mode 100644 index 00000000..5eb4d878 --- /dev/null +++ b/Source/Plugins/3DFloorMode/Windows/SlopeDataSectorDialog.Designer.cs @@ -0,0 +1,104 @@ +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + partial class SlopeDataSectorDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.useselectedsector = new System.Windows.Forms.Button(); + this.createnewsector = new System.Windows.Forms.Button(); + this.cancel = new System.Windows.Forms.Button(); + this.webBrowser1 = new System.Windows.Forms.WebBrowser(); + this.SuspendLayout(); + // + // useselectedsector + // + this.useselectedsector.Location = new System.Drawing.Point(147, 238); + this.useselectedsector.Name = "useselectedsector"; + this.useselectedsector.Size = new System.Drawing.Size(129, 23); + this.useselectedsector.TabIndex = 2; + this.useselectedsector.Text = "Use selected sector"; + this.useselectedsector.UseVisualStyleBackColor = true; + this.useselectedsector.Click += new System.EventHandler(this.button1_Click); + // + // createnewsector + // + this.createnewsector.Location = new System.Drawing.Point(12, 238); + this.createnewsector.Name = "createnewsector"; + this.createnewsector.Size = new System.Drawing.Size(129, 23); + this.createnewsector.TabIndex = 1; + this.createnewsector.Text = "Create sector in CSA"; + this.createnewsector.UseVisualStyleBackColor = true; + this.createnewsector.Click += new System.EventHandler(this.createnewsector_Click); + // + // cancel + // + this.cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.cancel.Location = new System.Drawing.Point(282, 238); + this.cancel.Name = "cancel"; + this.cancel.Size = new System.Drawing.Size(129, 23); + this.cancel.TabIndex = 3; + this.cancel.Text = "Cancel"; + this.cancel.UseVisualStyleBackColor = true; + // + // webBrowser1 + // + this.webBrowser1.Location = new System.Drawing.Point(12, 12); + this.webBrowser1.MinimumSize = new System.Drawing.Size(20, 20); + this.webBrowser1.Name = "webBrowser1"; + this.webBrowser1.ScrollBarsEnabled = false; + this.webBrowser1.Size = new System.Drawing.Size(399, 220); + this.webBrowser1.TabIndex = 4; + // + // SlopeDataSectorDialog + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.cancel; + this.ClientSize = new System.Drawing.Size(423, 273); + this.Controls.Add(this.webBrowser1); + this.Controls.Add(this.cancel); + this.Controls.Add(this.createnewsector); + this.Controls.Add(this.useselectedsector); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "SlopeDataSectorDialog"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Slope data sector"; + this.Load += new System.EventHandler(this.SlopeDataSectorDialog_Load); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Button useselectedsector; + private System.Windows.Forms.Button createnewsector; + private System.Windows.Forms.Button cancel; + private System.Windows.Forms.WebBrowser webBrowser1; + } +} \ No newline at end of file diff --git a/Source/Plugins/3DFloorMode/Windows/SlopeDataSectorDialog.cs b/Source/Plugins/3DFloorMode/Windows/SlopeDataSectorDialog.cs new file mode 100644 index 00000000..3f343358 --- /dev/null +++ b/Source/Plugins/3DFloorMode/Windows/SlopeDataSectorDialog.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using CodeImp.DoomBuilder.Map; +using CodeImp.DoomBuilder.Geometry; +using CodeImp.DoomBuilder.Windows; + +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + public partial class SlopeDataSectorDialog : Form + { + public SlopeDataSectorDialog() + { + InitializeComponent(); + } + + private void button1_Click(object sender, EventArgs e) + { + if (General.Map.Map.SelectedSectorsCount == 0) + MessageBox.Show("No sectors selected. Please select exactly one sector", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + else if (General.Map.Map.SelectedSectorsCount > 1) + MessageBox.Show(General.Map.Map.SelectedSectorsCount.ToString() + " sectors selected. Please select exactly one sector", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + else + { + General.Map.Map.ClearAllMarks(false); + General.Map.Map.GetSelectedSectors(true).First().Marked = true; + + this.DialogResult = DialogResult.OK; + this.Close(); + } + } + + private void SlopeDataSectorDialog_Load(object sender, EventArgs e) + { + webBrowser1.DocumentText = string.Format(System.Globalization.CultureInfo.GetCultureInfo("en-US"), @" + + +The map does not contain a slope data sector. This sector is required by the slope mode to store data for the slope vertex groups. + +You have two options: +
    +
  • Use selected sector: uses the currently selected sector to store the slope data. Make sure that this sector is only +used for this purpose! Do not edit or delete it!
  • +
  • Create sector in CSA: automatically creates a new sector in the control sector area. Do not edit or delete it!
  • +
+ +Creating the sector in the CSA is the recommended method to use.", this.BackColor.R, this.BackColor.G, this.BackColor.B, this.Font.Name); + } + + private void createnewsector_Click(object sender, EventArgs e) + { + List drawnvertices = new List(); + + try + { + drawnvertices = BuilderPlug.Me.ControlSectorArea.GetNewControlSectorVertices(); + } + catch (Exception ex) + { + MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + + General.Map.Map.ClearAllMarks(false); + + // DrawLines automatically marks the new sector, so we don't have to do it manually + if (Tools.DrawLines(drawnvertices) == false) + { + MessageBox.Show("Could not draw new sector", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + + // Update textures + General.Map.Data.UpdateUsedTextures(); + + // Update caches + General.Map.Map.Update(); + General.Interface.RedrawDisplay(); + General.Map.IsChanged = true; + + this.DialogResult = DialogResult.OK; + this.Close(); + } + } +} diff --git a/Source/Plugins/3DFloorMode/Windows/SlopeDataSectorDialog.resx b/Source/Plugins/3DFloorMode/Windows/SlopeDataSectorDialog.resx new file mode 100644 index 00000000..19dc0dd8 --- /dev/null +++ b/Source/Plugins/3DFloorMode/Windows/SlopeDataSectorDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Source/Plugins/3DFloorMode/Windows/SlopeVertexEditForm.Designer.cs b/Source/Plugins/3DFloorMode/Windows/SlopeVertexEditForm.Designer.cs new file mode 100644 index 00000000..4979ca50 --- /dev/null +++ b/Source/Plugins/3DFloorMode/Windows/SlopeVertexEditForm.Designer.cs @@ -0,0 +1,342 @@ +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + partial class SlopeVertexEditForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.apply = new System.Windows.Forms.Button(); + this.cancel = new System.Windows.Forms.Button(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.label3 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.label1 = new System.Windows.Forms.Label(); + this.positionz = new CodeImp.DoomBuilder.Controls.ButtonsNumericTextbox(); + this.positiony = new CodeImp.DoomBuilder.Controls.ButtonsNumericTextbox(); + this.positionx = new CodeImp.DoomBuilder.Controls.ButtonsNumericTextbox(); + this.groupBox2 = new System.Windows.Forms.GroupBox(); + this.checkedListBoxSectors = new System.Windows.Forms.CheckedListBox(); + this.reposition = new System.Windows.Forms.CheckBox(); + this.groupBox3 = new System.Windows.Forms.GroupBox(); + this.removeselectedsectorsceiling = new System.Windows.Forms.CheckBox(); + this.addselectedsectorsceiling = new System.Windows.Forms.CheckBox(); + this.groupBox4 = new System.Windows.Forms.GroupBox(); + this.removeselectedsectorsfloor = new System.Windows.Forms.CheckBox(); + this.addselectedsectorsfloor = new System.Windows.Forms.CheckBox(); + this.spline = new System.Windows.Forms.CheckBox(); + this.groupBox1.SuspendLayout(); + this.groupBox2.SuspendLayout(); + this.groupBox3.SuspendLayout(); + this.groupBox4.SuspendLayout(); + this.SuspendLayout(); + // + // apply + // + this.apply.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.apply.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.apply.Location = new System.Drawing.Point(260, 174); + this.apply.Name = "apply"; + this.apply.Size = new System.Drawing.Size(112, 25); + this.apply.TabIndex = 0; + this.apply.Text = "OK"; + this.apply.UseVisualStyleBackColor = true; + this.apply.Click += new System.EventHandler(this.apply_Click); + // + // cancel + // + this.cancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.cancel.Location = new System.Drawing.Point(380, 174); + this.cancel.Name = "cancel"; + this.cancel.Size = new System.Drawing.Size(112, 25); + this.cancel.TabIndex = 1; + this.cancel.Text = "Cancel"; + this.cancel.UseVisualStyleBackColor = true; + this.cancel.Click += new System.EventHandler(this.cancel_Click); + // + // groupBox1 + // + this.groupBox1.Controls.Add(this.label3); + this.groupBox1.Controls.Add(this.label2); + this.groupBox1.Controls.Add(this.label1); + this.groupBox1.Controls.Add(this.positionz); + this.groupBox1.Controls.Add(this.positiony); + this.groupBox1.Controls.Add(this.positionx); + this.groupBox1.Location = new System.Drawing.Point(18, 13); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(149, 114); + this.groupBox1.TabIndex = 0; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "Position"; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Font = new System.Drawing.Font("Arial", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label3.Location = new System.Drawing.Point(6, 87); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(17, 14); + this.label3.TabIndex = 15; + this.label3.Text = "Z:"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Font = new System.Drawing.Font("Arial", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label2.Location = new System.Drawing.Point(6, 57); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(17, 14); + this.label2.TabIndex = 14; + this.label2.Text = "Y:"; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Arial", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(6, 25); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(17, 14); + this.label1.TabIndex = 13; + this.label1.Text = "X:"; + // + // positionz + // + this.positionz.AllowDecimal = true; + this.positionz.AllowExpressions = false; + this.positionz.AllowNegative = true; + this.positionz.AllowRelative = true; + this.positionz.BackColor = System.Drawing.Color.Transparent; + this.positionz.ButtonStep = 8; + this.positionz.ButtonStepBig = 16F; + this.positionz.ButtonStepFloat = 8F; + this.positionz.ButtonStepSmall = 1F; + this.positionz.ButtonStepsUseModifierKeys = true; + this.positionz.ButtonStepsWrapAround = false; + this.positionz.Location = new System.Drawing.Point(29, 82); + this.positionz.Name = "positionz"; + this.positionz.Size = new System.Drawing.Size(115, 24); + this.positionz.StepValues = null; + this.positionz.TabIndex = 0; + // + // positiony + // + this.positiony.AllowDecimal = true; + this.positiony.AllowExpressions = false; + this.positiony.AllowNegative = true; + this.positiony.AllowRelative = true; + this.positiony.BackColor = System.Drawing.Color.Transparent; + this.positiony.ButtonStep = 8; + this.positiony.ButtonStepBig = 16F; + this.positiony.ButtonStepFloat = 8F; + this.positiony.ButtonStepSmall = 1F; + this.positiony.ButtonStepsUseModifierKeys = true; + this.positiony.ButtonStepsWrapAround = false; + this.positiony.Location = new System.Drawing.Point(29, 52); + this.positiony.Name = "positiony"; + this.positiony.Size = new System.Drawing.Size(115, 24); + this.positiony.StepValues = null; + this.positiony.TabIndex = 3; + // + // positionx + // + this.positionx.AllowDecimal = true; + this.positionx.AllowExpressions = false; + this.positionx.AllowNegative = true; + this.positionx.AllowRelative = true; + this.positionx.BackColor = System.Drawing.Color.Transparent; + this.positionx.ButtonStep = 8; + this.positionx.ButtonStepBig = 16F; + this.positionx.ButtonStepFloat = 8F; + this.positionx.ButtonStepSmall = 1F; + this.positionx.ButtonStepsUseModifierKeys = true; + this.positionx.ButtonStepsWrapAround = false; + this.positionx.Location = new System.Drawing.Point(29, 20); + this.positionx.Name = "positionx"; + this.positionx.Size = new System.Drawing.Size(115, 24); + this.positionx.StepValues = null; + this.positionx.TabIndex = 2; + // + // groupBox2 + // + this.groupBox2.Controls.Add(this.checkedListBoxSectors); + this.groupBox2.Location = new System.Drawing.Point(174, 13); + this.groupBox2.Name = "groupBox2"; + this.groupBox2.Size = new System.Drawing.Size(113, 149); + this.groupBox2.TabIndex = 2; + this.groupBox2.TabStop = false; + this.groupBox2.Text = "Sectors to remove"; + // + // checkedListBoxSectors + // + this.checkedListBoxSectors.CheckOnClick = true; + this.checkedListBoxSectors.FormattingEnabled = true; + this.checkedListBoxSectors.Location = new System.Drawing.Point(6, 19); + this.checkedListBoxSectors.Name = "checkedListBoxSectors"; + this.checkedListBoxSectors.Size = new System.Drawing.Size(100, 124); + this.checkedListBoxSectors.TabIndex = 1; + // + // reposition + // + this.reposition.AutoSize = true; + this.reposition.Location = new System.Drawing.Point(18, 178); + this.reposition.Name = "reposition"; + this.reposition.Size = new System.Drawing.Size(187, 18); + this.reposition.TabIndex = 5; + this.reposition.Text = "Reposition after dragging sectors"; + this.reposition.UseVisualStyleBackColor = true; + // + // groupBox3 + // + this.groupBox3.Controls.Add(this.removeselectedsectorsceiling); + this.groupBox3.Controls.Add(this.addselectedsectorsceiling); + this.groupBox3.Location = new System.Drawing.Point(297, 13); + this.groupBox3.Name = "groupBox3"; + this.groupBox3.Size = new System.Drawing.Size(195, 71); + this.groupBox3.TabIndex = 8; + this.groupBox3.TabStop = false; + this.groupBox3.Text = "Ceiling"; + // + // removeselectedsectorsceiling + // + this.removeselectedsectorsceiling.AutoSize = true; + this.removeselectedsectorsceiling.Location = new System.Drawing.Point(6, 43); + this.removeselectedsectorsceiling.Name = "removeselectedsectorsceiling"; + this.removeselectedsectorsceiling.Size = new System.Drawing.Size(174, 18); + this.removeselectedsectorsceiling.TabIndex = 6; + this.removeselectedsectorsceiling.Text = "Remove from selected sectors"; + this.removeselectedsectorsceiling.UseVisualStyleBackColor = true; + this.removeselectedsectorsceiling.CheckedChanged += new System.EventHandler(this.removeselectedsectorsceiling_CheckedChanged); + // + // addselectedsectorsceiling + // + this.addselectedsectorsceiling.AutoSize = true; + this.addselectedsectorsceiling.Location = new System.Drawing.Point(6, 19); + this.addselectedsectorsceiling.Name = "addselectedsectorsceiling"; + this.addselectedsectorsceiling.Size = new System.Drawing.Size(150, 18); + this.addselectedsectorsceiling.TabIndex = 5; + this.addselectedsectorsceiling.Text = "Apply to selected sectors"; + this.addselectedsectorsceiling.UseVisualStyleBackColor = true; + this.addselectedsectorsceiling.CheckedChanged += new System.EventHandler(this.addselectedsectorsceiling_CheckedChanged); + // + // groupBox4 + // + this.groupBox4.Controls.Add(this.removeselectedsectorsfloor); + this.groupBox4.Controls.Add(this.addselectedsectorsfloor); + this.groupBox4.Location = new System.Drawing.Point(297, 90); + this.groupBox4.Name = "groupBox4"; + this.groupBox4.Size = new System.Drawing.Size(195, 72); + this.groupBox4.TabIndex = 9; + this.groupBox4.TabStop = false; + this.groupBox4.Text = "Floor"; + // + // removeselectedsectorsfloor + // + this.removeselectedsectorsfloor.AutoSize = true; + this.removeselectedsectorsfloor.Location = new System.Drawing.Point(6, 43); + this.removeselectedsectorsfloor.Name = "removeselectedsectorsfloor"; + this.removeselectedsectorsfloor.Size = new System.Drawing.Size(174, 18); + this.removeselectedsectorsfloor.TabIndex = 9; + this.removeselectedsectorsfloor.Text = "Remove from selected sectors"; + this.removeselectedsectorsfloor.UseVisualStyleBackColor = true; + this.removeselectedsectorsfloor.CheckedChanged += new System.EventHandler(this.removeselectedsectorsfloor_CheckedChanged); + // + // addselectedsectorsfloor + // + this.addselectedsectorsfloor.AutoSize = true; + this.addselectedsectorsfloor.Location = new System.Drawing.Point(6, 19); + this.addselectedsectorsfloor.Name = "addselectedsectorsfloor"; + this.addselectedsectorsfloor.Size = new System.Drawing.Size(150, 18); + this.addselectedsectorsfloor.TabIndex = 8; + this.addselectedsectorsfloor.Text = "Apply to selected sectors"; + this.addselectedsectorsfloor.UseVisualStyleBackColor = true; + this.addselectedsectorsfloor.CheckedChanged += new System.EventHandler(this.addselectedsectorsfloor_CheckedChanged); + // + // spline + // + this.spline.AutoSize = true; + this.spline.Location = new System.Drawing.Point(18, 154); + this.spline.Name = "spline"; + this.spline.Size = new System.Drawing.Size(55, 18); + this.spline.TabIndex = 10; + this.spline.Text = "Spline"; + this.spline.UseVisualStyleBackColor = true; + // + // SlopeVertexEditForm + // + this.AcceptButton = this.apply; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 14F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.cancel; + this.ClientSize = new System.Drawing.Size(504, 211); + this.Controls.Add(this.spline); + this.Controls.Add(this.groupBox4); + this.Controls.Add(this.groupBox3); + this.Controls.Add(this.reposition); + this.Controls.Add(this.groupBox2); + this.Controls.Add(this.groupBox1); + this.Controls.Add(this.cancel); + this.Controls.Add(this.apply); + this.Font = new System.Drawing.Font("Arial", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.Name = "SlopeVertexEditForm"; + this.ShowIcon = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Edit Slope Vertex"; + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.groupBox2.ResumeLayout(false); + this.groupBox3.ResumeLayout(false); + this.groupBox3.PerformLayout(); + this.groupBox4.ResumeLayout(false); + this.groupBox4.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Button apply; + private System.Windows.Forms.Button cancel; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label label1; + public CodeImp.DoomBuilder.Controls.ButtonsNumericTextbox positionz; + public CodeImp.DoomBuilder.Controls.ButtonsNumericTextbox positiony; + public CodeImp.DoomBuilder.Controls.ButtonsNumericTextbox positionx; + private System.Windows.Forms.GroupBox groupBox2; + public System.Windows.Forms.CheckedListBox checkedListBoxSectors; + private System.Windows.Forms.CheckBox reposition; + private System.Windows.Forms.GroupBox groupBox3; + private System.Windows.Forms.CheckBox removeselectedsectorsceiling; + private System.Windows.Forms.CheckBox addselectedsectorsceiling; + private System.Windows.Forms.GroupBox groupBox4; + private System.Windows.Forms.CheckBox removeselectedsectorsfloor; + private System.Windows.Forms.CheckBox addselectedsectorsfloor; + private System.Windows.Forms.CheckBox spline; + } +} \ No newline at end of file diff --git a/Source/Plugins/3DFloorMode/Windows/SlopeVertexEditForm.cs b/Source/Plugins/3DFloorMode/Windows/SlopeVertexEditForm.cs new file mode 100644 index 00000000..7cfb3984 --- /dev/null +++ b/Source/Plugins/3DFloorMode/Windows/SlopeVertexEditForm.cs @@ -0,0 +1,222 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using CodeImp.DoomBuilder.Geometry; +using CodeImp.DoomBuilder.Map; + +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + public partial class SlopeVertexEditForm : Form + { + private List vertices; + private List sectors; + private string undodescription; + private bool canaddsectors; + private bool canremovesectors; + + public SlopeVertexEditForm() + { + InitializeComponent(); + } + + public void Setup(List vertices) + { + this.vertices = vertices; + + SlopeVertex fv = vertices[0]; + SlopeVertexGroup fsvg = BuilderPlug.Me.GetSlopeVertexGroup(fv); + + sectors = new List(); + + undodescription = "Edit slope vertex"; + + if (vertices.Count > 1) + undodescription = "Edit " + vertices.Count + " slope vertices"; + + positionx.Text = fv.Pos.x.ToString(); + positiony.Text = fv.Pos.y.ToString(); + positionz.Text = fv.Z.ToString(); + + foreach (Sector s in fsvg.Sectors) + if (!sectors.Contains(s)) + sectors.Add(s); + + reposition.Checked = fsvg.Reposition; + spline.Checked = fsvg.Spline; + + canaddsectors = true; + canremovesectors = true; + + if (vertices.Count > 1) + { + List listsvgs = new List(); + + this.Text = "Edit slope vertices (" + vertices.Count.ToString() + ")"; + + foreach (SlopeVertex sv in vertices) + { + SlopeVertexGroup svg = BuilderPlug.Me.GetSlopeVertexGroup(sv); + + if (!listsvgs.Contains(svg)) + listsvgs.Add(svg); + + if (sv.Pos.x.ToString() != positionx.Text) + positionx.Text = ""; + + if (sv.Pos.y.ToString() != positiony.Text) + positiony.Text = ""; + + if (sv.Z.ToString() != positionz.Text) + positionz.Text = ""; + + if (svg.Reposition != reposition.Checked) + reposition.CheckState = CheckState.Indeterminate; + + if (svg.Spline) + spline.Enabled = true; + + if (svg.Spline != spline.Checked) + spline.CheckState = CheckState.Indeterminate; + + foreach (Sector s in svg.Sectors) + if (!sectors.Contains(s)) + sectors.Add(s); + } + + if (listsvgs.Count > 2) + { + canaddsectors = false; + canremovesectors = false; + } + } + + foreach (Sector s in sectors.OrderBy(x => x.Index)) + { + checkedListBoxSectors.Items.Add(s); + } + + if (General.Map.Map.SelectedSectorsCount == 0) + { + addselectedsectorsceiling.Enabled = false; + removeselectedsectorsceiling.Enabled = false; + addselectedsectorsfloor.Enabled = false; + removeselectedsectorsfloor.Enabled = false; + } + else + { + addselectedsectorsceiling.Enabled = canaddsectors; + removeselectedsectorsceiling.Enabled = canremovesectors; + addselectedsectorsfloor.Enabled = canaddsectors; + removeselectedsectorsfloor.Enabled = canremovesectors; + } + } + + private void apply_Click(object sender, EventArgs e) + { + List groups = new List(); + + // undodescription was set in the Setup method + General.Map.UndoRedo.CreateUndo(undodescription); + + foreach (SlopeVertex sv in vertices) + { + SlopeVertexGroup svg = BuilderPlug.Me.GetSlopeVertexGroup(sv); + float x = positionx.GetResultFloat(sv.Pos.x); + float y = positiony.GetResultFloat(sv.Pos.y); + + sv.Pos = new Vector2D(x, y); + + sv.Z = positionz.GetResultFloat(sv.Z); + + if (!groups.Contains(svg)) + groups.Add(svg); + } + + foreach (SlopeVertexGroup svg in groups) + { + if (reposition.CheckState != CheckState.Indeterminate) + svg.Reposition = reposition.Checked; + + if (spline.CheckState != CheckState.Indeterminate && svg.Vertices.Count == 3) + svg.Spline = spline.Checked; + + // Ceiling + if (addselectedsectorsceiling.Checked) + foreach (Sector s in General.Map.Map.GetSelectedSectors(true).ToList()) + svg.AddSector(s, PlaneType.Ceiling); + + if (removeselectedsectorsceiling.Checked) + foreach (Sector s in General.Map.Map.GetSelectedSectors(true).ToList()) + if (svg.Sectors.Contains(s)) + svg.RemoveSector(s, PlaneType.Ceiling); + + // Floor + if (addselectedsectorsfloor.Checked) + foreach (Sector s in General.Map.Map.GetSelectedSectors(true).ToList()) + svg.AddSector(s, PlaneType.Floor); + + if (removeselectedsectorsfloor.Checked) + foreach (Sector s in General.Map.Map.GetSelectedSectors(true).ToList()) + if (svg.Sectors.Contains(s)) + svg.RemoveSector(s, PlaneType.Floor); + + foreach (Sector s in checkedListBoxSectors.CheckedItems) + { + if (svg.Sectors.Contains(s)) + { + svg.RemoveSector(s, PlaneType.Floor); + svg.RemoveSector(s, PlaneType.Ceiling); + } + } + + svg.ApplyToSectors(); + } + + BuilderPlug.Me.StoreSlopeVertexGroupsInSector(); + + this.DialogResult = DialogResult.OK; + } + + private void cancel_Click(object sender, EventArgs e) + { + this.DialogResult = DialogResult.Cancel; + } + + private void addselectedsectorsceiling_CheckedChanged(object sender, EventArgs e) + { + // Adding and removing selected sectors at the same time doesn't make sense, + // so make sure only one of the checkboxes is checked at most + if (addselectedsectorsceiling.Checked) + removeselectedsectorsceiling.Checked = false; + } + + private void removeselectedsectorsceiling_CheckedChanged(object sender, EventArgs e) + { + // Adding and removing selected sectors at the same time doesn't make sense, + // so make sure only one of the checkboxes is checked at most + if (removeselectedsectorsceiling.Checked) + addselectedsectorsceiling.Checked = false; + } + + private void addselectedsectorsfloor_CheckedChanged(object sender, EventArgs e) + { + // Adding and removing selected sectors at the same time doesn't make sense, + // so make sure only one of the checkboxes is checked at most + if (addselectedsectorsfloor.Checked) + removeselectedsectorsfloor.Checked = false; + } + + private void removeselectedsectorsfloor_CheckedChanged(object sender, EventArgs e) + { + // Adding and removing selected sectors at the same time doesn't make sense, + // so make sure only one of the checkboxes is checked at most + if (removeselectedsectorsfloor.Checked) + addselectedsectorsfloor.Checked = false; + } + } +} diff --git a/Source/Plugins/3DFloorMode/Windows/SlopeVertexEditForm.resx b/Source/Plugins/3DFloorMode/Windows/SlopeVertexEditForm.resx new file mode 100644 index 00000000..d58980a3 --- /dev/null +++ b/Source/Plugins/3DFloorMode/Windows/SlopeVertexEditForm.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Source/Plugins/3DFloorMode/Windows/ThreeDFloorEditorWindow.Designer.cs b/Source/Plugins/3DFloorMode/Windows/ThreeDFloorEditorWindow.Designer.cs new file mode 100644 index 00000000..1e229f00 --- /dev/null +++ b/Source/Plugins/3DFloorMode/Windows/ThreeDFloorEditorWindow.Designer.cs @@ -0,0 +1,181 @@ +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + partial class ThreeDFloorEditorWindow + { + /// + /// Erforderliche Designervariable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Verwendete Ressourcen bereinigen. + /// + /// True, wenn verwaltete Ressourcen gelöscht werden sollen; andernfalls False. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Vom Windows Form-Designer generierter Code + + /// + /// Erforderliche Methode für die Designerunterstützung. + /// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.threeDFloorPanel = new System.Windows.Forms.FlowLayoutPanel(); + this.okButton = new System.Windows.Forms.Button(); + this.cancelButton = new System.Windows.Forms.Button(); + this.addThreeDFloorButton = new System.Windows.Forms.Button(); + this.sharedThreeDFloorsCheckBox = new System.Windows.Forms.CheckBox(); + this.toolTip1 = new System.Windows.Forms.ToolTip(this.components); + this.no3dfloorspanel = new System.Windows.Forms.Panel(); + this.label1 = new System.Windows.Forms.Label(); + this.add3dfloorbutton2 = new System.Windows.Forms.Button(); + this.no3dfloorspanel.SuspendLayout(); + this.SuspendLayout(); + // + // threeDFloorPanel + // + this.threeDFloorPanel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.threeDFloorPanel.AutoScroll = true; + this.threeDFloorPanel.BackColor = System.Drawing.SystemColors.ControlLightLight; + this.threeDFloorPanel.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.threeDFloorPanel.Location = new System.Drawing.Point(12, 6); + this.threeDFloorPanel.Name = "threeDFloorPanel"; + this.threeDFloorPanel.Size = new System.Drawing.Size(760, 500); + this.threeDFloorPanel.TabIndex = 0; + // + // okButton + // + this.okButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.okButton.Location = new System.Drawing.Point(616, 513); + this.okButton.Name = "okButton"; + this.okButton.Size = new System.Drawing.Size(75, 23); + this.okButton.TabIndex = 3; + this.okButton.Text = "OK"; + this.okButton.UseVisualStyleBackColor = true; + this.okButton.Click += new System.EventHandler(this.okButton_Click); + // + // cancelButton + // + this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.cancelButton.Location = new System.Drawing.Point(697, 513); + this.cancelButton.Name = "cancelButton"; + this.cancelButton.Size = new System.Drawing.Size(75, 23); + this.cancelButton.TabIndex = 4; + this.cancelButton.Text = "Cancel"; + this.cancelButton.UseVisualStyleBackColor = true; + this.cancelButton.Click += new System.EventHandler(this.cancelButton_Click); + // + // addThreeDFloorButton + // + this.addThreeDFloorButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.addThreeDFloorButton.Location = new System.Drawing.Point(12, 513); + this.addThreeDFloorButton.Name = "addThreeDFloorButton"; + this.addThreeDFloorButton.Size = new System.Drawing.Size(75, 23); + this.addThreeDFloorButton.TabIndex = 1; + this.addThreeDFloorButton.Text = "Add 3D floor"; + this.addThreeDFloorButton.UseVisualStyleBackColor = true; + this.addThreeDFloorButton.Click += new System.EventHandler(this.addThreeDFloorButton_Click); + // + // sharedThreeDFloorsCheckBox + // + this.sharedThreeDFloorsCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.sharedThreeDFloorsCheckBox.AutoSize = true; + this.sharedThreeDFloorsCheckBox.Location = new System.Drawing.Point(93, 517); + this.sharedThreeDFloorsCheckBox.Name = "sharedThreeDFloorsCheckBox"; + this.sharedThreeDFloorsCheckBox.Size = new System.Drawing.Size(155, 17); + this.sharedThreeDFloorsCheckBox.TabIndex = 2; + this.sharedThreeDFloorsCheckBox.Text = "Show shared 3D floors only"; + this.toolTip1.SetToolTip(this.sharedThreeDFloorsCheckBox, "If checked only shows the 3D floors that\r\nare shared among all selected sectors"); + this.sharedThreeDFloorsCheckBox.UseVisualStyleBackColor = true; + this.sharedThreeDFloorsCheckBox.CheckedChanged += new System.EventHandler(this.sharedThreeDFloorsCheckBox_CheckedChanged); + // + // no3dfloorspanel + // + this.no3dfloorspanel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.no3dfloorspanel.Controls.Add(this.add3dfloorbutton2); + this.no3dfloorspanel.Controls.Add(this.label1); + this.no3dfloorspanel.Location = new System.Drawing.Point(12, 6); + this.no3dfloorspanel.Name = "no3dfloorspanel"; + this.no3dfloorspanel.Size = new System.Drawing.Size(760, 500); + this.no3dfloorspanel.TabIndex = 0; + // + // label1 + // + this.label1.Anchor = System.Windows.Forms.AnchorStyles.None; + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(279, 212); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(227, 25); + this.label1.TabIndex = 0; + this.label1.Text = "There are no 3D floors"; + // + // add3dfloorbutton2 + // + this.add3dfloorbutton2.Anchor = System.Windows.Forms.AnchorStyles.None; + this.add3dfloorbutton2.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.add3dfloorbutton2.Location = new System.Drawing.Point(320, 254); + this.add3dfloorbutton2.Name = "add3dfloorbutton2"; + this.add3dfloorbutton2.Size = new System.Drawing.Size(145, 33); + this.add3dfloorbutton2.TabIndex = 1; + this.add3dfloorbutton2.Text = "Add 3D floor"; + this.add3dfloorbutton2.UseVisualStyleBackColor = true; + this.add3dfloorbutton2.Click += new System.EventHandler(this.addThreeDFloorButton_Click); + // + // ThreeDFloorEditorWindow + // + this.AcceptButton = this.okButton; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.cancelButton; + this.ClientSize = new System.Drawing.Size(784, 548); + this.Controls.Add(this.no3dfloorspanel); + this.Controls.Add(this.sharedThreeDFloorsCheckBox); + this.Controls.Add(this.addThreeDFloorButton); + this.Controls.Add(this.cancelButton); + this.Controls.Add(this.okButton); + this.Controls.Add(this.threeDFloorPanel); + this.MaximizeBox = false; + this.MaximumSize = new System.Drawing.Size(800, 2000); + this.MinimizeBox = false; + this.MinimumSize = new System.Drawing.Size(800, 200); + this.Name = "ThreeDFloorEditorWindow"; + this.ShowIcon = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "3D floors"; + this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.ThreeDFloorEditorWindow_FormClosed); + this.Load += new System.EventHandler(this.ThreeDFloorEditorWindow_Load); + this.no3dfloorspanel.ResumeLayout(false); + this.no3dfloorspanel.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.FlowLayoutPanel threeDFloorPanel; + private System.Windows.Forms.Button okButton; + private System.Windows.Forms.Button cancelButton; + private System.Windows.Forms.Button addThreeDFloorButton; + private System.Windows.Forms.CheckBox sharedThreeDFloorsCheckBox; + private System.Windows.Forms.ToolTip toolTip1; + private System.Windows.Forms.Panel no3dfloorspanel; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Button add3dfloorbutton2; + } +} \ No newline at end of file diff --git a/Source/Plugins/3DFloorMode/Windows/ThreeDFloorEditorWindow.cs b/Source/Plugins/3DFloorMode/Windows/ThreeDFloorEditorWindow.cs new file mode 100644 index 00000000..3b0967ea --- /dev/null +++ b/Source/Plugins/3DFloorMode/Windows/ThreeDFloorEditorWindow.cs @@ -0,0 +1,267 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using System.Text.RegularExpressions; +using CodeImp.DoomBuilder.Windows; +using CodeImp.DoomBuilder.IO; +using CodeImp.DoomBuilder.Map; +using CodeImp.DoomBuilder.Rendering; +using CodeImp.DoomBuilder.Geometry; +using CodeImp.DoomBuilder.Editing; +using CodeImp.DoomBuilder.Plugins; +using CodeImp.DoomBuilder.Actions; +using CodeImp.DoomBuilder.Types; +using CodeImp.DoomBuilder.Config; +using CodeImp.DoomBuilder.Data; + +namespace CodeImp.DoomBuilder.ThreeDFloorMode +{ + public partial class ThreeDFloorEditorWindow : Form + { + List threedfloors; + List selectedsectors; + List controlpool; + + public List SelectedSectors { get { return selectedsectors; } } + + public List ThreeDFloors { get { return threedfloors; } set { threedfloors = value; } } + + public ThreeDFloorEditorWindow() + { + this.Location = new Point(Screen.PrimaryScreen.WorkingArea.Width/2, Screen.PrimaryScreen.WorkingArea.Height/2); + controlpool = new List(); + InitializeComponent(); + } + + private void ThreeDFloorEditorWindow_Load(object sender, EventArgs e) + { + selectedsectors = new List(General.Map.Map.GetSelectedSectors(true)); + sharedThreeDFloorsCheckBox.Checked = false; + FillThreeDFloorPanel(threedfloors); + } + + // Gets a control from the pool or creates a new one + private ThreeDFloorHelperControl GetThreeDFloorControl() + { + ThreeDFloorHelperControl ctrl = controlpool.FirstOrDefault(o => o.Used == false); + + if (ctrl == null) + { + ctrl = new ThreeDFloorHelperControl(); + ctrl.Used = true; + controlpool.Add(ctrl); + threeDFloorPanel.Controls.Add(ctrl); + } + else + { + ctrl.SetDefaults(); + ctrl.Used = true; + } + + return ctrl; + } + + private void okButton_Click(object sender, EventArgs e) + { + threedfloors = new List(); + + foreach (ThreeDFloorHelperControl ctrl in threeDFloorPanel.Controls.OfType()) + { + if (ctrl.Used) + { + ctrl.ApplyToThreeDFloor(); + threedfloors.Add(ctrl.ThreeDFloor); + } + } + + this.DialogResult = DialogResult.OK; + this.Close(); + } + + private void cancelButton_Click(object sender, EventArgs e) + { + this.DialogResult = DialogResult.Cancel; + this.Close(); + } + + public void addThreeDFloorButton_Click(object sender, EventArgs e) + { + ThreeDFloorHelperControl ctrl = GetThreeDFloorControl(); + + ctrl.Show(); + + threeDFloorPanel.ScrollControlIntoView(ctrl); + + no3dfloorspanel.Hide(); + } + + public void DuplicateThreeDFloor(ThreeDFloorHelperControl ctrl) + { + ThreeDFloorHelperControl dup = GetThreeDFloorControl(); + + dup.Update(ctrl); + dup.Show(); + + threeDFloorPanel.ScrollControlIntoView(dup); + } + + public void SplitThreeDFloor(ThreeDFloorHelperControl ctrl) + { + var items = new List(); + var controls = new List(); + int numsplits = 0; + + for (int i = 0; i < ctrl.checkedListBoxSectors.Items.Count; i++) + { + if(ctrl.checkedListBoxSectors.GetItemCheckState(i) == CheckState.Checked) + items.Add(i); + } + + int useitem = items.Count - 1; + + /* + Case 1: all tagged sectors are also selected sectors. In this case we can reuse + the original control, so one less additional control is needed + Case 2: multiple tagged sectors are also selected sectors. In this case we can + reuse the original control, so one less additional control is needed + Case 3: only one tagged sector is also the selected sector. In this case we + have to add exactly one additional control + */ + + controls.Add(ctrl); + + if (items.Count == 1) + { + numsplits = 1; + } + else + { + numsplits = items.Count - 1; + } + + for (int i = 0; i < numsplits; i++) + { + var newctrl = GetThreeDFloorControl(); + + newctrl.Update(ctrl); + newctrl.Show(); + + controls.Add(newctrl); + } + + for (int i = controls.Count - 1; i >= 0 ; i--) + { + for (int j = 0; j < items.Count; j++) + { + controls[i].checkedListBoxSectors.SetItemChecked(j, false); + } + + if (useitem >= 0) + controls[i].checkedListBoxSectors.SetItemChecked(items[useitem], true); + + useitem--; + } + } + + public void DetachThreeDFloor(ThreeDFloorHelperControl ctrl) + { + ThreeDFloorHelperControl dup = GetThreeDFloorControl(); + + dup.Update(ctrl); + + for (int i = 0; i < ctrl.checkedListBoxSectors.Items.Count; i++) + { + if (ctrl.checkedListBoxSectors.GetItemCheckState(i) == CheckState.Checked) + ctrl.checkedListBoxSectors.SetItemChecked(i, false); + } + + dup.Show(); + + threeDFloorPanel.ScrollControlIntoView(dup); + } + + private void FillThreeDFloorPanel(List threedfloors) + { + if (threedfloors.Count > 0) + { + // Create a new controller instance for each linedef and set its properties + foreach (ThreeDFloor tdf in threedfloors.OrderByDescending(o => o.TopHeight).ToList()) + { + ThreeDFloorHelperControl ctrl = GetThreeDFloorControl(); + ctrl.Update(tdf); + ctrl.Show(); + } + + no3dfloorspanel.Hide(); + } + else + { + no3dfloorspanel.Show(); + } + + // Hide all unused pool controls + if (controlpool.Count - threedfloors.Count > 0) + { + foreach (ThreeDFloorHelperControl ctrl in controlpool.Skip(threedfloors.Count)) + { + ctrl.Used = false; + ctrl.Hide(); + } + } + } + + private void sharedThreeDFloorsCheckBox_CheckedChanged(object sender, EventArgs e) + { + ICollection selectedSectors = General.Map.Map.GetSelectedSectors(true); + + if (selectedSectors.Count > 1 && sharedThreeDFloorsCheckBox.Checked) + { + var hideControls = new List(); + + foreach (Sector s in selectedSectors) + { + foreach (ThreeDFloorHelperControl ctrl in threeDFloorPanel.Controls.OfType()) + { + // If the selected sector is not in the control's tagged sectors the control + // should be hidden + if (!ctrl.ThreeDFloor.TaggedSectors.Contains(s)) + hideControls.Add(ctrl); + } + } + + foreach (ThreeDFloorHelperControl ctrl in hideControls) + { + // Hide controls, unless they are new + if (ctrl.IsNew == false) + ctrl.Hide(); + } + } + else + { + foreach (ThreeDFloorHelperControl ctrl in threeDFloorPanel.Controls.OfType()) + if (ctrl.Used) + ctrl.Show(); + } + } + + private void ThreeDFloorEditorWindow_FormClosed(object sender, FormClosedEventArgs e) + { + // Get rid of dummy sectors and makes all controls available + foreach (ThreeDFloorHelperControl ctrl in threeDFloorPanel.Controls.OfType().ToList()) + { + if (ctrl.Sector != null) + ctrl.Sector.Dispose(); + + ctrl.Used = false; + } + + General.Map.Map.Update(); + } + } +} diff --git a/Source/Plugins/3DFloorMode/Windows/ThreeDFloorEditorWindow.resx b/Source/Plugins/3DFloorMode/Windows/ThreeDFloorEditorWindow.resx new file mode 100644 index 00000000..84f73fcc --- /dev/null +++ b/Source/Plugins/3DFloorMode/Windows/ThreeDFloorEditorWindow.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + 17, 17 + + \ No newline at end of file diff --git a/build_git_generic.cmd b/build_git_generic.cmd index 42e66159..bc17ed48 100755 --- a/build_git_generic.cmd +++ b/build_git_generic.cmd @@ -182,6 +182,15 @@ msbuild "Source\Plugins\TagRange\TagRange.csproj" /t:Rebuild /p:Configuration=Re IF %ERRORLEVEL% NEQ 0 GOTO ERRORFAIL IF NOT EXIST "Build\Plugins\TagRange.dll" GOTO FILEFAIL +ECHO. +ECHO Compiling 3D Floor Mode plugin... +ECHO. +IF EXIST "Build\Plugins\ThreeDFloorMode.dll" DEL /F /Q "Build\Plugins\ThreeDFloorMode.dll" > NUL +IF EXIST "Source\Plugins\3DFloorMode\obj" RD /S /Q "Source\Plugins\3DFloorMode\obj" +msbuild "Source\Plugins\3DFloorMode\ThreeDFloorMode.csproj" /t:Rebuild /p:Configuration=Release /p:Platform=%PLATFORM% /v:minimal +IF %ERRORLEVEL% NEQ 0 GOTO ERRORFAIL +IF NOT EXIST "Build\Plugins\ThreeDFloorMode.dll" GOTO FILEFAIL + ECHO. ECHO Compiling vpo_dll... ECHO. @@ -191,7 +200,6 @@ msbuild "Source\Plugins\vpo_dll\vpo_dll.vcxproj" /t:Rebuild /p:Configuration=Rel IF %ERRORLEVEL% NEQ 0 GOTO ERRORFAIL IF NOT EXIST "Source\Plugins\VisplaneExplorer\Resources\vpo.dll" GOTO FILEFAIL - ECHO. ECHO Compiling Visplane Explorer plugin... ECHO. From b94dd31fdb3f519131156aa5d1dc4125c6fa64d8 Mon Sep 17 00:00:00 2001 From: biwa Date: Thu, 31 Oct 2019 21:16:59 +0100 Subject: [PATCH 18/34] - Fixed a bug where the wrong sectors and linedefs were highlighted in UDMF under certain conditions. Fixes #307. --- Source/Core/Map/Linedef.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Source/Core/Map/Linedef.cs b/Source/Core/Map/Linedef.cs index e270b65b..3c15366e 100755 --- a/Source/Core/Map/Linedef.cs +++ b/Source/Core/Map/Linedef.cs @@ -1010,11 +1010,15 @@ namespace CodeImp.DoomBuilder.Map // Limit intersection offset to the line if (bounded) { - if (General.Map.UDMF) + // We really don't want u to be 0 or 1, because that'd mean the distance will be measured + // from the vertices, which will result in linedefs being equally far away. We still need + // special handling for linedefs that are shorter than 1 mu (which is possible in UDMF) + // Detailed explanation here: https://github.com/jewalky/GZDoom-Builder-Bugfix/issues/307 + if (lengthinv > 1.0f) { u = Math.Max(0f, Math.Min(1f, u)); } - else // restore old way for visplane explorer (which doesn't work for UDMF anyway) + else { u = Math.Max(lengthinv, Math.Min(1f - lengthinv, u)); } From 7dc01a9497511b693f8f82d9dd3fcd78639c7f73 Mon Sep 17 00:00:00 2001 From: biwa Date: Thu, 31 Oct 2019 21:23:54 +0100 Subject: [PATCH 19/34] - Updated tools to use .Net 4.6.1 to be in line with GZDB-BF --- Source/Tools/ChangelogMaker/ChangelogMaker.csproj | 12 +++++++++++- Source/Tools/Updater/Updater.csproj | 10 +++++++++- Source/Tools/VersionFromEXE/VersionFromEXE.csproj | 12 +++++++++++- Source/Tools/VersionFromSVN/VersionFromGIT.csproj | 12 +++++++++++- 4 files changed, 42 insertions(+), 4 deletions(-) diff --git a/Source/Tools/ChangelogMaker/ChangelogMaker.csproj b/Source/Tools/ChangelogMaker/ChangelogMaker.csproj index 0eeea2d9..d45095a1 100755 --- a/Source/Tools/ChangelogMaker/ChangelogMaker.csproj +++ b/Source/Tools/ChangelogMaker/ChangelogMaker.csproj @@ -10,13 +10,14 @@ Properties mxd.ChangelogMaker ChangelogMaker - v3.5 + v4.6.1 512 3.5 + false @@ -26,6 +27,7 @@ DEBUG;TRACE prompt 4 + false none @@ -34,6 +36,7 @@ TRACE prompt 4 + false bin\x64\Debug\ @@ -41,6 +44,7 @@ x64 prompt MinimumRecommendedRules.ruleset + false bin\x64\Release\ @@ -49,6 +53,7 @@ x64 prompt MinimumRecommendedRules.ruleset + false bin\x86\Debug\ @@ -56,6 +61,7 @@ x86 prompt MinimumRecommendedRules.ruleset + false bin\x86\Release\ @@ -64,6 +70,7 @@ x86 prompt MinimumRecommendedRules.ruleset + false @@ -75,6 +82,9 @@ + + + YXTMNY12}wsdd( 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 literal 0 HcmV?d00001 diff --git a/Help/gzdb/features/classic_modes/editslopevertexdialog.png b/Help/gzdb/features/classic_modes/editslopevertexdialog.png new file mode 100644 index 0000000000000000000000000000000000000000..5227028af76c21613f7ef02b0891588a3dd9743f GIT binary patch literal 6343 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 + + + + Template + + + + + + + + + + +

3D Floor Mode

+ +
+

+This mode lets you manage the 3D floors. Available in Hexen format and UDMF
+Menu path: Mode -> 3D Floor Mode
+Action category: 3D Floor Plugin.
+Default key: None.
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ActionDefault keyUI buttonDescription
3D floor editing modenoneEnters the 3D floor editing mode
Cycle highlighted 3D floor downShift+ScrollDownnoneCycles down through the 3D floors present in the highlighted sector
Cycle highlighted 3D floor upShift+ScrollUpnoneCycles up through the 3D floors present in the highlighted sector
Select 3D floor control sectorShift+SnoneSelects the control sector of the highlighted 3D floor
Relocate 3D floor control sectorsnoneText buttonRelocates the 3D floor control sectors to the current position of the control sector area
none
+ +

The Control Sector Area

+ +Upon entering the 3D floor mode you will see a green square:
+ +
+ +This is the control sector area (CSA). All 3D floor control sectors will be created in this area. If there is not enough space in the CSA you will not be able to create more 3D floors.
+ +

Modifying The Control Sector Area

+ +You can resize and move the CSA. Resizing is done by simply dragging the edges or corners by holding the right mouse button. Moving is done by pointing the cursor inside the CSA and then drag it around by holding the right mouse button.
+ +

Tag Ranges

+ +You can define a range of tags that should be used for the 3D floor control sectors. This is done by pointing the cursor inside the CSA and then pressing the right mouse button. This will open the following dialog:
+
+
+
+To set a range of tags to use first check the Use tag range checkbox and then set the desired first and last tag. Note: if you run out of tags you will not be able to create more 3D floors.
+ +

Managing 3D Floors

+ +3D floor mode works similar to sectors mode. You can select and deselect sectors, but when you edit them (default: right mouse button) the 3D floor editing dialog will show up:
+
+
+
+To add a new 3D floor press either one of the *Add 3D floor* buttons. After doing so a widget will be shown in the window that lets you set the properties of the 3D floor. The green bar on the left side indicates that this 3D floor was newly added.
+
+Note: you can have many 3D floors in the same sectors. Just keep pressing the Add 3D floor button.
+
+
+
+On the left side you can set bottom (control sector floor) height and texture, the border texture and the top (control sector ceiling) height and texture of the 3D floor. The border height, or thickness, is calculated automatically.
+
+In the center let's you set commonly used properties, like the type and flags of the 3D floor, as well as it's alpha and the brightness below the 3D floor. It also shows the tags of the control sector, as well as a button to edit the all properties of the control sector.
+
+On the right a list of sectors is displayed. This list indicates which sectors this 3D floor is applied to. Currently selected sectors are shown at the top, currently not selected sectors at the bottom, grayed out. You can check or uncheck the selected sectors to apply or remove a 3D floor from this sector.
+
+On the very right are several buttons to speed up common workflows: + + + + + + + + + + + + + + + + + + + + + + + + + + +
ButtonAction
Duplicatecreates an exact copy of the 3D floor and adds it to all checked sectors
Splitcreates a new 3D floor for each checked sector, so that each sector has its unique 3D floor
Detachcreates a copy of the 3D floor, remocing the checked sectors from the source 3D floor, adding them to the newly created one
Check allchecks all sectors, applying the 3D floor to them
Uncheck allunchecks all sectors, removing the 3D floor from them
+ +

Using The Docker

+ +The plugin comes with a docker for the 3D floor editing mode. Make sure the dockers are always expanded by pressing the icon at the top of the docker if necessary. The docker will be selected by default when entering the 3D floor editing mode.
+
+When highlighting a sector the docker will show basic information about the 3D floors in this sector:
+
+
+
+You can use the cycle highlighted 3D floor up (default: Shift+ScrollUp) and cycle highlighted 3D floor down (default: Shift+ScrollDown) actions to cycle through the 3D floors in the docker. A green bar on the left side will indicate which 3D floor is highlighted. All sectors the highlighted 3D floor is applied to will be shown with a green tint.
+
+
+
+You can use the Select 3D floor control sector action (default: Shift+S) to select the control sector of the highlighted 3D floor. This is useful if you want to apply a slope to this 3D floor. + +

+
+ diff --git a/Help/gzdb/features/classic_modes/mode_slopes.html b/Help/gzdb/features/classic_modes/mode_slopes.html new file mode 100644 index 00000000..95ea6228 --- /dev/null +++ b/Help/gzdb/features/classic_modes/mode_slopes.html @@ -0,0 +1,120 @@ + + + + + Template + + + + + + + + + + +

Draw Slope Mode, Slope Mode

+ +
+

+

    +
  • Draw slope mode: draws slope definitions (slope vertex groups, SVG), that slope a sector using UDMF sector properties. Primary use it to make sloping 3D floors easy, but works on any sector. Only available in UDMF
  • +
  • Slope mode: modify the slope vertex groups created by draw slope mode. Only available in UDMF
  • +
+
+Menu path: Mode -> Draw Slope Mode
+Action category: 3D Floor Plugin.
+Default key: None.
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ActionDefault keyUI buttonDescription
Draw slope modenoneLets you draw a lope vertex group
Slope modenoneEnters slope mode that lets you edit slope vertex groups
Draw slope vertexLeft mouse buttonnoneDraws a slope vertex
Finish slope drawingRight mouse buttonnoneFinishes drawing a slope vertex group
+ +

Slope Data Sector

+ +The plugin needs a slope data sector to store custom UDMF fields that describe the slope vertex groups. This is required for undo/redo purposes and to keep the slope vertex groups saved between mapping sessions. When you enter Draw Slope Mode and no slope data sector is defined, you will get a pop-up asking you what to do.
+
+
+
+The easiest and recommended way is to let the plugin create the slope data sector in the Control Sector Area. Note: it is important that you do not edit or delete this sector. + +

Draw Slope Mode

+ +Draw Slope Mode allows you to draw slope vertex groups, that define a slope. If any sectors are selected the drawn slope will be assigned to them. + +

Drawing A Slope

+ +Drawing slopes works similar to drawing geometry. You always have to draw either two or three slope vertices, forming a slope vertex group. The slope vertices in the group define the plane of your slope.
+
+When you start drawing a slope you will see a yellow square with a black center at the mouse cursor. This is a slope vertex. You can place it anywhere by pressing the left mouse button. Repeat this with the second and optional third slope vertex. If you only want to use two slope vertices you can finish drawing by pressing the right mouse button.
+
+
+
+It is important to understand that the the slope vertex group only defines a plane - it does not say if it slopes a floor or ceiling of a sector. That also means that you can slope both floors and ceilings with a single slope vertex group, which can come in handy when sloping both normal sectors and 3D floors at the same time. + +

Assigning A Slope While Drawing A Slope

+ +When you have one or more sectors selected when drawing a slope, this slope will immediately be assigned to those sectors. Wile drawing the slope you will see three buttons in the menu bar, depicting F, C, and FC.
+
+
+
+If F is enabled (indicated by the blue border), the floor of the sectors will be sloped. If C is enabled, the ceiling of the sectors will be sloped. If FC is on, both the floor and ceiling of the sectors will be sloped. + +

Slope Mode

+ +Slope Mode lets you modify existing slope vertex groups, and assign the slopes to sectors. + +

Modifying Slope Vertices

+ +

Moving Slope Vertices

+ +Moving slope vertices works just like moving normal vertices - you can simple drag them around while holding the right mouse button. You can also select multiple vertices, either be left-clicking on them while holding the shift key, or by drawing a multi-selection around them. All selected slope vertices (indicated by their red color) will move simultaneously when being dragged around, just like any other geometry. + +

Editing Slope Vertices

+ +Slope vertices can be edited by hovering the mouse cursor over one and clicking the right mouse button. This will open the Edit Slope Vertex dialog.
+
+
+
+In this dialog you can modify the position of the slope vertex - most notably its Z position (height). The input boxes allow relative values (like ++128 to add 128 to the current value). Having multiple slope vertices selected will modify all of them.
+
+You can also add or remove the slope from sectors, more on that in the following sections.
+ +

Deleting A Slope Vertex / Slope Vertex Group

+ +You can not delete a single slope vertex - you can only remove a whole slope vertex group. To do so hover the mouse over one slope vertex of the slope vertex group and press the delete key. + + + +

+
+ diff --git a/Help/gzdb/features/classic_modes/mode_soundenvironment.html b/Help/gzdb/features/classic_modes/mode_soundenvironment.html index 148a55a5..6a2adb4b 100755 --- a/Help/gzdb/features/classic_modes/mode_soundenvironment.html +++ b/Help/gzdb/features/classic_modes/mode_soundenvironment.html @@ -19,7 +19,7 @@

-This mode is based on Sound Propagation Mode Plugin by Boris Iwansky (https://github.com/biwa/soundpropagationmode).
+This mode is based on Sound Propagation Mode Plugin by Boris Iwanski (https://github.com/biwa/soundpropagationmode).

Action category: Modes.
Default key: none.

diff --git a/Help/gzdb/features/classic_modes/mode_soundpropagation.html b/Help/gzdb/features/classic_modes/mode_soundpropagation.html index 6fe53260..2f7c2f65 100755 --- a/Help/gzdb/features/classic_modes/mode_soundpropagation.html +++ b/Help/gzdb/features/classic_modes/mode_soundpropagation.html @@ -19,7 +19,7 @@

-This mode is based on Sound Propagation Mode Plugin by Boris Iwansky (https://github.com/biwa/soundpropagationmode).
+This mode is based on Sound Propagation Mode Plugin by Boris Iwanski (https://github.com/biwa/soundpropagationmode).

Action category: Modes.
Default key: none.

diff --git a/Help/gzdb/features/classic_modes/new3dfloor.png b/Help/gzdb/features/classic_modes/new3dfloor.png new file mode 100644 index 0000000000000000000000000000000000000000..7fd8764b6c08bc17f8af7638904bc9b17bfefbec GIT binary patch literal 28586 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 literal 0 HcmV?d00001 diff --git a/Help/gzdb/features/classic_modes/no3dfloors.png b/Help/gzdb/features/classic_modes/no3dfloors.png new file mode 100644 index 0000000000000000000000000000000000000000..901b59d70ca2e121a9fa6add65bc2703bcd9e476 GIT binary patch literal 4355 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 literal 0 HcmV?d00001 diff --git a/Help/gzdb/features/classic_modes/slopedatasector.png b/Help/gzdb/features/classic_modes/slopedatasector.png new file mode 100644 index 0000000000000000000000000000000000000000..0671fe5a370fa2789ce4a47dc74bd7855bb14a90 GIT binary patch literal 7950 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 Date: Fri, 15 Nov 2019 21:56:25 +0100 Subject: [PATCH 26/34] - 3D Floor Mode: mode is now only available in Hexen format and UDMF - 3D Floor Mode: removed non-functional "Spline" checkbox from the Edit Slope Vertex dialog --- Source/Plugins/3DFloorMode/ThreeDFloorMode.cs | 1 + .../Plugins/3DFloorMode/Windows/SlopeVertexEditForm.Designer.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/Source/Plugins/3DFloorMode/ThreeDFloorMode.cs b/Source/Plugins/3DFloorMode/ThreeDFloorMode.cs index efc11044..093ed5f2 100644 --- a/Source/Plugins/3DFloorMode/ThreeDFloorMode.cs +++ b/Source/Plugins/3DFloorMode/ThreeDFloorMode.cs @@ -51,6 +51,7 @@ namespace CodeImp.DoomBuilder.ThreeDFloorMode ButtonImage = "ThreeDFloorIcon.png", // Image resource name for the button ButtonOrder = int.MinValue + 501, // Position of the button (lower is more to the left) ButtonGroup = "000_editing", + SupportedMapFormats = new[] { "HexenMapSetIO", "UniversalMapSetIO" }, UseByDefault = true, SafeStartMode = false, Volatile = false)] diff --git a/Source/Plugins/3DFloorMode/Windows/SlopeVertexEditForm.Designer.cs b/Source/Plugins/3DFloorMode/Windows/SlopeVertexEditForm.Designer.cs index 4979ca50..915106f0 100644 --- a/Source/Plugins/3DFloorMode/Windows/SlopeVertexEditForm.Designer.cs +++ b/Source/Plugins/3DFloorMode/Windows/SlopeVertexEditForm.Designer.cs @@ -283,6 +283,7 @@ this.spline.TabIndex = 10; this.spline.Text = "Spline"; this.spline.UseVisualStyleBackColor = true; + this.spline.Visible = false; // // SlopeVertexEditForm // From 490fa56749ec0f6378ec8dd4750a4474bb2d1ed0 Mon Sep 17 00:00:00 2001 From: biwa Date: Fri, 15 Nov 2019 22:34:39 +0100 Subject: [PATCH 27/34] - 3D Floor Mode: fixed a bug where orphaned managed control sectors would be overwritten by relocating the control sectors --- .../Plugins/3DFloorMode/ControlSectorArea.cs | 20 ++++++++++++++++++- Source/Plugins/3DFloorMode/ThreeDFloorMode.cs | 1 + 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/Source/Plugins/3DFloorMode/ControlSectorArea.cs b/Source/Plugins/3DFloorMode/ControlSectorArea.cs index 7c441215..0e085c52 100644 --- a/Source/Plugins/3DFloorMode/ControlSectorArea.cs +++ b/Source/Plugins/3DFloorMode/ControlSectorArea.cs @@ -432,8 +432,26 @@ namespace CodeImp.DoomBuilder.ThreeDFloorMode { // Managed control sectors have the custom UDMF field "user_managed_3d_floor" set to true // So if the field is NOT set, add the sector to the blockmap - if (s.Fields.GetValue("user_managed_3d_floor", false) == false) + bool managed = s.Fields.GetValue("user_managed_3d_floor", false); + + if (managed == false) blockmap.AddSector(s); + else // When a tag was manually removed a control sector still might have the user_managed_3d_floor field, but not be + { // recognized as a 3D floor control sector. In that case also add the sector to the blockmap + bool orphaned = true; + + foreach(ThreeDFloor tdf in ((ThreeDFloorHelperMode)General.Editing.Mode).ThreeDFloors) + { + if(tdf.Sector == s) + { + orphaned = false; + break; + } + } + + if (orphaned) + blockmap.AddSector(s); + } } } else diff --git a/Source/Plugins/3DFloorMode/ThreeDFloorMode.cs b/Source/Plugins/3DFloorMode/ThreeDFloorMode.cs index 093ed5f2..dedd2757 100644 --- a/Source/Plugins/3DFloorMode/ThreeDFloorMode.cs +++ b/Source/Plugins/3DFloorMode/ThreeDFloorMode.cs @@ -94,6 +94,7 @@ namespace CodeImp.DoomBuilder.ThreeDFloorMode #region ================== Properties public override object HighlightedObject { get { return highlighted; } } + public List ThreeDFloors { get { return threedfloors; } } #endregion From cbaa0c030c0b0250759aa40e00f988b91c0b4fc5 Mon Sep 17 00:00:00 2001 From: biwa Date: Sat, 30 Nov 2019 17:05:00 +0100 Subject: [PATCH 28/34] Long names can now used for flats (again) --- Source/Core/Data/DataManager.cs | 16 +--------------- Source/Core/Data/FileImage.cs | 26 ++++---------------------- Source/Core/Data/PK3FileImage.cs | 4 ---- 3 files changed, 5 insertions(+), 41 deletions(-) diff --git a/Source/Core/Data/DataManager.cs b/Source/Core/Data/DataManager.cs index 4bd180cd..5f268556 100755 --- a/Source/Core/Data/DataManager.cs +++ b/Source/Core/Data/DataManager.cs @@ -1368,15 +1368,8 @@ namespace CodeImp.DoomBuilder.Data // This checks if a flat is known public bool GetFlatExists(long longname) { - // [ZZ] return nonexistent name for bad flats. if (flats.ContainsKey(longname)) - { - // [ZZ] long name is long. a doom flat with a long name is invalid. - ImageData id = flats[longname]; - if (id is PK3FileImage && ((PK3FileImage)id).IsBadForLongTextureNames) - return false; return true; - } return flatnamesshorttofull.ContainsKey(longname); } @@ -1398,14 +1391,7 @@ namespace CodeImp.DoomBuilder.Data if(flatnamesshorttofull.ContainsKey(longname)) return flats[flatnamesshorttofull[longname]]; //mxd if (flats.ContainsKey(longname)) - { - // [ZZ] long name is long. a doom flat with a long name is invalid. - ImageData id = flats[longname]; - if (id is PK3FileImage && ((PK3FileImage)id).IsBadForLongTextureNames) - return unknownimage; - - return id; - } + return flats[longname]; // Return null image return unknownimage; //mxd diff --git a/Source/Core/Data/FileImage.cs b/Source/Core/Data/FileImage.cs index b02f3f30..05e99b44 100755 --- a/Source/Core/Data/FileImage.cs +++ b/Source/Core/Data/FileImage.cs @@ -30,9 +30,6 @@ namespace CodeImp.DoomBuilder.Data #region ================== Variables private readonly int probableformat; - private readonly string _c_name; - private readonly string _c_filepathname; - private readonly bool isinternal = false; #endregion @@ -42,8 +39,6 @@ namespace CodeImp.DoomBuilder.Data public FileImage(string name, string filepathname, bool asflat) { // Initialize - _c_name = name; // this is used to call SetName later - _c_filepathname = filepathname; // this is used to call SetName later this.isFlat = asflat; //mxd if (asflat) @@ -69,8 +64,6 @@ namespace CodeImp.DoomBuilder.Data public FileImage(string name, string filepathname, bool asflat, float scalex, float scaley) { // Initialize - _c_name = name; // this is used to call SetName later - _c_filepathname = filepathname; // this is used to call SetName later this.scale.x = scalex; this.scale.y = scaley; this.isFlat = asflat; //mxd @@ -86,12 +79,7 @@ namespace CodeImp.DoomBuilder.Data //mxd. Constructor for loading internal images internal FileImage(string name, string filepathname) { - // Initialize - _c_name = name; // this is used to call SetName later - _c_filepathname = filepathname; // this is used to call SetName later - probableformat = ImageDataFormat.DOOMPICTURE; - isinternal = true; SetName(name, filepathname, true, 1); @@ -108,10 +96,12 @@ namespace CodeImp.DoomBuilder.Data //mxd: also, zdoom uses '/' as directory separator char. //mxd: and doesn't recognize long texture names in a root folder / pk3/7 root //[ZZ] and doesn't work with flats in Doom format (added SetName call to post-load to validate this) + // biwa. It works (again?) with Doom flat format private void SetName(string name, string filepathname) { - SetName(name, filepathname, General.Map.Config.UseLongTextureNames, (probableformat == ImageDataFormat.DOOMFLAT) ? -1 : 0); - } + //SetName(name, filepathname, General.Map.Config.UseLongTextureNames, (probableformat == ImageDataFormat.DOOMFLAT) ? -1 : 0); + SetName(name, filepathname, General.Map.Config.UseLongTextureNames, 0); + } // prevent long texture names by forcelongtexturename=-1 private void SetName(string name, string filepathname, bool uselongtexturenames, int forcelongtexturename) @@ -160,8 +150,6 @@ namespace CodeImp.DoomBuilder.Data // Load file data if (bitmap != null) bitmap.Dispose(); bitmap = null; - bool isBadForLongTextureNames = false; - MemoryStream filedata = null; try { @@ -179,9 +167,6 @@ namespace CodeImp.DoomBuilder.Data IImageReader reader = ImageDataFormat.GetImageReader(filedata, probableformat, General.Map.Data.Palette); if (!(reader is UnknownImageReader)) { - // [ZZ] check for doom flat, always short name for these - if (reader is DoomFlatReader) - isBadForLongTextureNames = true; // Load the image filedata.Seek(0, SeekOrigin.Begin); try { bitmap = reader.ReadAsBitmap(filedata); } @@ -208,9 +193,6 @@ namespace CodeImp.DoomBuilder.Data filedata.Dispose(); } - // [ZZ] validate disabled long texture names for flats. (and enabled for everything else, if our guessed format was wrong) - SetName(_c_name, _c_filepathname, General.Map.Config.UseLongTextureNames, isBadForLongTextureNames ? -1 : (isinternal ? 1 : 0)); - // Pass on to base base.LocalLoadImage(); } diff --git a/Source/Core/Data/PK3FileImage.cs b/Source/Core/Data/PK3FileImage.cs index 79906eb3..a41f7ae2 100755 --- a/Source/Core/Data/PK3FileImage.cs +++ b/Source/Core/Data/PK3FileImage.cs @@ -128,10 +128,6 @@ namespace CodeImp.DoomBuilder.Data IImageReader reader = ImageDataFormat.GetImageReader(filedata, probableformat, General.Map.Data.Palette); if(!(reader is UnknownImageReader)) { - // [ZZ] check for flat type - if (reader is DoomFlatReader) - isBadForLongTextureNames = true; - // Load the image filedata.Seek(0, SeekOrigin.Begin); try From 8824a2bb94bd0b15a5226ac6d33b7442125efd13 Mon Sep 17 00:00:00 2001 From: biwa Date: Sat, 30 Nov 2019 17:49:21 +0100 Subject: [PATCH 29/34] Fixed a bug where the wrong texture/flat with the same name would be displayed in the texture browser when they were loaded from a PK3 or directory --- Source/Core/Controls/ImageBrowserControl.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Source/Core/Controls/ImageBrowserControl.cs b/Source/Core/Controls/ImageBrowserControl.cs index ebdff7c3..bf6c604e 100755 --- a/Source/Core/Controls/ImageBrowserControl.cs +++ b/Source/Core/Controls/ImageBrowserControl.cs @@ -481,9 +481,11 @@ namespace CodeImp.DoomBuilder.Controls // biwa. Removes all duplicates. That was done each time in AddItem before. Much faster // to do it in one go. Not sure when there are actually duplicates + // Depending on whether a floor or a wall is selected the corrosponding images come first + // in the list, so alawys keep the first occurence public void MakeTexturesUnique() { - items = items.GroupBy(item => item.TextureName).Select(item => item.Last()).ToList(); + items = items.GroupBy(item => item.TextureName).Select(item => item.First()).ToList(); } // This fills the list based on the objectname filter From 2699f5793bcea5f1bba26829525b22a638b051ae Mon Sep 17 00:00:00 2001 From: biwa Date: Tue, 3 Dec 2019 15:23:49 +0100 Subject: [PATCH 30/34] Fixed an issue where the ZScript parser aborted with a cryptic error message when encountering a number that was too small or big. It now clamps the value to min/max for the data type and prints a warning --- Source/Core/ZDoom/ZScriptParser.cs | 4 ++++ Source/Core/ZDoom/ZScriptTokenizer.cs | 29 ++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/Source/Core/ZDoom/ZScriptParser.cs b/Source/Core/ZDoom/ZScriptParser.cs index 46e6f347..c603c4ea 100755 --- a/Source/Core/ZDoom/ZScriptParser.cs +++ b/Source/Core/ZDoom/ZScriptParser.cs @@ -309,6 +309,10 @@ namespace CodeImp.DoomBuilder.ZDoom return null; } + // biwa. Report a recoverable parsing problem + if (!string.IsNullOrEmpty(token.WarningMessage)) + LogWarning(token.WarningMessage); + if ((token.Type == ZScriptTokenType.Semicolon || token.Type == ZScriptTokenType.Comma) && nestingLevel == 0 && !betweenparen) { diff --git a/Source/Core/ZDoom/ZScriptTokenizer.cs b/Source/Core/ZDoom/ZScriptTokenizer.cs index 0f55c529..891fe3f4 100755 --- a/Source/Core/ZDoom/ZScriptTokenizer.cs +++ b/Source/Core/ZDoom/ZScriptTokenizer.cs @@ -101,6 +101,7 @@ namespace CodeImp.DoomBuilder.ZDoom public ZScriptToken() { IsValid = true; + WarningMessage = String.Empty; } public ZScriptTokenType Type { get; internal set; } @@ -108,6 +109,7 @@ namespace CodeImp.DoomBuilder.ZDoom public int ValueInt { get; internal set; } public double ValueDouble { get; internal set; } public bool IsValid { get; internal set; } + public string WarningMessage { get; internal set; } public override string ToString() { @@ -330,9 +332,34 @@ namespace CodeImp.DoomBuilder.ZDoom tok.ValueInt = (int)tok.ValueDouble; } } + catch (OverflowException) // biwa. If the value is too small or too big set it to the min or max, and set a warning message + { + tok.WarningMessage = "Number " + tok.Value + " too " + (tok.Value[0] == '-' ? "small" : "big") + ". Set to "; + + if (ishex || isoctal || !isdouble) + { + if (tok.Value[0] == '-') + tok.ValueInt = Int32.MinValue; + else + tok.ValueInt = Int32.MaxValue; + + tok.ValueDouble = tok.ValueInt; + tok.WarningMessage += tok.ValueInt; + } + else if (isdouble) + { + if (tok.Value[0] == '-') + tok.ValueDouble = Double.MinValue; + else + tok.ValueDouble = Double.MaxValue; + + tok.ValueInt = (int)tok.ValueDouble; + tok.WarningMessage += tok.ValueDouble; + } + } catch (Exception) { - //throw new Exception(tok.ToString()); + // throw new Exception(tok.ToString()); return null; } From c9e7551ca380169a6ae67094a72690b323424457 Mon Sep 17 00:00:00 2001 From: biwa Date: Sun, 8 Dec 2019 01:14:21 +0100 Subject: [PATCH 31/34] Added ZScript mixin class support --- Source/Core/ZDoom/ZScriptActorStructure.cs | 53 ++++- Source/Core/ZDoom/ZScriptParser.cs | 242 ++++++++++++++------- 2 files changed, 210 insertions(+), 85 deletions(-) diff --git a/Source/Core/ZDoom/ZScriptActorStructure.cs b/Source/Core/ZDoom/ZScriptActorStructure.cs index 96b3814a..f7c8370d 100755 --- a/Source/Core/ZDoom/ZScriptActorStructure.cs +++ b/Source/Core/ZDoom/ZScriptActorStructure.cs @@ -9,13 +9,22 @@ namespace CodeImp.DoomBuilder.ZDoom { public sealed class ZScriptActorStructure : ActorStructure { - // privates - private ZScriptParser parser; + #region ================== Variables + + private ZScriptParser parser; private Stream stream; private ZScriptTokenizer tokenizer; - // ======== + private List mixins; - internal static bool ParseGZDBComment(Dictionary> props, string text) + #endregion + + #region ================== Properties + + public List Mixins { get { return mixins; } } + + #endregion + + internal static bool ParseGZDBComment(Dictionary> props, string text) { if (string.IsNullOrWhiteSpace(text)) return false; @@ -373,6 +382,30 @@ namespace CodeImp.DoomBuilder.ZDoom return true; } + private bool ParseMixin() + { + // mixin identifier; + tokenizer.SkipWhitespace(); + ZScriptToken token = tokenizer.ExpectToken(ZScriptTokenType.Identifier); + if (token == null || !token.IsValid) + { + parser.ReportError("Expected mixin class name, got " + ((Object)token ?? "").ToString()); + return false; + } + + mixins.Add(token.Value.ToLowerInvariant()); + + tokenizer.SkipWhitespace(); + token = tokenizer.ExpectToken(ZScriptTokenType.Semicolon); + if (token == null || !token.IsValid) + { + parser.ReportError("Expected semicolon, got " + ((Object)token ?? "").ToString()); + return false; + } + + return true; + } + private bool ParseProperty() { // property identifier: identifier, identifier, identifier, ...; @@ -462,7 +495,9 @@ namespace CodeImp.DoomBuilder.ZDoom classname = _classname; replaceclass = _replacesname; - //baseclass = parser.GetArchivedActorByName(_parentname); // this is not guaranteed to work here + //baseclass = parser.GetArchivedActorByName(_parentname); // this is not guaranteed to work here + + mixins = new List(); ZScriptToken cls_open = tokenizer.ExpectToken(ZScriptTokenType.OpenCurly); if (cls_open == null || !cls_open.IsValid) @@ -531,7 +566,7 @@ namespace CodeImp.DoomBuilder.ZDoom // apparently we can have a struct inside a class, but not another class. case "struct": - if (!parser.ParseClassOrStruct(true, false, null)) + if (!parser.ParseClassOrStruct(true, false, false, null)) return; continue; @@ -547,6 +582,12 @@ namespace CodeImp.DoomBuilder.ZDoom return; continue; + // mixins + case "mixin": + if (!ParseMixin()) + return; + continue; + default: stream.Position = ocpos; break; diff --git a/Source/Core/ZDoom/ZScriptParser.cs b/Source/Core/ZDoom/ZScriptParser.cs index c603c4ea..1c4d4809 100755 --- a/Source/Core/ZDoom/ZScriptParser.cs +++ b/Source/Core/ZDoom/ZScriptParser.cs @@ -21,6 +21,7 @@ namespace CodeImp.DoomBuilder.ZDoom public string ParentName { get; internal set; } public ZScriptActorStructure Actor { get; internal set; } internal DecorateCategoryInfo Region; + public bool IsMixin { get; internal set; } // these are used for parsing and error reporting public ZScriptParser Parser { get; internal set; } @@ -33,7 +34,7 @@ namespace CodeImp.DoomBuilder.ZDoom // textresourcepath public string TextResourcePath { get; internal set; } - internal ZScriptClassStructure(ZScriptParser parser, string classname, string replacesname, string parentname, DecorateCategoryInfo region) + internal ZScriptClassStructure(ZScriptParser parser, string classname, string replacesname, string parentname, bool ismixin, DecorateCategoryInfo region) { Parser = parser; @@ -49,6 +50,8 @@ namespace CodeImp.DoomBuilder.ZDoom ParentName = parentname; Actor = null; Region = region; + + IsMixin = ismixin; } internal void RestoreStreamData() @@ -87,7 +90,7 @@ namespace CodeImp.DoomBuilder.ZDoom if (ReplacementName != null) log_inherits += ((log_inherits.Length > 0) ? ", " : "") + "replaces " + ReplacementName; if (log_inherits.Length > 0) log_inherits = " (" + log_inherits + ")"; - if (isactor) + if (isactor || IsMixin) { Actor = new ZScriptActorStructure(Parser, Region, ClassName, ReplacementName, ParentName); if (Parser.HasError) @@ -156,6 +159,10 @@ namespace CodeImp.DoomBuilder.ZDoom private Dictionary allclasses; private List allclasseslist; + // Mixin classes + private Dictionary mixinclasses; + private List mixinclasseslist; + //mxd. Includes tracking private HashSet parsedlumps; @@ -575,7 +582,7 @@ namespace CodeImp.DoomBuilder.ZDoom return name; } - internal bool ParseClassOrStruct(bool isstruct, bool extend, DecorateCategoryInfo region) + internal bool ParseClassOrStruct(bool isstruct, bool extend, bool mixin, DecorateCategoryInfo region) { // 'class' keyword is already parsed tokenizer.SkipWhitespace(); @@ -733,21 +740,37 @@ namespace CodeImp.DoomBuilder.ZDoom if (extend) log_inherits += ((log_inherits.Length > 0) ? ", " : "") + "extends"; if (log_inherits.Length > 0) log_inherits = " (" + log_inherits + ")"; - // now if we are a class, and we inherit actor, parse this entry as an actor. don't process extensions. - if (!isstruct && !extend) - { - ZScriptClassStructure cls = new ZScriptClassStructure(this, tok_classname.Value, (tok_replacename != null) ? tok_replacename.Value : null, (tok_parentname != null) ? tok_parentname.Value : null, region); - cls.Position = cpos; - string clskey = cls.ClassName.ToLowerInvariant(); - if (allclasses.ContainsKey(clskey)) - { - ReportError("Class "+cls.ClassName+" is double-defined"); - return false; - } + // now if we are a class, and we inherit actor, parse this entry as an actor. don't process extensions. + if (!isstruct && !extend && !mixin) + { + ZScriptClassStructure cls = new ZScriptClassStructure(this, tok_classname.Value, (tok_replacename != null) ? tok_replacename.Value : null, (tok_parentname != null) ? tok_parentname.Value : null, false, region); + cls.Position = cpos; + string clskey = cls.ClassName.ToLowerInvariant(); + if (allclasses.ContainsKey(clskey)) + { + ReportError("Class " + cls.ClassName + " is double-defined"); + return false; + } - allclasses.Add(cls.ClassName.ToLowerInvariant(), cls); - allclasseslist.Add(cls); - } + allclasses.Add(cls.ClassName.ToLowerInvariant(), cls); + allclasseslist.Add(cls); + } + else if (mixin) + { + // This is a bit ugly. We're treating mixin classes as actors, even though they aren't. But otherwise the parser + // doesn't parse all the actor info we need + ZScriptClassStructure cls = new ZScriptClassStructure(this, tok_classname.Value, null, null, true, region); + cls.Position = cpos; + string clskey = cls.ClassName.ToLowerInvariant(); + if(mixinclasses.ContainsKey(clskey)) + { + ReportError("Mixin class " + cls.ClassName + " is double-defines"); + return false; + } + + mixinclasses.Add(cls.ClassName.ToLowerInvariant(), cls); + mixinclasseslist.Add(cls); + } //LogWarning(string.Format("Parsed {0} {1}{2}", (isstruct ? "struct" : "class"), tok_classname.Value, log_inherits)); @@ -894,17 +917,28 @@ namespace CodeImp.DoomBuilder.ZDoom ReportError("Expected class or struct, got " + ((Object)token ?? "").ToString()); return false; } - if (!ParseClassOrStruct((token.Value.ToLowerInvariant() == "struct"), true, (regions.Count > 0 ? regions.Last() : null))) + if (!ParseClassOrStruct((token.Value.ToLowerInvariant() == "struct"), true, false, (regions.Count > 0 ? regions.Last() : null))) return false; break; - case "class": + case "mixin": + tokenizer.SkipWhitespace(); + token = tokenizer.ExpectToken(ZScriptTokenType.Identifier); + if(token == null || !token.IsValid ||((token.Value.ToLower() != "class"))) + { + ReportError("Expected class, got " + ((Object)token ?? "").ToString()); + return false; + } + if (!ParseClassOrStruct(false, false, true, (regions.Count > 0 ? regions.Last() : null))) + return false; + break; + case "class": // todo parse class - if (!ParseClassOrStruct(false, false, (regions.Count > 0 ? regions.Last() : null))) + if (!ParseClassOrStruct(false, false, false, (regions.Count > 0 ? regions.Last() : null))) return false; break; case "struct": // todo parse struct - if (!ParseClassOrStruct(true, false, null)) + if (!ParseClassOrStruct(true, false, false, null)) return false; break; case "const": @@ -948,83 +982,131 @@ namespace CodeImp.DoomBuilder.ZDoom return false; } + // Parse mixin class data + foreach(ZScriptClassStructure cls in mixinclasseslist) + { + if (!cls.Process()) + return false; + } + // set datastream to null so that log messages aren't output using incorrect line numbers Stream odatastream = datastream; datastream = null; - // inject superclasses, since everything is parsed by now + // inject superclasses, and mixins, since everything is parsed by now Dictionary things = General.Map.Config.GetThingTypes(); foreach (ZScriptClassStructure cls in allclasseslist) { ActorStructure actor = cls.Actor; - if (actor != null && cls.ParentName != null && cls.ParentName.ToLowerInvariant() != "thinker") // don't try to inherit this one - { - actor.baseclass = GetArchivedActorByName(cls.ParentName, true); - string inheritclass = cls.ParentName; + if (actor != null) + { + // Inheritance + if (cls.ParentName != null && cls.ParentName.ToLowerInvariant() != "thinker") // don't try to inherit this one) + { + actor.baseclass = GetArchivedActorByName(cls.ParentName, true); + string inheritclass = cls.ParentName; - //check if this class inherits from a class defined in game configuration - string inheritclasscheck = inheritclass.ToLowerInvariant(); + //check if this class inherits from a class defined in game configuration + string inheritclasscheck = inheritclass.ToLowerInvariant(); - // inherit args from base class - if (actor.baseclass != null) - { - for (int i = 0; i < 5; i++) - { - if (actor.args[i] == null) - actor.args[i] = actor.baseclass.args[i]; - } - } + // inherit args from base class + if (actor.baseclass != null) + { + for (int i = 0; i < 5; i++) + { + if (actor.args[i] == null) + actor.args[i] = actor.baseclass.args[i]; + } + } - bool thingfound = false; - foreach (KeyValuePair ti in things) - { - if (!string.IsNullOrEmpty(ti.Value.ClassName) && ti.Value.ClassName.ToLowerInvariant() == inheritclasscheck) - { - //states - // [ZZ] allow internal prefix here. it can inherit MapSpot, light, or other internal stuff. - if (actor.states.Count == 0 && !string.IsNullOrEmpty(ti.Value.Sprite)) - actor.states.Add("spawn", new StateStructure(ti.Value.Sprite.StartsWith(DataManager.INTERNAL_PREFIX) ? ti.Value.Sprite : ti.Value.Sprite.Substring(0, 5))); + bool thingfound = false; + foreach (KeyValuePair ti in things) + { + if (!string.IsNullOrEmpty(ti.Value.ClassName) && ti.Value.ClassName.ToLowerInvariant() == inheritclasscheck) + { + //states + // [ZZ] allow internal prefix here. it can inherit MapSpot, light, or other internal stuff. + if (actor.states.Count == 0 && !string.IsNullOrEmpty(ti.Value.Sprite)) + actor.states.Add("spawn", new StateStructure(ti.Value.Sprite.StartsWith(DataManager.INTERNAL_PREFIX) ? ti.Value.Sprite : ti.Value.Sprite.Substring(0, 5))); - if (actor.baseclass == null) - { - //flags - if (ti.Value.Hangs && !actor.flags.ContainsKey("spawnceiling")) - actor.flags["spawnceiling"] = true; + if (actor.baseclass == null) + { + //flags + if (ti.Value.Hangs && !actor.flags.ContainsKey("spawnceiling")) + actor.flags["spawnceiling"] = true; - if (ti.Value.Blocking > 0 && !actor.flags.ContainsKey("solid")) - actor.flags["solid"] = true; + if (ti.Value.Blocking > 0 && !actor.flags.ContainsKey("solid")) + actor.flags["solid"] = true; - //properties - if (!actor.props.ContainsKey("height")) - actor.props["height"] = new List { ti.Value.Height.ToString() }; + //properties + if (!actor.props.ContainsKey("height")) + actor.props["height"] = new List { ti.Value.Height.ToString() }; - if (!actor.props.ContainsKey("radius")) - actor.props["radius"] = new List { ti.Value.Radius.ToString() }; - } + if (!actor.props.ContainsKey("radius")) + actor.props["radius"] = new List { ti.Value.Radius.ToString() }; + } - // [ZZ] inherit arguments from game configuration - // - if (!actor.props.ContainsKey("$clearargs")) - { - for (int i = 0; i < 5; i++) - { - if (actor.args[i] != null) - continue; // don't touch it if we already have overrides + // [ZZ] inherit arguments from game configuration + // + if (!actor.props.ContainsKey("$clearargs")) + { + for (int i = 0; i < 5; i++) + { + if (actor.args[i] != null) + continue; // don't touch it if we already have overrides - ArgumentInfo arg = ti.Value.Args[i]; - if (arg != null && arg.Used) - actor.args[i] = arg; - } - } + ArgumentInfo arg = ti.Value.Args[i]; + if (arg != null && arg.Used) + actor.args[i] = arg; + } + } - thingfound = true; - break; - } + thingfound = true; + break; + } - if (actor.baseclass == null && !thingfound) - LogWarning("Unable to find \"" + inheritclass + "\" class to inherit from, while parsing \"" + cls.ClassName + "\""); - } - } + if (actor.baseclass == null && !thingfound) + LogWarning("Unable to find \"" + inheritclass + "\" class to inherit from, while parsing \"" + cls.ClassName + "\""); + } + } + + // Mixins. https://zdoom.org/wiki/ZScript_mixins + if (((ZScriptActorStructure)actor).Mixins.Count > 0) + { + foreach(string mixinclassname in ((ZScriptActorStructure)actor).Mixins) + { + if(!mixinclasses.ContainsKey(mixinclassname)) + { + LogWarning("Unable to find \"" + mixinclassname + "\" mixin class while parsing \"" + actor.ClassName + "\""); + continue; + } + + ZScriptClassStructure mixincls = mixinclasses[mixinclassname]; + + // States + if(actor.states.Count == 0 && mixincls.Actor.states.Count != 0) + { + // Can't use HasState and GetState here, because it does some magic that will not work for mixins + if (!actor.states.ContainsKey("spawn") && mixincls.Actor.states.ContainsKey("spawn")) + actor.states.Add("spawn", mixincls.Actor.GetState("spawn")); + } + + // Properties + if (!actor.props.ContainsKey("height") && mixincls.Actor.props.ContainsKey("height")) + actor.props["height"] = new List(mixincls.Actor.props["height"]); + + if (!actor.props.ContainsKey("radius") && mixincls.Actor.props.ContainsKey("radius")) + actor.props["radius"] = new List(mixincls.Actor.props["radius"]); + + // Flags + if (!actor.flags.ContainsKey("spawnceiling") && mixincls.Actor.flags.ContainsKey("spawnceiling")) + actor.flags["spawnceiling"] = true; + + if (!actor.flags.ContainsKey("solid") && mixincls.Actor.flags.ContainsKey("solid")) + actor.flags["solid"] = true; + } + } + } } // validate user variables (no variables should shadow parent variables) @@ -1101,6 +1183,8 @@ namespace CodeImp.DoomBuilder.ZDoom parsedlumps = new HashSet(StringComparer.OrdinalIgnoreCase); //mxd allclasses = new Dictionary(); allclasseslist = new List(); + mixinclasses = new Dictionary(); + mixinclasseslist = new List(); } #endregion From 31eaf98cbe76c81d4c63dc93125b0b753d506e6c Mon Sep 17 00:00:00 2001 From: biwa Date: Sat, 14 Dec 2019 11:52:46 +0100 Subject: [PATCH 32/34] Using --- and +++ now also works correctly for the height offset in the edit sector properties dialog --- Source/Core/Controls/ButtonsNumericTextbox.cs | 6 ++++ Source/Core/Controls/NumericTextbox.cs | 6 ++++ Source/Core/Windows/SectorEditForm.cs | 36 ++++++++++++++----- Source/Core/Windows/SectorEditFormUDMF.cs | 23 +++++++++--- 4 files changed, 57 insertions(+), 14 deletions(-) diff --git a/Source/Core/Controls/ButtonsNumericTextbox.cs b/Source/Core/Controls/ButtonsNumericTextbox.cs index fd05785d..e987d0f4 100755 --- a/Source/Core/Controls/ButtonsNumericTextbox.cs +++ b/Source/Core/Controls/ButtonsNumericTextbox.cs @@ -239,6 +239,12 @@ namespace CodeImp.DoomBuilder.Controls } } + // biwa + public void ResetIncrementStep() + { + textbox.ResetIncrementStep(); + } + #endregion } } diff --git a/Source/Core/Controls/NumericTextbox.cs b/Source/Core/Controls/NumericTextbox.cs index 64f11035..6174cd95 100755 --- a/Source/Core/Controls/NumericTextbox.cs +++ b/Source/Core/Controls/NumericTextbox.cs @@ -444,6 +444,12 @@ namespace CodeImp.DoomBuilder.Controls tooltip.RemoveAll(); } } + + // biwa + public void ResetIncrementStep() + { + incrementstep = 1; + } #endregion } diff --git a/Source/Core/Windows/SectorEditForm.cs b/Source/Core/Windows/SectorEditForm.cs index c86dc954..234eca04 100755 --- a/Source/Core/Windows/SectorEditForm.cs +++ b/Source/Core/Windows/SectorEditForm.cs @@ -229,18 +229,27 @@ namespace CodeImp.DoomBuilder.Windows } else { - offset = heightoffset.GetResult(0); + // Reset increment steps, otherwise it's just keep counting and counting + heightoffset.ResetIncrementStep(); //restore values - if(string.IsNullOrEmpty(ceilingheight.Text)) + if (string.IsNullOrEmpty(ceilingheight.Text)) { - foreach(Sector s in sectors) + foreach (Sector s in sectors) + { + // To get the steps for ---/+++ into effect the offset has to be retrieved again for each sector + offset = heightoffset.GetResult(0); s.CeilHeight = sectorprops[i++].CeilHeight + offset; + } } else //update values { - foreach(Sector s in sectors) + foreach (Sector s in sectors) + { + // To get the steps for ---/+++ into effect the offset has to be retrieved again for each sector + offset = heightoffset.GetResult(0); s.CeilHeight = ceilingheight.GetResult(sectorprops[i++].CeilHeight) + offset; + } } } } @@ -264,18 +273,27 @@ namespace CodeImp.DoomBuilder.Windows } else { - offset = heightoffset.GetResult(0); - + // Reset increment steps, otherwise it's just keep counting and counting + heightoffset.ResetIncrementStep(); + //restore values - if(string.IsNullOrEmpty(floorheight.Text)) + if (string.IsNullOrEmpty(floorheight.Text)) { - foreach(Sector s in sectors) + foreach (Sector s in sectors) + { + // To get the steps for ---/+++ into effect the offset has to be retrieved again for each sector + offset = heightoffset.GetResult(0); s.FloorHeight = sectorprops[i++].FloorHeight + offset; + } } else //update values { - foreach(Sector s in sectors) + foreach (Sector s in sectors) + { + // To get the steps for ---/+++ into effect the offset has to be retrieved again for each sector + offset = heightoffset.GetResult(0); s.FloorHeight = floorheight.GetResult(sectorprops[i++].FloorHeight) + offset; + } } } } diff --git a/Source/Core/Windows/SectorEditFormUDMF.cs b/Source/Core/Windows/SectorEditFormUDMF.cs index 4bc26165..173354a3 100755 --- a/Source/Core/Windows/SectorEditFormUDMF.cs +++ b/Source/Core/Windows/SectorEditFormUDMF.cs @@ -751,21 +751,29 @@ namespace CodeImp.DoomBuilder.Windows } else { - offset = heightoffset.GetResult(0); - //restore values if(string.IsNullOrEmpty(ceilingheight.Text)) { - foreach(Sector s in sectors) + // Reset increment steps, otherwise it's just keep counting and counting + heightoffset.ResetIncrementStep(); + + foreach (Sector s in sectors) { + // To get the steps for ---/+++ into effect the offset has to be retrieved again for each sector + offset = heightoffset.GetResult(0); s.CeilHeight = sectorprops[s].CeilHeight + offset; SynchCeilSlopeOffsetToHeight(s); } } else //update values { - foreach(Sector s in sectors) + // Reset increment steps, otherwise it's just keep counting and counting + heightoffset.ResetIncrementStep(); + + foreach (Sector s in sectors) { + // To get the steps for ---/+++ into effect the offset has to be retrieved again for each sector + offset = heightoffset.GetResult(0); s.CeilHeight = ceilingheight.GetResult(sectorprops[s].CeilHeight) + offset; SynchCeilSlopeOffsetToHeight(s); } @@ -790,13 +798,16 @@ namespace CodeImp.DoomBuilder.Windows } else { - offset = heightoffset.GetResult(0); + // Reset increment steps, otherwise it's just keep counting and counting + heightoffset.ResetIncrementStep(); //restore values if(string.IsNullOrEmpty(floorheight.Text)) { foreach(Sector s in sectors) { + // To get the steps for ---/+++ into effect the offset has to be retrieved again for each sector + offset = heightoffset.GetResult(0); s.FloorHeight = sectorprops[s].FloorHeight + offset; SynchFloorSlopeOffsetToHeight(s); } @@ -805,6 +816,8 @@ namespace CodeImp.DoomBuilder.Windows { foreach(Sector s in sectors) { + // To get the steps for ---/+++ into effect the offset has to be retrieved again for each sector + offset = heightoffset.GetResult(0); s.FloorHeight = floorheight.GetResult(sectorprops[s].FloorHeight) + offset; SynchFloorSlopeOffsetToHeight(s); } From ee4ac1e4a65469702dc8277425a46cf427f6245c Mon Sep 17 00:00:00 2001 From: biwa Date: Sat, 14 Dec 2019 12:18:17 +0100 Subject: [PATCH 33/34] Stair sector builder: prefabs can now be loaded by double-clicking them --- .../StairSectorBuilderForm.cs | 82 +++++++++++-------- .../StairSectorBuilderForm.designer.cs | 69 +++++++++++++++- .../StairSectorBuilderForm.resx | 4 +- 3 files changed, 115 insertions(+), 40 deletions(-) diff --git a/Source/Plugins/StairSectorBuilder/StairSectorBuilderForm.cs b/Source/Plugins/StairSectorBuilder/StairSectorBuilderForm.cs index 10becaf3..c8244ebf 100755 --- a/Source/Plugins/StairSectorBuilder/StairSectorBuilderForm.cs +++ b/Source/Plugins/StairSectorBuilder/StairSectorBuilderForm.cs @@ -736,62 +736,67 @@ namespace CodeImp.DoomBuilder.StairSectorBuilderMode } } - private void prefabload_Click(object sender, EventArgs e) - { - if(prefabs.SelectedIndices.Count == 0) return; - + private void LoadPrefab(int position) + { loadingprefab = true; - BuilderPlug.Prefab p = BuilderPlug.Me.Prefabs[prefabs.SelectedIndices[0]]; - - prefabname.Text = p.name; + BuilderPlug.Prefab p = BuilderPlug.Me.Prefabs[position]; - NumberOfSectors = (uint)p.numberofsectors; - OuterVertexMultiplier = p.outervertexmultiplier; - InnerVertexMultiplier = p.innervertexmultiplier; + prefabname.Text = p.name; - tabcontrol.SelectedIndex = p.stairtype; + NumberOfSectors = (uint)p.numberofsectors; + OuterVertexMultiplier = p.outervertexmultiplier; + InnerVertexMultiplier = p.innervertexmultiplier; - // Straight stairs - SectorDepth = (uint)p.sectordepth; - Spacing = p.spacing; - SideFront = p.frontside; - SingleSectors.Checked = p.singlesectors; - SingleDirection.Checked = p.singledirection; + tabcontrol.SelectedIndex = p.stairtype; + + // Straight stairs + SectorDepth = (uint)p.sectordepth; + Spacing = p.spacing; + SideFront = p.frontside; + SingleSectors.Checked = p.singlesectors; + SingleDirection.Checked = p.singledirection; DistinctBaseHeights.Checked = p.distinctbaseheights; - // Auto curve TODO + // Auto curve TODO Flipping = p.flipping; - // Catmull Rom spline - NumControlPoints = p.numberofcontrolpoints; + // Catmull Rom spline + NumControlPoints = p.numberofcontrolpoints; - // Height info - FloorHeight = p.applyfloormod; - FloorHeightModification = p.floormod; + // Height info + FloorHeight = p.applyfloormod; + FloorHeightModification = p.floormod; //FloorBase = p.floorbase; - CeilingHeight = p.applyceilingmod; - CeilingHeightModification = p.ceilingmod; + CeilingHeight = p.applyceilingmod; + CeilingHeightModification = p.ceilingmod; //CeilingBase = p.ceilingbase; - // Textures - FloorFlat = p.applyfloortexture; - FloorFlatTexture = p.floortexture; - CeilingFlat = p.applyceilingtexture; - CeilingFlatTexture = p.ceilingtexture; + // Textures + FloorFlat = p.applyfloortexture; + FloorFlatTexture = p.floortexture; + CeilingFlat = p.applyceilingtexture; + CeilingFlatTexture = p.ceilingtexture; - UpperTexture = p.applyuppertexture; - UpperTextureTexture = p.uppertexture; + UpperTexture = p.applyuppertexture; + UpperTextureTexture = p.uppertexture; UpperUnpegged = p.upperunpegged; MiddleTexture = p.applymiddletexture; MiddleTextureTexture = p.middletexture; - LowerTexture = p.applylowertexture; - LowerTextureTexture = p.lowertexture; + LowerTexture = p.applylowertexture; + LowerTextureTexture = p.lowertexture; LowerUnpegged = p.lowerunpegged; loadingprefab = false; + } + + private void prefabload_Click(object sender, EventArgs e) + { + if(prefabs.SelectedIndices.Count == 0) return; + + LoadPrefab(prefabs.SelectedIndices[0]); DoRedrawDisplay(); } @@ -877,5 +882,14 @@ namespace CodeImp.DoomBuilder.StairSectorBuilderMode { ceilingbase.Text = originalceilingbase.ToString(); } + + private void prefabs_DoubleClick(object sender, EventArgs e) + { + if (prefabs.SelectedIndices.Count == 0) return; + + LoadPrefab(prefabs.SelectedIndices[0]); + + DoRedrawDisplay(); + } } } diff --git a/Source/Plugins/StairSectorBuilder/StairSectorBuilderForm.designer.cs b/Source/Plugins/StairSectorBuilder/StairSectorBuilderForm.designer.cs index b7abcbbb..0cdcaf92 100755 --- a/Source/Plugins/StairSectorBuilder/StairSectorBuilderForm.designer.cs +++ b/Source/Plugins/StairSectorBuilder/StairSectorBuilderForm.designer.cs @@ -102,8 +102,8 @@ this.prefabsave = new System.Windows.Forms.Button(); this.prefabname = new System.Windows.Forms.TextBox(); this.prefabs = new System.Windows.Forms.ListView(); - this.columnHeader1 = new System.Windows.Forms.ColumnHeader(); - this.columnHeader2 = new System.Windows.Forms.ColumnHeader(); + this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.groupBox10 = new System.Windows.Forms.GroupBox(); this.middletexturetexture = new CodeImp.DoomBuilder.Controls.TextureSelectorControl(); this.middletexture = new System.Windows.Forms.CheckBox(); @@ -159,10 +159,15 @@ // numberofsectors // this.numberofsectors.AllowDecimal = false; + this.numberofsectors.AllowExpressions = false; this.numberofsectors.AllowNegative = false; this.numberofsectors.AllowRelative = false; this.numberofsectors.ButtonStep = 1; + this.numberofsectors.ButtonStepBig = 10F; this.numberofsectors.ButtonStepFloat = 1F; + this.numberofsectors.ButtonStepSmall = 0.1F; + this.numberofsectors.ButtonStepsUseModifierKeys = false; + this.numberofsectors.ButtonStepsWrapAround = false; this.numberofsectors.Location = new System.Drawing.Point(112, 17); this.numberofsectors.Name = "numberofsectors"; this.numberofsectors.Size = new System.Drawing.Size(56, 24); @@ -222,10 +227,15 @@ // spacing // this.spacing.AllowDecimal = false; + this.spacing.AllowExpressions = false; this.spacing.AllowNegative = false; this.spacing.AllowRelative = false; this.spacing.ButtonStep = 8; + this.spacing.ButtonStepBig = 10F; this.spacing.ButtonStepFloat = 1F; + this.spacing.ButtonStepSmall = 0.1F; + this.spacing.ButtonStepsUseModifierKeys = false; + this.spacing.ButtonStepsWrapAround = false; this.spacing.Location = new System.Drawing.Point(81, 33); this.spacing.Name = "spacing"; this.spacing.Size = new System.Drawing.Size(56, 24); @@ -316,10 +326,15 @@ // sectordepth // this.sectordepth.AllowDecimal = false; + this.sectordepth.AllowExpressions = false; this.sectordepth.AllowNegative = false; this.sectordepth.AllowRelative = false; this.sectordepth.ButtonStep = 8; + this.sectordepth.ButtonStepBig = 10F; this.sectordepth.ButtonStepFloat = 1F; + this.sectordepth.ButtonStepSmall = 0.1F; + this.sectordepth.ButtonStepsUseModifierKeys = false; + this.sectordepth.ButtonStepsWrapAround = false; this.sectordepth.Location = new System.Drawing.Point(81, 3); this.sectordepth.Name = "sectordepth"; this.sectordepth.Size = new System.Drawing.Size(56, 24); @@ -378,10 +393,15 @@ // autocurveoutervertexmultiplier // this.autocurveoutervertexmultiplier.AllowDecimal = false; + this.autocurveoutervertexmultiplier.AllowExpressions = false; this.autocurveoutervertexmultiplier.AllowNegative = false; this.autocurveoutervertexmultiplier.AllowRelative = false; this.autocurveoutervertexmultiplier.ButtonStep = 1; + this.autocurveoutervertexmultiplier.ButtonStepBig = 10F; this.autocurveoutervertexmultiplier.ButtonStepFloat = 1F; + this.autocurveoutervertexmultiplier.ButtonStepSmall = 0.1F; + this.autocurveoutervertexmultiplier.ButtonStepsUseModifierKeys = false; + this.autocurveoutervertexmultiplier.ButtonStepsWrapAround = false; this.autocurveoutervertexmultiplier.Location = new System.Drawing.Point(128, 72); this.autocurveoutervertexmultiplier.Name = "autocurveoutervertexmultiplier"; this.autocurveoutervertexmultiplier.Size = new System.Drawing.Size(56, 24); @@ -392,10 +412,15 @@ // autocurveinnervertexmultiplier // this.autocurveinnervertexmultiplier.AllowDecimal = false; + this.autocurveinnervertexmultiplier.AllowExpressions = false; this.autocurveinnervertexmultiplier.AllowNegative = false; this.autocurveinnervertexmultiplier.AllowRelative = false; this.autocurveinnervertexmultiplier.ButtonStep = 1; + this.autocurveinnervertexmultiplier.ButtonStepBig = 10F; this.autocurveinnervertexmultiplier.ButtonStepFloat = 1F; + this.autocurveinnervertexmultiplier.ButtonStepSmall = 0.1F; + this.autocurveinnervertexmultiplier.ButtonStepsUseModifierKeys = false; + this.autocurveinnervertexmultiplier.ButtonStepsWrapAround = false; this.autocurveinnervertexmultiplier.Location = new System.Drawing.Point(128, 45); this.autocurveinnervertexmultiplier.Name = "autocurveinnervertexmultiplier"; this.autocurveinnervertexmultiplier.Size = new System.Drawing.Size(56, 24); @@ -465,10 +490,15 @@ // splineoutervertexmultiplier // this.splineoutervertexmultiplier.AllowDecimal = false; + this.splineoutervertexmultiplier.AllowExpressions = false; this.splineoutervertexmultiplier.AllowNegative = false; this.splineoutervertexmultiplier.AllowRelative = false; this.splineoutervertexmultiplier.ButtonStep = 1; + this.splineoutervertexmultiplier.ButtonStepBig = 10F; this.splineoutervertexmultiplier.ButtonStepFloat = 1F; + this.splineoutervertexmultiplier.ButtonStepSmall = 0.1F; + this.splineoutervertexmultiplier.ButtonStepsUseModifierKeys = false; + this.splineoutervertexmultiplier.ButtonStepsWrapAround = false; this.splineoutervertexmultiplier.Location = new System.Drawing.Point(128, 72); this.splineoutervertexmultiplier.Name = "splineoutervertexmultiplier"; this.splineoutervertexmultiplier.Size = new System.Drawing.Size(56, 24); @@ -479,10 +509,15 @@ // splineinnervertexmultiplier // this.splineinnervertexmultiplier.AllowDecimal = false; + this.splineinnervertexmultiplier.AllowExpressions = false; this.splineinnervertexmultiplier.AllowNegative = false; this.splineinnervertexmultiplier.AllowRelative = false; this.splineinnervertexmultiplier.ButtonStep = 1; + this.splineinnervertexmultiplier.ButtonStepBig = 10F; this.splineinnervertexmultiplier.ButtonStepFloat = 1F; + this.splineinnervertexmultiplier.ButtonStepSmall = 0.1F; + this.splineinnervertexmultiplier.ButtonStepsUseModifierKeys = false; + this.splineinnervertexmultiplier.ButtonStepsWrapAround = false; this.splineinnervertexmultiplier.Location = new System.Drawing.Point(128, 45); this.splineinnervertexmultiplier.Name = "splineinnervertexmultiplier"; this.splineinnervertexmultiplier.Size = new System.Drawing.Size(56, 24); @@ -511,10 +546,15 @@ // numberofcontrolpoints // this.numberofcontrolpoints.AllowDecimal = false; + this.numberofcontrolpoints.AllowExpressions = false; this.numberofcontrolpoints.AllowNegative = false; this.numberofcontrolpoints.AllowRelative = false; this.numberofcontrolpoints.ButtonStep = 1; + this.numberofcontrolpoints.ButtonStepBig = 10F; this.numberofcontrolpoints.ButtonStepFloat = 1F; + this.numberofcontrolpoints.ButtonStepSmall = 0.1F; + this.numberofcontrolpoints.ButtonStepsUseModifierKeys = false; + this.numberofcontrolpoints.ButtonStepsWrapAround = false; this.numberofcontrolpoints.Location = new System.Drawing.Point(128, 99); this.numberofcontrolpoints.Name = "numberofcontrolpoints"; this.numberofcontrolpoints.Size = new System.Drawing.Size(56, 24); @@ -623,10 +663,15 @@ // floorbase // this.floorbase.AllowDecimal = false; + this.floorbase.AllowExpressions = false; this.floorbase.AllowNegative = true; this.floorbase.AllowRelative = false; this.floorbase.ButtonStep = 8; + this.floorbase.ButtonStepBig = 10F; this.floorbase.ButtonStepFloat = 1F; + this.floorbase.ButtonStepSmall = 0.1F; + this.floorbase.ButtonStepsUseModifierKeys = false; + this.floorbase.ButtonStepsWrapAround = false; this.floorbase.Location = new System.Drawing.Point(45, 48); this.floorbase.Name = "floorbase"; this.floorbase.Size = new System.Drawing.Size(56, 24); @@ -686,10 +731,15 @@ // floorheightmod // this.floorheightmod.AllowDecimal = false; + this.floorheightmod.AllowExpressions = false; this.floorheightmod.AllowNegative = true; this.floorheightmod.AllowRelative = false; this.floorheightmod.ButtonStep = 8; + this.floorheightmod.ButtonStepBig = 10F; this.floorheightmod.ButtonStepFloat = 1F; + this.floorheightmod.ButtonStepSmall = 0.1F; + this.floorheightmod.ButtonStepsUseModifierKeys = false; + this.floorheightmod.ButtonStepsWrapAround = false; this.floorheightmod.Location = new System.Drawing.Point(45, 22); this.floorheightmod.Name = "floorheightmod"; this.floorheightmod.Size = new System.Drawing.Size(56, 24); @@ -837,10 +887,15 @@ // ceilingheightmod // this.ceilingheightmod.AllowDecimal = false; + this.ceilingheightmod.AllowExpressions = false; this.ceilingheightmod.AllowNegative = true; this.ceilingheightmod.AllowRelative = false; this.ceilingheightmod.ButtonStep = 8; + this.ceilingheightmod.ButtonStepBig = 10F; this.ceilingheightmod.ButtonStepFloat = 1F; + this.ceilingheightmod.ButtonStepSmall = 0.1F; + this.ceilingheightmod.ButtonStepsUseModifierKeys = false; + this.ceilingheightmod.ButtonStepsWrapAround = false; this.ceilingheightmod.Location = new System.Drawing.Point(45, 22); this.ceilingheightmod.Name = "ceilingheightmod"; this.ceilingheightmod.Size = new System.Drawing.Size(56, 24); @@ -887,10 +942,15 @@ // ceilingbase // this.ceilingbase.AllowDecimal = false; + this.ceilingbase.AllowExpressions = false; this.ceilingbase.AllowNegative = true; this.ceilingbase.AllowRelative = false; this.ceilingbase.ButtonStep = 8; + this.ceilingbase.ButtonStepBig = 10F; this.ceilingbase.ButtonStepFloat = 1F; + this.ceilingbase.ButtonStepSmall = 0.1F; + this.ceilingbase.ButtonStepsUseModifierKeys = false; + this.ceilingbase.ButtonStepsWrapAround = false; this.ceilingbase.Location = new System.Drawing.Point(45, 48); this.ceilingbase.Name = "ceilingbase"; this.ceilingbase.Size = new System.Drawing.Size(56, 24); @@ -975,6 +1035,7 @@ this.prefabs.TabIndex = 24; this.prefabs.UseCompatibleStateImageBehavior = false; this.prefabs.View = System.Windows.Forms.View.Details; + this.prefabs.DoubleClick += new System.EventHandler(this.prefabs_DoubleClick); // // columnHeader1 // @@ -1042,14 +1103,14 @@ this.MaximizeBox = false; this.MinimizeBox = false; this.Name = "StairSectorBuilderForm"; - this.Opacity = 0; + this.Opacity = 0D; this.ShowIcon = false; this.ShowInTaskbar = false; this.StartPosition = System.Windows.Forms.FormStartPosition.Manual; this.Text = "Stair Sector Builder"; + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.StairSectorBuilderForm_FormClosing); this.Load += new System.EventHandler(this.StairSectorBuilderForm_Load); this.Shown += new System.EventHandler(this.StairSectorBuilderForm_Shown); - this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.StairSectorBuilderForm_FormClosing); this.groupBox1.ResumeLayout(false); this.groupBox1.PerformLayout(); this.tabcontrol.ResumeLayout(false); diff --git a/Source/Plugins/StairSectorBuilder/StairSectorBuilderForm.resx b/Source/Plugins/StairSectorBuilder/StairSectorBuilderForm.resx index ff31a6db..c7e0d4bd 100755 --- a/Source/Plugins/StairSectorBuilder/StairSectorBuilderForm.resx +++ b/Source/Plugins/StairSectorBuilder/StairSectorBuilderForm.resx @@ -112,9 +112,9 @@ 2.0 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 \ No newline at end of file From 3f8da3fc70f3610e6d83238048c178a3a21c5452 Mon Sep 17 00:00:00 2001 From: biwa Date: Sat, 14 Dec 2019 14:32:33 +0100 Subject: [PATCH 34/34] Stair sector builder: renamen "Single sectors" option to "Single steps". Added option to keep distinct sectors when using single steps --- .../Plugins/StairSectorBuilder/BuilderPlug.cs | 3 +- .../StairSectorBuilderForm.cs | 37 +++++++--- .../StairSectorBuilderForm.designer.cs | 51 ++++++++----- .../StairSectorBuilderMode.cs | 73 +++++++++++++++++-- 4 files changed, 128 insertions(+), 36 deletions(-) diff --git a/Source/Plugins/StairSectorBuilder/BuilderPlug.cs b/Source/Plugins/StairSectorBuilder/BuilderPlug.cs index 4b022d6f..eea077e4 100755 --- a/Source/Plugins/StairSectorBuilder/BuilderPlug.cs +++ b/Source/Plugins/StairSectorBuilder/BuilderPlug.cs @@ -50,7 +50,8 @@ namespace CodeImp.DoomBuilder.StairSectorBuilderMode public int sectordepth; public int spacing; public bool frontside; - public bool singlesectors; + public bool singlesteps; + public bool distinctsectors; public bool singledirection; public bool distinctbaseheights; diff --git a/Source/Plugins/StairSectorBuilder/StairSectorBuilderForm.cs b/Source/Plugins/StairSectorBuilder/StairSectorBuilderForm.cs index c8244ebf..d42faabb 100755 --- a/Source/Plugins/StairSectorBuilder/StairSectorBuilderForm.cs +++ b/Source/Plugins/StairSectorBuilder/StairSectorBuilderForm.cs @@ -82,10 +82,16 @@ namespace CodeImp.DoomBuilder.StairSectorBuilderMode set { distinctbaseheights = value; } } - public CheckBox SingleSectors + public CheckBox SingleSteps { - get { return singlesectors; } - set { singlesectors = value; } + get { return singlesteps; } + set { singlesteps = value; } + } + + public CheckBox DistinctSectors + { + get { return distinctsectors; } + set { distinctsectors = value; } } public CheckBox SingleDirection @@ -466,17 +472,23 @@ namespace CodeImp.DoomBuilder.StairSectorBuilderMode singledirection.Checked = false; singledirection.Enabled = false; - singlesectors.Checked = true; - singlesectors.Enabled = false; + singlesteps.Checked = true; + singlesteps.Enabled = false; } } - private void singlesectors_CheckedChanged(object sender, EventArgs e) + private void singleseteps_CheckedChanged(object sender, EventArgs e) { - if(singlesectors.Checked) + if (singlesteps.Checked) + { singledirection.Enabled = true; + distinctsectors.Enabled = true; + } else + { singledirection.Enabled = false; + distinctsectors.Enabled = false; + } DoRedrawDisplay(); } @@ -677,7 +689,8 @@ namespace CodeImp.DoomBuilder.StairSectorBuilderMode pf.sectordepth = (int)SectorDepth; pf.spacing = Spacing; pf.frontside = SideFront; - pf.singlesectors = SingleSectors.Checked; + pf.singlesteps = SingleSteps.Checked; + pf.distinctsectors = distinctsectors.Checked; pf.singledirection = SingleDirection.Checked; pf.distinctbaseheights = DistinctBaseHeights.Checked; @@ -754,7 +767,8 @@ namespace CodeImp.DoomBuilder.StairSectorBuilderMode SectorDepth = (uint)p.sectordepth; Spacing = p.spacing; SideFront = p.frontside; - SingleSectors.Checked = p.singlesectors; + SingleSteps.Checked = p.singlesteps; + distinctsectors.Checked = p.distinctsectors; SingleDirection.Checked = p.singledirection; DistinctBaseHeights.Checked = p.distinctbaseheights; @@ -891,5 +905,10 @@ namespace CodeImp.DoomBuilder.StairSectorBuilderMode DoRedrawDisplay(); } + + private void distinctsectors_CheckedChanged(object sender, EventArgs e) + { + DoRedrawDisplay(); + } } } diff --git a/Source/Plugins/StairSectorBuilder/StairSectorBuilderForm.designer.cs b/Source/Plugins/StairSectorBuilder/StairSectorBuilderForm.designer.cs index 0cdcaf92..f115ee8b 100755 --- a/Source/Plugins/StairSectorBuilder/StairSectorBuilderForm.designer.cs +++ b/Source/Plugins/StairSectorBuilder/StairSectorBuilderForm.designer.cs @@ -40,7 +40,7 @@ this.label11 = new System.Windows.Forms.Label(); this.groupBox3 = new System.Windows.Forms.GroupBox(); this.singledirection = new System.Windows.Forms.CheckBox(); - this.singlesectors = new System.Windows.Forms.CheckBox(); + this.singlesteps = new System.Windows.Forms.CheckBox(); this.groupBox2 = new System.Windows.Forms.GroupBox(); this.sideback = new System.Windows.Forms.RadioButton(); this.sidefront = new System.Windows.Forms.RadioButton(); @@ -107,6 +107,7 @@ this.groupBox10 = new System.Windows.Forms.GroupBox(); this.middletexturetexture = new CodeImp.DoomBuilder.Controls.TextureSelectorControl(); this.middletexture = new System.Windows.Forms.CheckBox(); + this.distinctsectors = new System.Windows.Forms.CheckBox(); this.groupBox1.SuspendLayout(); this.tabcontrol.SuspendLayout(); this.tabPage1.SuspendLayout(); @@ -254,11 +255,12 @@ // // groupBox3 // + this.groupBox3.Controls.Add(this.distinctsectors); this.groupBox3.Controls.Add(this.singledirection); - this.groupBox3.Controls.Add(this.singlesectors); + this.groupBox3.Controls.Add(this.singlesteps); this.groupBox3.Location = new System.Drawing.Point(82, 94); this.groupBox3.Name = "groupBox3"; - this.groupBox3.Size = new System.Drawing.Size(124, 79); + this.groupBox3.Size = new System.Drawing.Size(124, 93); this.groupBox3.TabIndex = 3; this.groupBox3.TabStop = false; this.groupBox3.Text = "Appearance"; @@ -267,7 +269,7 @@ // this.singledirection.AutoSize = true; this.singledirection.Enabled = false; - this.singledirection.Location = new System.Drawing.Point(7, 46); + this.singledirection.Location = new System.Drawing.Point(10, 64); this.singledirection.Name = "singledirection"; this.singledirection.Size = new System.Drawing.Size(99, 18); this.singledirection.TabIndex = 1; @@ -275,17 +277,17 @@ this.singledirection.UseVisualStyleBackColor = true; this.singledirection.CheckedChanged += new System.EventHandler(this.singledirection_CheckedChanged); // - // singlesectors + // singlesteps // - this.singlesectors.AutoSize = true; - this.singlesectors.Enabled = false; - this.singlesectors.Location = new System.Drawing.Point(7, 22); - this.singlesectors.Name = "singlesectors"; - this.singlesectors.Size = new System.Drawing.Size(95, 18); - this.singlesectors.TabIndex = 0; - this.singlesectors.Text = "Single sectors"; - this.singlesectors.UseVisualStyleBackColor = true; - this.singlesectors.CheckedChanged += new System.EventHandler(this.singlesectors_CheckedChanged); + this.singlesteps.AutoSize = true; + this.singlesteps.Enabled = false; + this.singlesteps.Location = new System.Drawing.Point(10, 22); + this.singlesteps.Name = "singlesteps"; + this.singlesteps.Size = new System.Drawing.Size(85, 18); + this.singlesteps.TabIndex = 0; + this.singlesteps.Text = "Single steps"; + this.singlesteps.UseVisualStyleBackColor = true; + this.singlesteps.CheckedChanged += new System.EventHandler(this.singleseteps_CheckedChanged); // // groupBox2 // @@ -293,7 +295,7 @@ this.groupBox2.Controls.Add(this.sidefront); this.groupBox2.Location = new System.Drawing.Point(11, 94); this.groupBox2.Name = "groupBox2"; - this.groupBox2.Size = new System.Drawing.Size(65, 79); + this.groupBox2.Size = new System.Drawing.Size(65, 93); this.groupBox2.TabIndex = 2; this.groupBox2.TabStop = false; this.groupBox2.Text = "Side"; @@ -301,7 +303,7 @@ // sideback // this.sideback.AutoSize = true; - this.sideback.Location = new System.Drawing.Point(7, 46); + this.sideback.Location = new System.Drawing.Point(7, 54); this.sideback.Name = "sideback"; this.sideback.Size = new System.Drawing.Size(49, 18); this.sideback.TabIndex = 1; @@ -314,7 +316,7 @@ // this.sidefront.AutoSize = true; this.sidefront.Checked = true; - this.sidefront.Location = new System.Drawing.Point(7, 22); + this.sidefront.Location = new System.Drawing.Point(7, 30); this.sidefront.Name = "sidefront"; this.sidefront.Size = new System.Drawing.Size(50, 18); this.sidefront.TabIndex = 0; @@ -1079,6 +1081,18 @@ this.middletexture.UseVisualStyleBackColor = true; this.middletexture.CheckedChanged += new System.EventHandler(this.middletexture_CheckedChanged); // + // distinctsectors + // + this.distinctsectors.AutoSize = true; + this.distinctsectors.Enabled = false; + this.distinctsectors.Location = new System.Drawing.Point(10, 43); + this.distinctsectors.Name = "distinctsectors"; + this.distinctsectors.Size = new System.Drawing.Size(101, 18); + this.distinctsectors.TabIndex = 2; + this.distinctsectors.Text = "Distinct sectors"; + this.distinctsectors.UseVisualStyleBackColor = true; + this.distinctsectors.CheckedChanged += new System.EventHandler(this.distinctsectors_CheckedChanged); + // // StairSectorBuilderForm // this.AcceptButton = this.btnOK; @@ -1161,7 +1175,7 @@ private System.Windows.Forms.RadioButton sidefront; private System.Windows.Forms.GroupBox groupBox3; private System.Windows.Forms.CheckBox singledirection; - private System.Windows.Forms.CheckBox singlesectors; + private System.Windows.Forms.CheckBox singlesteps; private System.Windows.Forms.GroupBox groupBox4; private System.Windows.Forms.CheckBox floorflat; private CodeImp.DoomBuilder.Controls.FlatSelectorControl floorflattexture; @@ -1225,5 +1239,6 @@ private System.Windows.Forms.GroupBox groupBox10; private CodeImp.DoomBuilder.Controls.TextureSelectorControl middletexturetexture; private System.Windows.Forms.CheckBox middletexture; + private System.Windows.Forms.CheckBox distinctsectors; } } \ No newline at end of file diff --git a/Source/Plugins/StairSectorBuilder/StairSectorBuilderMode.cs b/Source/Plugins/StairSectorBuilder/StairSectorBuilderMode.cs index b915eed1..d8d0e032 100755 --- a/Source/Plugins/StairSectorBuilder/StairSectorBuilderMode.cs +++ b/Source/Plugins/StairSectorBuilder/StairSectorBuilderMode.cs @@ -107,6 +107,7 @@ namespace CodeImp.DoomBuilder.StairSectorBuilderMode public int floorheight; public int ceilingheight; public List> sectors; + public List> postlines; } @@ -714,7 +715,7 @@ namespace CodeImp.DoomBuilder.StairSectorBuilderMode GetConnectedLines(ref selectedlinedefs, -1); // Build an independend set of steps from each selected line - if(!stairsectorbuilderform.SingleSectors.Checked) + if(!stairsectorbuilderform.SingleSteps.Checked) { // Go through each selected line for(int k = 0; k < sourceld.Count; k++) @@ -761,7 +762,7 @@ namespace CodeImp.DoomBuilder.StairSectorBuilderMode stairinfo.Add(si); } } - else if(stairsectorbuilderform.SingleSectors.Checked) + else if(stairsectorbuilderform.SingleSteps.Checked) { Vector2D direction = new Vector2D(); bool closed = false; @@ -772,6 +773,7 @@ namespace CodeImp.DoomBuilder.StairSectorBuilderMode List connecteddirections = new List(); List connectedlength = new List(); List> sisecs = new List>(); + List> sipostlines = new List>(); Vector2D globaldirection = Vector2D.FromAngle(cld.firstlinedef.Angle + Angle2D.DegToRad(stairsectorbuilderform.SideFront ? -90.0f : 90.0f)); @@ -899,6 +901,20 @@ namespace CodeImp.DoomBuilder.StairSectorBuilderMode } newsec.Add(connectedvertices[k] + direction * length * (i + 1) + (direction * spacing) * i); + + // Add lines to draw after the stair has been created, if desired + if (stairsectorbuilderform.DistinctSectors.Checked) + { + // Skip last and first vertex if vertices are not in a loop, the line would + // just draw over existing lines anyway + if (closed || (!closed && (k != connectedvertices.Count - 1 && k != 0))) + { + sipostlines.Add(new List() { + connectedvertices[k] + direction * length * i + (direction * spacing) * i, + connectedvertices[k] + direction * length * (i + 1) + (direction * spacing) * i + }); + } + } } if(closed == false) @@ -916,6 +932,7 @@ namespace CodeImp.DoomBuilder.StairSectorBuilderMode GetSetTextureAndHeightInfo(cld.firstlinedef, out si); si.sectors = sisecs; + si.postlines = sipostlines; stairinfo.Add(si); } @@ -1190,7 +1207,7 @@ namespace CodeImp.DoomBuilder.StairSectorBuilderMode selectedcontrolpoint.crsd = -1; selectedcontrolpoint.crsg = -1; - stairsectorbuilderform.SingleSectors.Enabled = linesconnected; + stairsectorbuilderform.SingleSteps.Enabled = linesconnected; stairsectorbuilderform.DistinctBaseHeights.Checked = (General.Map.Map.SelectedLinedefsCount != 1); @@ -1326,8 +1343,32 @@ namespace CodeImp.DoomBuilder.StairSectorBuilderMode } } - if(stairsectorbuilderform.MiddleTexture) - General.Map.Options.DefaultWallTexture = olddefaulttexture; + // Draw post lines + foreach (StairInfo si in stairsectors) + { + if (si.postlines != null) + { + foreach (List lv in si.postlines) + { + List oldsectors = new List(General.Map.Map.Sectors); + List vertices = new List(); + + for (int i = 0; i < lv.Count; i++) + vertices.Add(SectorVertex(lv[i])); + + // Draw the new sector + if (!Tools.DrawLines(vertices)) throw new Exception("Failed drawing lines"); + + // Find new sectors + foreach (Sector s in General.Map.Map.Sectors) + if (!oldsectors.Contains(s)) + allnewsectors.Add(s); + } + } + } + + if (stairsectorbuilderform.MiddleTexture) + General.Map.Options.DefaultWallTexture = olddefaulttexture; // Snap to map format accuracy General.Map.Map.SnapAllToAccuracy(); @@ -1447,8 +1488,22 @@ namespace CodeImp.DoomBuilder.StairSectorBuilderMode renderer.RenderRectangle(rect, 2, new PixelColor(128, 255, 0, 0), true); } } + + if (si.postlines != null) + { + foreach (List lv in si.postlines) + { + for (int i = 0; i < lv.Count - 1; i++) + { + renderer.RenderLine(lv[i], lv[i + 1], LINE_THICKNESS, General.Colors.Highlight, true); + + //RectangleF rect = new RectangleF(lv[i].x - CONTROLPOINT_SIZE / 2, lv[i].y - CONTROLPOINT_SIZE / 2, 10.0f, 10.0f); + //renderer.RenderRectangle(rect, 2, new PixelColor(128, 255, 0, 0), true); + } + } + } } - + renderer.Finish(); } @@ -1541,7 +1596,8 @@ namespace CodeImp.DoomBuilder.StairSectorBuilderMode data.Add("sectordepth", p.sectordepth); data.Add("spacing", p.spacing); data.Add("frontside", p.frontside); - data.Add("singlesectors", p.singlesectors); + data.Add("singlesectors", p.singlesteps); + data.Add("distinctsectors", p.distinctsectors); data.Add("singledirection", p.singledirection); data.Add("distinctbaseheights", p.distinctbaseheights); data.Add("flipping", p.flipping); @@ -1594,7 +1650,8 @@ namespace CodeImp.DoomBuilder.StairSectorBuilderMode if((string)entry.Key == "sectordepth") p.sectordepth = (int)entry.Value; if((string)entry.Key == "spacing") p.spacing = (int)entry.Value; if((string)entry.Key == "frontside") p.frontside = (bool)entry.Value; - if((string)entry.Key == "singlesectors") p.singlesectors = (bool)entry.Value; + if((string)entry.Key == "singlesectors") p.singlesteps = (bool)entry.Value; + if((string)entry.Key == "distinctsectors") p.distinctsectors = (bool)entry.Value; if((string)entry.Key == "singledirection") p.singledirection = (bool)entry.Value; if((string)entry.Key == "distinctbaseheights") p.distinctbaseheights = (bool)entry.Value; if((string)entry.Key == "flipping") p.flipping = (int)entry.Value;