diff --git a/Build/Compilers/ZDoom/zspecial.acs b/Build/Compilers/ZDoom/zspecial.acs index 10f7c0bc..e78162ca 100644 --- a/Build/Compilers/ZDoom/zspecial.acs +++ b/Build/Compilers/ZDoom/zspecial.acs @@ -329,6 +329,8 @@ special -83:PickActor(5,8), -84:IsPointerEqual(2,4), -85:CanRaiseActor(1), + -86:SetActorTeleFog(3), + -87:SwapActorTeleFog(1), // Zandronum's -100:ResetMap(0), diff --git a/Build/Configurations/Includes/Boom_common.cfg b/Build/Configurations/Includes/Boom_common.cfg index 9a6dc413..7a0a593b 100644 --- a/Build/Configurations/Includes/Boom_common.cfg +++ b/Build/Configurations/Includes/Boom_common.cfg @@ -3,10 +3,11 @@ mapformat_doom // The format interface handles the map data format formatinterface = "DoomMapSetIO"; - maplumpnames - { - include("Doom_misc.cfg", "doommaplumpnames"); - } + maplumpnames + { + include("Doom_misc.cfg", "doommaplumpnames"); + include("Boom_misc.cfg", "boommaplumpnames"); + } // When this is set to true, sectors with the same tag will light up when a line is highlighted linetagindicatesectors = true; diff --git a/Build/Configurations/Includes/Boom_misc.cfg b/Build/Configurations/Includes/Boom_misc.cfg index 666f0863..d154bd74 100644 --- a/Build/Configurations/Includes/Boom_misc.cfg +++ b/Build/Configurations/Includes/Boom_misc.cfg @@ -35,25 +35,29 @@ thingflagstranslation // How thing flags should be compared (for the stuck thing error check) thingflagscompare { - skills { + skills + { 1; 2; 4; } - gamemodes { - 16 { - //invert = true; + gamemodes + { + 16 + { ignoredgroup = "skills"; ingnorethisgroupwhenunset = true; } - 32 { + 32 + { invert = true; requiredflag = "16"; } - 64 { + 64 + { invert = true; requiredflag = "16"; requiredgroup = "skills"; @@ -101,85 +105,8 @@ allowempty = The nodebuilder is allowed to leave this lump empty. script = This lump is a text-based script. Specify the filename of the script configuration to use. */ -doommaplumpnames +boommaplumpnames { - ~MAP - { - required = true; - blindcopy = true; - nodebuild = false; - } - - THINGS - { - required = true; - nodebuild = true; - allowempty = true; - } - - LINEDEFS - { - required = true; - nodebuild = true; - allowempty = false; - } - - SIDEDEFS - { - required = true; - nodebuild = true; - allowempty = false; - } - - VERTEXES - { - required = true; - nodebuild = true; - allowempty = false; - } - - SEGS - { - required = false; - nodebuild = true; - allowempty = false; - } - - SSECTORS - { - required = false; - nodebuild = true; - allowempty = false; - } - - NODES - { - required = false; - nodebuild = true; - allowempty = false; - } - - SECTORS - { - required = true; - nodebuild = true; - allowempty = false; - } - - REJECT - { - required = false; - nodebuild = true; - allowempty = false; - } - - BLOCKMAP - { - required = false; - nodebuild = true; - allowempty = false; - } - DEHACKED { required = false; diff --git a/Build/Configurations/Includes/UDMF_misc.cfg b/Build/Configurations/Includes/UDMF_misc.cfg index 9bf0768d..16d746dd 100644 --- a/Build/Configurations/Includes/UDMF_misc.cfg +++ b/Build/Configurations/Includes/UDMF_misc.cfg @@ -9,6 +9,9 @@ thingflags skill3 = "Skill 3"; skill4 = "Skill 4"; skill5 = "Skill 5"; + skill6 = "Skill 6"; + skill7 = "Skill 7"; + skill8 = "Skill 8"; ambush = "Deaf"; single = "Singleplayer"; dm = "Deathmatch"; @@ -30,6 +33,9 @@ defaultthingflags skill3; skill4; skill5; + skill6; + skill7; + skill8; single; coop; dm; @@ -39,27 +45,36 @@ defaultthingflags // How thing flags should be compared (for the stuck thing error check) thingflagscompare { - skills { + skills + { skill1; skill2; skill3; skill4; skill5; + skill6; + skill7; + skill8; } - gamemodes { - single { + gamemodes + { + single + { requiredgroup = "skills"; } - coop { + coop + { requiredgroup = "skills"; } - dm { + dm + { ignoredgroup = "skills"; } } - classes { + classes + { class1; class2; class3; diff --git a/Build/Configurations/Includes/ZDoom_common.cfg b/Build/Configurations/Includes/ZDoom_common.cfg index 37f60536..d1d36311 100644 --- a/Build/Configurations/Includes/ZDoom_common.cfg +++ b/Build/Configurations/Includes/ZDoom_common.cfg @@ -90,6 +90,7 @@ mapformat_doom { include("Doom_misc.cfg", "doommaplumpnames"); include("ZDoom_misc.cfg", "doommaplumpnames"); + include("ZDoom_misc.cfg", "glmaplumpnames"); } // When this is set to true, sectors with the same tag will light up when a line is highlighted @@ -203,6 +204,7 @@ mapformat_hexen { include("Doom_misc.cfg", "hexenmaplumpnames"); include("ZDoom_misc.cfg", "hexenmaplumpnames"); + include("ZDoom_misc.cfg", "glmaplumpnames"); } // When this is set to true, sectors with the same tag will light up when a line is highlighted diff --git a/Build/Configurations/Includes/ZDoom_misc.cfg b/Build/Configurations/Includes/ZDoom_misc.cfg index d213e3b2..8dbf0197 100644 --- a/Build/Configurations/Includes/ZDoom_misc.cfg +++ b/Build/Configurations/Includes/ZDoom_misc.cfg @@ -110,6 +110,9 @@ defaultthingflags_udmf skill3; skill4; skill5; + skill6; + skill7; + skill8; single; coop; dm; @@ -123,10 +126,8 @@ defaultthingflags_udmf // How thing flags should be compared (for the stuck thing error check) thingflagscompare_udmf { - skills { - skill6; - skill7; - skill8; + skills + { skill9; skill10; skill11; @@ -137,7 +138,8 @@ thingflagscompare_udmf skill16; } - classes { + classes + { class4; class5; class6; @@ -403,6 +405,52 @@ scriptbuild = This lump is a text-based script, which should be compiled using c script = This lump is a text-based script. Specify the filename of the script configuration to use. */ +// GL nodebuilders generate this stuff +glmaplumpnames +{ + GL_~MAP + { + required = false; + nodebuild = true; + allowempty = true; + } + + GL_VERT + { + required = false; + nodebuild = true; + allowempty = false; + } + + GL_SEGS + { + required = false; + nodebuild = true; + allowempty = false; + } + + GL_SSECT + { + required = false; + nodebuild = true; + allowempty = false; + } + + GL_NODES + { + required = false; + nodebuild = true; + allowempty = false; + } + + GL_PVS + { + required = false; + nodebuild = true; + allowempty = true; + } +} + doommaplumpnames { REJECT diff --git a/Build/Scripting/ZDoom_ACS.cfg b/Build/Scripting/ZDoom_ACS.cfg index aa3e150b..24566beb 100644 --- a/Build/Scripting/ZDoom_ACS.cfg +++ b/Build/Scripting/ZDoom_ACS.cfg @@ -397,6 +397,7 @@ keywords SetPointer = "bool SetPointer(int assign_slot, int tid[, int pointer_selector[, int flags]])\nSet the value of one of the caller's stored pointers."; SetResultValue = "void SetResultValue(int value)"; SetSkyScrollSpeed = "void SetSkyScrollSpeed(int sky, fixed skyspeed)\nChanges the scrolling speed of a sky.\nThis is useful in conjunction with ChangeSky.\nsky: either 1 or 2.\nskyspeed: the desired scrolling speed."; + SetTeleFog = "void SetTeleFog(int tid, str telefogsrcclass, str telefogdestclass"; SetThingSpecial = "void SetThingSpecial(int tid, int special [, int arg0 [, int arg1 [, int arg2 [, int arg3 [, int arg4]]]]])\nSets the special for any things with the same TID.\nThis is similar to Thing_SetSpecial, except it can only be used from ACS,\nand it can set all of a thing's special arguments.\nIf tid is 0, then the activator is used."; SetUserArray = "void SetUserArray(int tid, str name, int pos, int value)\nSets one of the affected actor's user array-bound variables."; SetUserCVar = "bool SetUserCVar(int playernumber, str cvar, int value)\nSets the console variable of a particular player.\nOnly mod-defined console variables through CVARINFO can be changed by using this function.\nReturns FALSE if cvar is invalid, it is not writable, or the player doesn't exist."; @@ -437,6 +438,7 @@ keywords StrParam = "int StrParam(type:expression)\nStrParam will create a new string formatted based upon the same method for Print or Log.\nThe return value is the string table index of the new string."; StrRight = "str StrRight(str string, int length)\nCreates a new string containing the length last characters of string.\nIf string does not exist, an empty string is returned.\nIf string is shorter than length characters, the entire string is returned."; Suspend = "Suspend"; + SwapTeleFog = "int SwapTeleFog(int tid)"; Switch = "Switch(expression)"; TagWait = "void TagWait(int tag)"; TakeActorInventory = "void TakeActorInventory(int tid, str inventory_item, int amount)\nThis function will take the amount of items from the specified actor.\nTakeActorInventory can remove items that are flagged as undroppable."; diff --git a/Build/Scripting/ZDoom_DECORATE.cfg b/Build/Scripting/ZDoom_DECORATE.cfg index 9f320c3c..15b2d011 100644 --- a/Build/Scripting/ZDoom_DECORATE.cfg +++ b/Build/Scripting/ZDoom_DECORATE.cfg @@ -55,6 +55,8 @@ keywords A_RemoveTracer = "A_RemoveTracer[(int flags)]\nflags: RMVF flags."; A_Remove = "A_Remove(int pointer, int flags)\nflags: RMVF flags."; A_SentinelBob = "A_SentinelBob"; + A_SetTeleFog = "A_SetTeleFog(string telefogsourceclass, string telefogdestclass)"; + A_SwapTeleFog = "A_SwapTeleFog"; A_TurretLook = "A_TurretLook"; A_Teleport = "A_Teleport[(string teleportstate = \"Teleport\"[, string targettype = \"BossSpot\"[, string fogtype = \"TeleportFog\"[, int flags = 0[, float mindist = 0[, float maxdist = 0]]]]])]"; A_VileChase = "A_VileChase"; diff --git a/Help/gzdb/features/classic_modes/import_terrain_settings.jpg b/Help/gzdb/features/classic_modes/import_terrain_settings.jpg new file mode 100644 index 00000000..02f82bc5 Binary files /dev/null and b/Help/gzdb/features/classic_modes/import_terrain_settings.jpg differ diff --git a/Help/gzdb/features/classic_modes/mode_importterrain.html b/Help/gzdb/features/classic_modes/mode_importterrain.html index 656ab3cf..00d23792 100644 --- a/Help/gzdb/features/classic_modes/mode_importterrain.html +++ b/Help/gzdb/features/classic_modes/mode_importterrain.html @@ -23,12 +23,16 @@ Action category: Tools.
Default key: none.

Usage:
- Create a terrain model in your favorite 3d modeling app (Blender, Earth Sculptor or any other, which can save a model to Wavefront .obj format)
- Use File -> Import -> Wavefront .obj as Terrain action to import it as sectors. Each polygon in your model will be transformed into sector.

+ Create a terrain model in your favorite 3d modeling app (Blender, Earth Sculptor or any other, which can save or export a model to Wavefront .obj format)
+ Use File -> Import -> Wavefront .obj as Terrain action to import it as sectors. Each polygon in your model will be transformed into a sector.

+ Settings:
+ Scale: self explanatory. The default is 1.0.
+ Up axis: should be the same as vertical axis in the 3d modeling app used to create a terrain model.
+ Sloped terrain: when enabled, the mode will generate sloped terrain using floor vertex height offsets ("ZFloor") in UDMF or Vertex slope floor (1504) things. Regardless of this setting, the mode will also set each new sector's floor height to the averaged height of a polygon it was created from.
+
Limitations:
The model should be triangulated.
Polygons should not overlap each other when viewed from the top.
- UDMF only, because the mode uses vertex height offsets to create sloped floors ("zfloor" vertex field).

diff --git a/Help/gzdb/features/visual_mode/texturefit.html b/Help/gzdb/features/visual_mode/texturefit.html index aaccae6b..3faaa5d5 100644 --- a/Help/gzdb/features/visual_mode/texturefit.html +++ b/Help/gzdb/features/visual_mode/texturefit.html @@ -10,20 +10,23 @@
-

"Fit Texture" actions

+

"Fit Textures" action

-

Action names: Fit Texture, Fit Texture's Width, Fit Texture's Height
+

Action name: Fit Textures.
Action category: Visual Modes.
- Default keys: Ctrl-Alt-A, Alt-A, Alt-Shift-A.

-

Example:
- Initial scaling:
-

-

After "Fit Texture's Width" action:
+ Default key: Ctrl-Alt-A.

+

This action allows you to align textures to selected surfaces in Visual mode. "Fit across connected surfaces" setting controls whether adjacent surfaces sharing the same texture are threated as a continuous surface.

+

Examples:

+ Initial setup:
+


+

Examples of various settings in action:

-

After "Fit Texture's Height" action:
-

-

After "Fit Texture" action:
-

+
+ +
+ +
+
diff --git a/Help/gzdb/features/visual_mode/texturefit1.jpg b/Help/gzdb/features/visual_mode/texturefit1.jpg index cd834a98..b0027377 100644 Binary files a/Help/gzdb/features/visual_mode/texturefit1.jpg and b/Help/gzdb/features/visual_mode/texturefit1.jpg differ diff --git a/Help/gzdb/features/visual_mode/texturefit2.jpg b/Help/gzdb/features/visual_mode/texturefit2.jpg index 6c00d40a..218ccda1 100644 Binary files a/Help/gzdb/features/visual_mode/texturefit2.jpg and b/Help/gzdb/features/visual_mode/texturefit2.jpg differ diff --git a/Help/gzdb/features/visual_mode/texturefit3.jpg b/Help/gzdb/features/visual_mode/texturefit3.jpg index 52205f4d..8ed52eae 100644 Binary files a/Help/gzdb/features/visual_mode/texturefit3.jpg and b/Help/gzdb/features/visual_mode/texturefit3.jpg differ diff --git a/Help/gzdb/features/visual_mode/texturefit4.jpg b/Help/gzdb/features/visual_mode/texturefit4.jpg index 81a6c6a8..68e0daab 100644 Binary files a/Help/gzdb/features/visual_mode/texturefit4.jpg and b/Help/gzdb/features/visual_mode/texturefit4.jpg differ diff --git a/Help/gzdb/features/visual_mode/texturefit5.jpg b/Help/gzdb/features/visual_mode/texturefit5.jpg new file mode 100644 index 00000000..c8fe7540 Binary files /dev/null and b/Help/gzdb/features/visual_mode/texturefit5.jpg differ diff --git a/Source/Core/Compilers/NodesCompiler.cs b/Source/Core/Compilers/NodesCompiler.cs index eb5edf22..56f23719 100644 --- a/Source/Core/Compilers/NodesCompiler.cs +++ b/Source/Core/Compilers/NodesCompiler.cs @@ -113,8 +113,8 @@ namespace CodeImp.DoomBuilder.Compilers } //mxd - string outErr = process.StandardError.ReadToEnd(); - string outMsg = process.StandardOutput.ReadToEnd(); + string outErr = process.StandardError.ReadToEnd().Trim().Replace("\b", ""); + string outMsg = process.StandardOutput.ReadToEnd().Trim().Replace("\b", ""); // Wait for compiler to complete process.WaitForExit(); diff --git a/Source/Core/Controls/ResourceListEditor.cs b/Source/Core/Controls/ResourceListEditor.cs index 59a3d409..d34cdb56 100644 --- a/Source/Core/Controls/ResourceListEditor.cs +++ b/Source/Core/Controls/ResourceListEditor.cs @@ -145,7 +145,7 @@ namespace CodeImp.DoomBuilder.Controls resourceitems.Items[0].ForeColor = SystemColors.GrayText; // Validate path (mxd) - resourceitems.Items[0].BackColor = (LocationValid(list[i]) ? resourceitems.BackColor : Color.MistyRose); + resourceitems.Items[0].BackColor = (list[i].IsValid() ? resourceitems.BackColor : Color.MistyRose); } // Done @@ -211,7 +211,7 @@ namespace CodeImp.DoomBuilder.Controls resourceitems.Items[index].ForeColor = SystemColors.WindowText; // Validate path (mxd) - resourceitems.Items[index].BackColor = (LocationValid(rl) ? resourceitems.BackColor : Color.MistyRose); + resourceitems.Items[index].BackColor = (rl.IsValid() ? resourceitems.BackColor : Color.MistyRose); // Done resourceitems.EndUpdate(); @@ -249,23 +249,6 @@ namespace CodeImp.DoomBuilder.Controls } } } - - //mxd - internal static bool LocationValid(DataLocation location) - { - switch(location.type) - { - case DataLocation.RESOURCE_DIRECTORY: - return Directory.Exists(location.location); - - case DataLocation.RESOURCE_WAD: - case DataLocation.RESOURCE_PK3: - return File.Exists(location.location); - - default: - throw new NotImplementedException("ResourceListEditor.FixedResourceLocationList: got unknown location type: " + location.type); - } - } // This fixes the column header in the list private void ResizeColumnHeader() @@ -413,7 +396,7 @@ namespace CodeImp.DoomBuilder.Controls { foreach(ListViewItem item in resourceitems.Items) { - if (!LocationValid((DataLocation) item.Tag)) return false; + if (!((DataLocation)item.Tag).IsValid()) return false; } return true; } diff --git a/Source/Core/Data/DataLocation.cs b/Source/Core/Data/DataLocation.cs index 500796e8..cd37b598 100644 --- a/Source/Core/Data/DataLocation.cs +++ b/Source/Core/Data/DataLocation.cs @@ -17,6 +17,7 @@ #region ================== Namespaces using System; +using System.IO; #endregion @@ -71,5 +72,26 @@ namespace CodeImp.DoomBuilder.Data { return (this.CompareTo(other) == 0); } + + //mxd + public bool IsValid() + { + switch(type) + { + case RESOURCE_DIRECTORY: + if(!Directory.Exists(location)) return false; + break; + + case RESOURCE_WAD: + case RESOURCE_PK3: + if(!File.Exists(location)) return false; + break; + + default: + throw new NotImplementedException("ResourceListEditor.FixedResourceLocationList: got unknown location type: " + type); + } + + return true; + } } } diff --git a/Source/Core/Data/DataLocationList.cs b/Source/Core/Data/DataLocationList.cs index c8ea6a6a..19057d25 100644 --- a/Source/Core/Data/DataLocationList.cs +++ b/Source/Core/Data/DataLocationList.cs @@ -16,9 +16,11 @@ #region ================== Namespaces +using System; using System.Collections; using System.Collections.Generic; using System.Globalization; +using System.IO; using CodeImp.DoomBuilder.IO; using System.Collections.Specialized; @@ -107,6 +109,13 @@ namespace CodeImp.DoomBuilder.Data // Write to config cfg.WriteSetting(path, resinfo); } + + //mxd + public bool IsValid() + { + foreach (DataLocation location in this) if (!location.IsValid()) return false; + return true; + } #endregion } diff --git a/Source/Core/GZBuilder/Data/ModelData.cs b/Source/Core/GZBuilder/Data/ModelData.cs index 5e26d11b..d4d28e5f 100644 --- a/Source/Core/GZBuilder/Data/ModelData.cs +++ b/Source/Core/GZBuilder/Data/ModelData.cs @@ -1,8 +1,8 @@ #region ================== Namespaces using System.Collections.Generic; -using CodeImp.DoomBuilder.Geometry; using CodeImp.DoomBuilder.GZBuilder.MD3; +using CodeImp.DoomBuilder.Rendering; using SlimDX; using SlimDX.Direct3D9; @@ -15,6 +15,9 @@ namespace CodeImp.DoomBuilder.GZBuilder.Data #region ================== Variables private ModelLoadState loadstate; + private Vector3 scale; + private Matrix transform; + private Matrix transformstretched; #endregion @@ -25,14 +28,9 @@ namespace CodeImp.DoomBuilder.GZBuilder.Data internal GZModel Model; - internal Matrix Scale; - internal Vector2D OffsetXY; - internal float OffsetZ; - - internal float AngleOffset; //in radians - internal float PitchOffset; //in radians - internal float RollOffset; //in radians - internal bool OverridePalette; //used for voxel models only + internal Vector3 Scale { get { return scale; } } + internal Matrix Transform { get { return (General.Settings.GZStretchView ? transformstretched : transform); } } + internal bool OverridePalette; //used for voxel models only internal bool InheritActorPitch; internal bool InheritActorRoll; @@ -48,8 +46,8 @@ namespace CodeImp.DoomBuilder.GZBuilder.Data { ModelNames = new List(); TextureNames = new List(); - Scale = Matrix.Identity; - OffsetXY = new Vector2D(); + transform = Matrix.Identity; + transformstretched = Matrix.Identity; } internal void Dispose() @@ -62,6 +60,13 @@ namespace CodeImp.DoomBuilder.GZBuilder.Data } } + internal void SetTransform(Matrix rotation, Matrix offset, Vector3 scale) + { + this.scale = scale; + this.transform = Matrix.Scaling(scale) * rotation * offset; + this.transformstretched = Matrix.Scaling(scale.X, scale.Y, scale.Z * Renderer3D.GZDOOM_INVERTED_VERTICAL_VIEW_STRETCH) * rotation * offset; + } + #endregion } } diff --git a/Source/Core/GZBuilder/GZDoom/ModeldefStructure.cs b/Source/Core/GZBuilder/GZDoom/ModeldefStructure.cs index 53bfbf3a..6eb2a359 100644 --- a/Source/Core/GZBuilder/GZDoom/ModeldefStructure.cs +++ b/Source/Core/GZBuilder/GZDoom/ModeldefStructure.cs @@ -409,14 +409,13 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom //classname is set in ModeldefParser ModelData mde = new ModelData(); - mde.Scale = Matrix.Scaling(scale); - mde.OffsetXY = new Vector2D(offset.Y, -offset.X); // Things are complicated in GZDoom... - mde.OffsetZ = offset.Z; - mde.AngleOffset = Angle2D.DegToRad(angleOffset); - mde.RollOffset = Angle2D.DegToRad(rollOffset); - mde.PitchOffset = Angle2D.DegToRad(pitchOffset); mde.InheritActorPitch = inheritactorpitch; mde.InheritActorRoll = inheritactorroll; + Matrix moffset = Matrix.Translation(offset.Y, -offset.X, offset.Z); // Things are complicated in GZDoom... + Matrix mrotation = Matrix.RotationY(inheritactorroll ? -Angle2D.DegToRad(rollOffset) : 0) + * Matrix.RotationX(inheritactorpitch ? -Angle2D.DegToRad(pitchOffset) : 0) + * Matrix.RotationZ(Angle2D.DegToRad(angleOffset)); + mde.SetTransform(mrotation, moffset, scale); for(int i = 0; i < modelNames.Length; i++) { diff --git a/Source/Core/GZBuilder/md3/ModelReader.cs b/Source/Core/GZBuilder/md3/ModelReader.cs index 98d8a5ee..1da51682 100644 --- a/Source/Core/GZBuilder/md3/ModelReader.cs +++ b/Source/Core/GZBuilder/md3/ModelReader.cs @@ -734,12 +734,12 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 //create bounding box BoundingBoxSizes bbs = new BoundingBoxSizes(); - bbs.MinX = (short)((xsize / 2 - pivot.x) * mde.Scale.M11); //That should be scale x - bbs.MaxX = (short)((xsize / 2 + pivot.x) * mde.Scale.M11); - bbs.MinZ = (short)((zsize / 2 - pivot.z) * mde.Scale.M11); - bbs.MaxZ = (short)((zsize / 2 + pivot.z) * mde.Scale.M11); - bbs.MinY = (short)((ysize / 2 - pivot.y) * mde.Scale.M11); - bbs.MaxY = (short)((ysize / 2 + pivot.y) * mde.Scale.M11); + bbs.MinX = (short)((xsize / 2f - pivot.x) * mde.Scale.X); + bbs.MaxX = (short)((xsize / 2f + pivot.x) * mde.Scale.X); + bbs.MinZ = (short)((zsize / 2f - pivot.z) * mde.Scale.Z); + bbs.MaxZ = (short)((zsize / 2f + pivot.z) * mde.Scale.Z); + bbs.MinY = (short)((ysize / 2f - pivot.y) * mde.Scale.Y); + bbs.MaxY = (short)((ysize / 2f + pivot.y) * mde.Scale.Y); mde.Model.BoundingBox = BoundingBoxTools.CalculateBoundingBox(bbs); diff --git a/Source/Core/General/MapManager.cs b/Source/Core/General/MapManager.cs index ac01fd3f..1f4988bb 100644 --- a/Source/Core/General/MapManager.cs +++ b/Source/Core/General/MapManager.cs @@ -686,6 +686,7 @@ namespace CodeImp.DoomBuilder { // Determine original map name origmapname = (options.PreviousName != "" && purpose != SavePurpose.IntoFile) ? options.PreviousName : options.CurrentName; + string origwadfile = string.Empty; //mxd try { @@ -736,7 +737,7 @@ namespace CodeImp.DoomBuilder { if (File.Exists(newfilepathname)) { // Move the target file aside - string origwadfile = newfilepathname + ".temp"; + origwadfile = newfilepathname + ".temp"; File.Move(newfilepathname, origwadfile); // Open original file @@ -772,6 +773,7 @@ namespace CodeImp.DoomBuilder { catch (IOException) { General.ShowErrorMessage("IO Error while writing target file: " + newfilepathname + ". Please make sure the location is accessible and not in use by another program.", MessageBoxButtons.OK); + if(!string.IsNullOrEmpty(origwadfile) && File.Exists(origwadfile)) File.Delete(origwadfile); //mxd. Clean-up data.Resume(); General.WriteLogLine("Map saving failed"); return false; @@ -779,6 +781,7 @@ namespace CodeImp.DoomBuilder { catch (UnauthorizedAccessException) { General.ShowErrorMessage("Error while accessing target file: " + newfilepathname + ". Please make sure the location is accessible and not in use by another program.", MessageBoxButtons.OK); + if(!string.IsNullOrEmpty(origwadfile) && File.Exists(origwadfile)) File.Delete(origwadfile); //mxd. Clean-up data.Resume(); General.WriteLogLine("Map saving failed"); return false; @@ -923,6 +926,9 @@ namespace CodeImp.DoomBuilder { // Determine source file string sourcefile = (filepathname.Length > 0 ? filepathname : tempwad.Filename); + //mxd. + RemoveUnneededLumps(tempwad, TEMP_MAP_HEADER, true); + // Copy lumps to buildwad General.WriteLogLine("Copying map lumps to temporary build file..."); CopyLumpsByType(tempwad, TEMP_MAP_HEADER, buildwad, BUILD_MAP_HEADER, true, false, false, true); @@ -976,7 +982,7 @@ namespace CodeImp.DoomBuilder { //mxd. collect errors string compilererrors = ""; foreach (CompilerError e in compiler.Errors) - compilererrors += "Error: " + Environment.NewLine + e.description; + compilererrors += Environment.NewLine + e.description; // Nodebuilder did not build the lumps! if (failaswarning) @@ -993,7 +999,7 @@ namespace CodeImp.DoomBuilder { //collect errors string compilererrors = ""; foreach (CompilerError e in compiler.Errors) - compilererrors += "Error: " + Environment.NewLine + e.description; + compilererrors += Environment.NewLine + e.description; // Nodebuilder did not build the lumps! General.ShowErrorMessage("Unable to build the nodes: The nodebuilder failed to build the expected data structures" + (compiler.Errors.Length > 0 ? ":" + Environment.NewLine + compilererrors : "."), MessageBoxButtons.OK); @@ -1023,10 +1029,14 @@ namespace CodeImp.DoomBuilder { foreach (KeyValuePair group in config.MapLumps) { // Check if this lump should exist - if (group.Value.NodeBuild && !group.Value.AllowEmpty) + if(group.Value.NodeBuild && !group.Value.AllowEmpty && group.Value.Required) { + //mxd + string lumpname = group.Key; + if (lumpname.Contains(CONFIG_MAP_HEADER)) lumpname = lumpname.Replace(CONFIG_MAP_HEADER, mapheader); + // Find the lump in the source - if(wad.FindLump(group.Key, srcindex, srcindex + config.MapLumps.Count + 2) == null) + if(wad.FindLump(lumpname, srcindex, srcindex + config.MapLumps.Count + 2) == null) { // Missing a lump! lumpscomplete = false; @@ -1103,7 +1113,7 @@ namespace CodeImp.DoomBuilder { if(group.Value.Required) { // Get the lump name - string lumpname = (group.Key == CONFIG_MAP_HEADER ? mapname : group.Key); + string lumpname = (group.Key.Contains(CONFIG_MAP_HEADER) ? group.Key.Replace(CONFIG_MAP_HEADER, mapname) : group.Key); //mxd // Check if the lump is missing at the target int targetindex = FindSpecificLump(target, lumpname, headerindex, mapname, config.MapLumps); @@ -1127,15 +1137,16 @@ namespace CodeImp.DoomBuilder { } //mxd. This is called on tempwad, which should only have the current map inside it. - private void RemoveUnneededLumps(WAD target, string mapname) + private void RemoveUnneededLumps(WAD target, string mapname, bool glnodesonly) { //Get the list of lumps required by current map format List requiredLumps = new List(); foreach(KeyValuePair group in config.MapLumps) { - if(group.Value.NodeBuild) continue; //this lump well be recreated by a nodebuilder when saving the map - //(or it won't be if the new map format doesn't require this lump, - //so it will just stay there, possibly messing things up) + //this lump well be recreated by a nodebuilder when saving the map + //(or it won't be if the new map format or nodebuilder doesn't require / build this lump, + //so it will just stay there, possibly messing things up) + if(group.Value.NodeBuild && (!glnodesonly || group.Key.ToUpperInvariant().StartsWith("GL_"))) continue; string lumpname = group.Key; if(lumpname == CONFIG_MAP_HEADER) lumpname = mapname; @@ -1158,10 +1169,17 @@ namespace CodeImp.DoomBuilder { foreach (Lump srclump in source.Lumps) { // Check if we should stop skipping lumps here - if (skipping && !mapconfig.MapLumps.ContainsKey(srclump.Name)) + if (skipping) { - // Stop skipping - skipping = false; + //mxd + string srclumpname = srclump.Name; + if (srclumpname.Contains(sourcemapname)) srclumpname = srclumpname.Replace(sourcemapname, CONFIG_MAP_HEADER); + + if (!mapconfig.MapLumps.ContainsKey(srclumpname)) + { + // Stop skipping + skipping = false; + } } // Check if we should start skipping lumps here @@ -1211,8 +1229,8 @@ namespace CodeImp.DoomBuilder { (group.Value.NodeBuild && copynodebuild) || ((group.Value.Script != null || group.Value.ScriptBuild) && copyscript)) { // Get the lump name - string srclumpname = (group.Key == CONFIG_MAP_HEADER ? sourcemapname : group.Key); - string tgtlumpname = (group.Key == CONFIG_MAP_HEADER ? targetmapname : group.Key); + string srclumpname = (group.Key.Contains(CONFIG_MAP_HEADER) ? group.Key.Replace(CONFIG_MAP_HEADER, sourcemapname) : group.Key); //mxd + string tgtlumpname = (group.Key.Contains(CONFIG_MAP_HEADER) ? group.Key.Replace(CONFIG_MAP_HEADER, targetmapname) : group.Key); //mxd // Find the lump in the source int sourceindex = FindSpecificLump(source, srclumpname, srcheaderindex, sourcemapname, config.MapLumps); @@ -1249,7 +1267,7 @@ namespace CodeImp.DoomBuilder { // This finds a lump within the range of known lump names // Returns -1 when the lump cannot be found - internal static int FindSpecificLump(WAD source, string lumpname, int mapheaderindex, string mapheadername, Dictionary maplumps) + private static int FindSpecificLump(WAD source, string lumpname, int mapheaderindex, string mapheadername, Dictionary maplumps) { // Use the configured map lump names to find the specific lump within range, // because when an unknown lump is met, this search must stop. @@ -1261,8 +1279,10 @@ namespace CodeImp.DoomBuilder { if ((mapheaderindex + i) < source.Lumps.Count) { // Check if this is a known lump name - if (maplumps.ContainsKey(source.Lumps[mapheaderindex + i].Name) || - (maplumps.ContainsKey(CONFIG_MAP_HEADER) && (source.Lumps[mapheaderindex + i].Name == mapheadername))) + string srclumpname = source.Lumps[mapheaderindex + i].Name; //mxd + if (srclumpname.Contains(mapheadername)) srclumpname = srclumpname.Replace(mapheadername, CONFIG_MAP_HEADER); + + if (maplumps.ContainsKey(srclumpname)) //mxd { // Is this the lump we are looking for? if (source.Lumps[mapheaderindex + i].Name == lumpname) @@ -1897,7 +1917,7 @@ namespace CodeImp.DoomBuilder { //mxd. Some lumps may've become unneeded during map format conversion. if(oldFormatInterface != config.FormatInterface) - RemoveUnneededLumps(tempwad, TEMP_MAP_HEADER); + RemoveUnneededLumps(tempwad, TEMP_MAP_HEADER, false); // Create required lumps if they don't exist yet CreateRequiredLumps(tempwad, TEMP_MAP_HEADER); diff --git a/Source/Core/Geometry/Tools.cs b/Source/Core/Geometry/Tools.cs index 74709ecf..9bdfe8fd 100644 --- a/Source/Core/Geometry/Tools.cs +++ b/Source/Core/Geometry/Tools.cs @@ -27,6 +27,7 @@ using CodeImp.DoomBuilder.Config; using CodeImp.DoomBuilder.Types; using System.Windows.Forms; using CodeImp.DoomBuilder.GZBuilder.Tools; +using CodeImp.DoomBuilder.VisualModes; #endregion @@ -1799,6 +1800,26 @@ namespace CodeImp.DoomBuilder.Geometry ((sd.LongMiddleTexture == texturelongname) && (sd.MiddleRequired() || sd.LongMiddleTexture != MapSet.EmptyLongName)) ; } + //mxd. This converts offsetY from/to "normalized" offset for given wall part + public static float GetSidedefOffsetY(Sidedef side, VisualGeometryType part, float offset, float scaleY, bool fromNormalized) + { + switch (part) + { + case VisualGeometryType.WALL_UPPER: + return GetSidedefTopOffsetY(side, offset, scaleY, fromNormalized); + + case VisualGeometryType.WALL_MIDDLE: + case VisualGeometryType.WALL_MIDDLE_3D: + return GetSidedefMiddleOffsetY(side, offset, scaleY, fromNormalized); + + case VisualGeometryType.WALL_LOWER: + return GetSidedefBottomOffsetY(side, offset, scaleY, fromNormalized); + + default: + throw new NotSupportedException("Tools.GetSidedefOffsetY: '" + part + "' geometry type is not supported!"); + } + } + //mxd. This converts offsetY from/to "normalized" offset for given upper wall public static float GetSidedefTopOffsetY(Sidedef side, float offset, float scaleY, bool fromNormalized) { @@ -1806,7 +1827,7 @@ namespace CodeImp.DoomBuilder.Geometry return offset; //if we don't have UpperUnpegged flag, normalize offset - float surfaceHeight = (side.Sector.CeilHeight - side.Other.Sector.CeilHeight) * scaleY; + float surfaceHeight = side.GetHighHeight() * scaleY; if(fromNormalized) return (float)Math.Round(offset + surfaceHeight); return (float)Math.Round(offset - surfaceHeight); @@ -1815,13 +1836,38 @@ namespace CodeImp.DoomBuilder.Geometry //mxd. This converts offsetY from/to "normalized" offset for given middle wall public static float GetSidedefMiddleOffsetY(Sidedef side, float offset, float scaleY, bool fromNormalized) { - if(!side.Line.IsFlagSet(General.Map.Config.LowerUnpeggedFlag) || side.Sector == null) - return offset; + if(side.Sector == null) return offset; - // If we have LowerUnpegged flag, normalize offset - // Absolute value is used because ceiling height of vavoom-type 3d floors - // is lower than floor height - float surfaceHeight = (Math.Abs(side.Sector.CeilHeight - side.Sector.FloorHeight)) * scaleY; + // Normalize offset + float surfaceHeight; + if(side.Other != null && side.Other.Sector != null) + { + if(side.Line.IsFlagSet(General.Map.Config.LowerUnpeggedFlag)) + { + // Double-sided with LowerUnpeggedFlag set + surfaceHeight = (side.Sector.CeilHeight - Math.Max(side.Sector.FloorHeight, side.Other.Sector.FloorHeight)) * scaleY; + } + else + { + // Double-sided without LowerUnpeggedFlag + surfaceHeight = Math.Abs(side.Sector.CeilHeight - side.Other.Sector.CeilHeight) * scaleY; + } + } + else + { + if(side.Line.IsFlagSet(General.Map.Config.LowerUnpeggedFlag)) + { + // Single-sided with LowerUnpeggedFlag set + // Absolute value is used because ceiling height of vavoom-type 3d floors + // is lower than floor height + surfaceHeight = (Math.Abs(side.Sector.CeilHeight - side.Sector.FloorHeight)) * scaleY; + } + else + { + // Single-sided without LowerUnpeggedFlag + return offset; + } + } if(fromNormalized) return (float)Math.Round(offset + surfaceHeight); return (float)Math.Round(offset - surfaceHeight); diff --git a/Source/Core/IO/Configuration.cs b/Source/Core/IO/Configuration.cs index 3e9c7bc6..1e7a1c59 100644 --- a/Source/Core/IO/Configuration.cs +++ b/Source/Core/IO/Configuration.cs @@ -839,6 +839,7 @@ namespace CodeImp.DoomBuilder.IO if(args.Count < 1) RaiseError(file, line, ERROR_INVALID_ARGS); if(!(args[0] is string)) RaiseError(file, line, ERROR_INVALID_ARGS + " Expected a string for argument 1."); if((args.Count > 1) && !(args[1] is string)) RaiseError(file, line, ERROR_INVALID_ARGS + " Expected a string for argument 2."); + if(args[0].ToString().ToUpperInvariant() == Path.GetFileName(file).ToUpperInvariant()) RaiseError(file, line, " A file cannot call include() on itself."); //mxd if(cpErrorResult) return; // Determine the full path of the file to include diff --git a/Source/Core/Map/Thing.cs b/Source/Core/Map/Thing.cs index ed386c01..33bd52a3 100644 --- a/Source/Core/Map/Thing.cs +++ b/Source/Core/Map/Thing.cs @@ -78,7 +78,7 @@ namespace CodeImp.DoomBuilder.Map #region ================== Properties public MapSet Map { get { return map; } } - public int Type { get { return type; } set { BeforePropsChange(); type = value; /*UpdateCache();*/ } } //mxd + public int Type { get { return type; } set { BeforePropsChange(); type = value; } } //mxd public Vector3D Position { get { return pos; } } public float ScaleX { get { return scaleX; } } //mxd. This is UDMF property, not actual scale! public float ScaleY { get { return scaleY; } } //mxd. This is UDMF property, not actual scale! @@ -431,7 +431,7 @@ namespace CodeImp.DoomBuilder.Map BeforePropsChange(); pitch = p; - pitchrad = ((isModel && General.Map.Data.ModeldefEntries[type].InheritActorRoll) ? Angle2D.DegToRad(pitch) : 0); + pitchrad = ((isModel && General.Map.Data.ModeldefEntries[type].InheritActorPitch) ? Angle2D.DegToRad(pitch) : 0); if (type != General.Map.Config.Start3DModeThingType) General.Map.IsChanged = true; @@ -444,7 +444,6 @@ namespace CodeImp.DoomBuilder.Map roll = r; rollrad = ((isModel && General.Map.Data.ModeldefEntries[type].InheritActorRoll) ? Angle2D.DegToRad(roll) : 0); - //rotation = Matrix.RotationYawPitchRoll(rollrad, pitchrad, anglerad); //mxd if (type != General.Map.Config.Start3DModeThingType) General.Map.IsChanged = true; diff --git a/Source/Core/Rendering/Renderer2D.cs b/Source/Core/Rendering/Renderer2D.cs index 7c7dc3a9..aff31cab 100644 --- a/Source/Core/Rendering/Renderer2D.cs +++ b/Source/Core/Rendering/Renderer2D.cs @@ -1339,7 +1339,7 @@ namespace CodeImp.DoomBuilder.Rendering foreach(Thing t in group.Value) { if(General.Settings.GZDrawModelsMode == ModelRenderMode.SELECTION && !t.Selected) continue; - Vector2D screenpos = ((Vector2D)t.Position + General.Map.Data.ModeldefEntries[t.Type].OffsetXY.GetScaled(t.ScaleX).GetRotated(t.Angle)).GetTransformed(translatex, translatey, scale, -scale); + Vector2D screenpos = ((Vector2D)t.Position).GetTransformed(translatex, translatey, scale, -scale); float modelScale = scale * t.ActorScale.Width * t.ScaleX; //should we render this model? @@ -1355,12 +1355,9 @@ namespace CodeImp.DoomBuilder.Rendering float sy = t.ScaleY * t.ActorScale.Height; Matrix modelscale = Matrix.Scaling(sx, sx, sy); - Matrix mdescale = General.Map.Data.ModeldefEntries[t.Type].Scale; - Matrix rotation = Matrix.RotationY(-(t.RollRad + General.Map.Data.ModeldefEntries[t.Type].RollOffset)) - * Matrix.RotationX(-(t.PitchRad + General.Map.Data.ModeldefEntries[t.Type].PitchOffset)) - * Matrix.RotationZ(t.Angle + General.Map.Data.ModeldefEntries[t.Type].AngleOffset); + Matrix rotation = Matrix.RotationY(-t.RollRad) * Matrix.RotationX(-t.PitchRad) * Matrix.RotationZ(t.Angle); Matrix position = Matrix.Translation(screenpos.x, screenpos.y, 0.0f); - Matrix world = mdescale * rotation * modelscale * viewscale * position; + Matrix world = General.Map.Data.ModeldefEntries[t.Type].Transform * rotation * modelscale * viewscale * position; graphics.Shaders.Things2D.SetTransformSettings(world); graphics.Shaders.Things2D.ApplySettings(); diff --git a/Source/Core/Rendering/Renderer3D.cs b/Source/Core/Rendering/Renderer3D.cs index d02ce23c..06f96eb7 100644 --- a/Source/Core/Rendering/Renderer3D.cs +++ b/Source/Core/Rendering/Renderer3D.cs @@ -42,7 +42,8 @@ namespace CodeImp.DoomBuilder.Rendering private const float PROJ_NEAR_PLANE = 1f; private const float CROSSHAIR_SCALE = 0.06f; private const float FOG_RANGE = 0.9f; - private const float INVERTED_VERTICAL_STRETCH = 1.0f / 1.2f; + internal const float GZDOOM_VERTICAL_VIEW_STRETCH = 1.2f; + internal const float GZDOOM_INVERTED_VERTICAL_VIEW_STRETCH = 1.0f / GZDOOM_VERTICAL_VIEW_STRETCH; #endregion @@ -55,7 +56,6 @@ namespace CodeImp.DoomBuilder.Rendering private Matrix worldviewproj; private Matrix view2d; private Matrix world; - private float viewstretch; //mxd private Vector3D cameraposition; private int shaderpass; @@ -257,7 +257,7 @@ namespace CodeImp.DoomBuilder.Rendering internal void CreateProjection() { // Calculate aspect - float screenheight = General.Map.Graphics.RenderTarget.ClientSize.Height * (General.Settings.GZStretchView ? INVERTED_VERTICAL_STRETCH : 1.0f); //mxd + float screenheight = General.Map.Graphics.RenderTarget.ClientSize.Height * (General.Settings.GZStretchView ? GZDOOM_INVERTED_VERTICAL_VIEW_STRETCH : 1.0f); //mxd float aspect = General.Map.Graphics.RenderTarget.ClientSize.Width / screenheight; // The DirectX PerspectiveFovRH matrix method calculates the scaling in X and Y as follows: @@ -273,9 +273,6 @@ namespace CodeImp.DoomBuilder.Rendering // Make the projection matrix projection = Matrix.PerspectiveFovRH(fovy, aspect, PROJ_NEAR_PLANE, General.Settings.ViewDistance); - // Update the view stretch scaler (mxd) - viewstretch = (General.Settings.GZStretchView ? INVERTED_VERTICAL_STRETCH : 1.0f); - // Apply matrices ApplyMatrices3D(); } @@ -1121,19 +1118,12 @@ namespace CodeImp.DoomBuilder.Rendering // Create the matrix for positioning / rotation float sx = t.Thing.ScaleX * t.Thing.ActorScale.Width; - float sy = t.Thing.ScaleY * t.Thing.ActorScale.Height * viewstretch; + float sy = t.Thing.ScaleY * t.Thing.ActorScale.Height; Matrix modelscale = Matrix.Scaling(sx, sx, sy); - Matrix mdescale = General.Map.Data.ModeldefEntries[t.Thing.Type].Scale; + Matrix modelrotation = Matrix.RotationY(-t.Thing.RollRad) * Matrix.RotationX(-t.Thing.PitchRad) * Matrix.RotationZ(t.Thing.Angle); - Matrix rotation = Matrix.RotationY(-(t.Thing.RollRad + General.Map.Data.ModeldefEntries[t.Thing.Type].RollOffset)) - * Matrix.RotationX(-(t.Thing.PitchRad + General.Map.Data.ModeldefEntries[t.Thing.Type].PitchOffset)) - * Matrix.RotationZ(t.Thing.Angle + General.Map.Data.ModeldefEntries[t.Thing.Type].AngleOffset); - - Vector2D offset2d = General.Map.Data.ModeldefEntries[t.Thing.Type].OffsetXY.GetScaled(t.Thing.ScaleX).GetRotated(t.Thing.Angle); - Matrix position = Matrix.Translation(offset2d.x, offset2d.y, General.Map.Data.ModeldefEntries[t.Thing.Type].OffsetZ * t.Thing.ScaleY) * t.Position; - - world = mdescale * rotation * modelscale * position; + world = General.Map.Data.ModeldefEntries[t.Thing.Type].Transform * modelrotation * modelscale * t.Position; ApplyMatrices3D(); //mxd. set variables for fog rendering diff --git a/Source/Core/VisualModes/VisualGeometry.cs b/Source/Core/VisualModes/VisualGeometry.cs index afed6833..d77ccd9a 100644 --- a/Source/Core/VisualModes/VisualGeometry.cs +++ b/Source/Core/VisualModes/VisualGeometry.cs @@ -69,7 +69,8 @@ namespace CodeImp.DoomBuilder.VisualModes //mxd private Vector3[] boundingBox; - protected VisualGeometryType geoType; + protected VisualGeometryType geometrytype; + protected string partname; //UDMF part name #endregion @@ -83,7 +84,7 @@ namespace CodeImp.DoomBuilder.VisualModes //mxd public Vector3[] BoundingBox { get { return boundingBox; } } - public VisualGeometryType GeometryType { get { return geoType; } } + public VisualGeometryType GeometryType { get { return geometrytype; } } /// /// Render pass in which this geometry must be rendered. Default is Solid. @@ -126,8 +127,7 @@ namespace CodeImp.DoomBuilder.VisualModes { this.sector = vs; this.ModulateColor = new PixelColor(255, 255, 255, 255); - //mxd - geoType = VisualGeometryType.UNKNOWN; + this.geometrytype = VisualGeometryType.UNKNOWN; //mxd } /// @@ -139,8 +139,7 @@ namespace CodeImp.DoomBuilder.VisualModes this.sector = vs; this.sidedef = sd; this.ModulateColor = new PixelColor(255, 255, 255, 255); - //mxd - geoType = VisualGeometryType.UNKNOWN; + this.geometrytype = VisualGeometryType.UNKNOWN; //mxd } #endregion diff --git a/Source/Core/Windows/ConfigForm.cs b/Source/Core/Windows/ConfigForm.cs index aee47943..5c86e676 100644 --- a/Source/Core/Windows/ConfigForm.cs +++ b/Source/Core/Windows/ConfigForm.cs @@ -360,16 +360,13 @@ namespace CodeImp.DoomBuilder.Windows { // Get configuration item ci = listconfigs.Items[i].Tag as ConfigurationInfo; - foreach (DataLocation location in ci.Resources) + if(!ci.Resources.IsValid()) { - if (!ResourceListEditor.LocationValid(location)) - { - MessageBox.Show(this, "At least one resource doesn't exist in '" + ci.Name + "' game configuration!", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Warning); - tabs.SelectedTab = tabresources; - listconfigs.Focus(); - listconfigs.Items[i].Selected = true; - return; - } + MessageBox.Show(this, "At least one resource doesn't exist in '" + ci.Name + "' game configuration!", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Warning); + tabs.SelectedTab = tabresources; + listconfigs.Focus(); + listconfigs.Items[i].Selected = true; + return; } } diff --git a/Source/Core/Windows/MainForm.cs b/Source/Core/Windows/MainForm.cs index f8f22b95..93ca57f0 100644 --- a/Source/Core/Windows/MainForm.cs +++ b/Source/Core/Windows/MainForm.cs @@ -508,10 +508,14 @@ namespace CodeImp.DoomBuilder.Windows { // Position window from configuration settings this.SuspendLayout(); - this.Location = new Point(General.Settings.ReadSetting("mainwindow.positionx", this.Location.X), - General.Settings.ReadSetting("mainwindow.positiony", this.Location.Y)); this.Size = new Size(General.Settings.ReadSetting("mainwindow.sizewidth", this.Size.Width), General.Settings.ReadSetting("mainwindow.sizeheight", this.Size.Height)); + this.Location = new Point(General.Clamp(General.Settings.ReadSetting("mainwindow.positionx", this.Location.X), + SystemInformation.VirtualScreen.Left - this.Size.Width + 128, + SystemInformation.VirtualScreen.Right - 128), + General.Clamp(General.Settings.ReadSetting("mainwindow.positiony", this.Location.Y), + SystemInformation.VirtualScreen.Top, + SystemInformation.VirtualScreen.Bottom - 128)); this.WindowState = (FormWindowState)General.Settings.ReadSetting("mainwindow.windowstate", (int)FormWindowState.Maximized); this.ResumeLayout(true); diff --git a/Source/Core/ZDoom/VoxeldefParser.cs b/Source/Core/ZDoom/VoxeldefParser.cs index 81efb305..ceafe34e 100644 --- a/Source/Core/ZDoom/VoxeldefParser.cs +++ b/Source/Core/ZDoom/VoxeldefParser.cs @@ -64,8 +64,10 @@ namespace CodeImp.DoomBuilder.ZDoom } else if(token == "{") //read the settings { - ModelData data = new ModelData(); - data.IsVoxel = true; + ModelData mde = new ModelData(); + mde.IsVoxel = true; + float scale = 1.0f; + float angleoffset = 0; while(SkipWhitespace(true)) { @@ -79,17 +81,18 @@ namespace CodeImp.DoomBuilder.ZDoom { if(!string.IsNullOrEmpty(modelName) && spriteNames.Count > 0) { - data.ModelNames.Add(modelName); + mde.ModelNames.Add(modelName); + mde.SetTransform(Matrix.RotationZ(Angle2D.DegToRad(angleoffset)), Matrix.Identity, new Vector3(scale)); foreach(string s in spriteNames) { if(entries.ContainsKey(s)) //TODO: is this a proper behaviour? { - entries[s] = data; + entries[s] = mde; } else { - entries.Add(s, data); + entries.Add(s, mde); } } @@ -103,7 +106,7 @@ namespace CodeImp.DoomBuilder.ZDoom } else if(token == "overridepalette") { - data.OverridePalette = true; + mde.OverridePalette = true; } else if(token == "angleoffset") { @@ -116,15 +119,12 @@ namespace CodeImp.DoomBuilder.ZDoom break; } - float angleOffset = 0; //90? token = StripTokenQuotes(ReadToken()); - if(!ReadSignedFloat(token, ref angleOffset)) + if(!ReadSignedFloat(token, ref angleoffset)) { // Not numeric! General.ErrorLogger.Add(ErrorType.Error, "Error in " + sourcefilename + " at line " + GetCurrentLineNumber() + ": expected AngleOffset value, but got '" + token + "'"); } - data.AngleOffset = Angle2D.DegToRad(angleOffset); - } else if(token == "scale") { @@ -137,15 +137,12 @@ namespace CodeImp.DoomBuilder.ZDoom break; } - float scale = 1.0f; token = StripTokenQuotes(ReadToken()); if(!ReadSignedFloat(token, ref scale)) { // Not numeric! General.ErrorLogger.Add(ErrorType.Error, "Error in " + sourcefilename + " at line " + GetCurrentLineNumber() + ": expected Scale value, but got '" + token + "'"); } - - data.Scale = Matrix.Scaling(scale, scale, scale); } prevToken = token.ToUpperInvariant(); } diff --git a/Source/Plugins/BuilderModes/BuilderModes.csproj b/Source/Plugins/BuilderModes/BuilderModes.csproj index de4d31d4..23f400f6 100644 --- a/Source/Plugins/BuilderModes/BuilderModes.csproj +++ b/Source/Plugins/BuilderModes/BuilderModes.csproj @@ -326,6 +326,12 @@ FilterSelectedThingsForm.cs + + Form + + + FitTexturesForm.cs + Form @@ -504,6 +510,9 @@ FilterSelectedThingsForm.cs + + FitTexturesForm.cs + PastePropertiesOptionsForm.cs diff --git a/Source/Plugins/BuilderModes/General/BuilderModesTools.cs b/Source/Plugins/BuilderModes/General/BuilderModesTools.cs index da2d0212..d875b537 100644 --- a/Source/Plugins/BuilderModes/General/BuilderModesTools.cs +++ b/Source/Plugins/BuilderModes/General/BuilderModesTools.cs @@ -1,7 +1,10 @@ #region ================== Namespaces using System; +using System.Collections.Generic; using System.Drawing; +using CodeImp.DoomBuilder.GZBuilder.Tools; +using CodeImp.DoomBuilder.Geometry; using CodeImp.DoomBuilder.Map; using CodeImp.DoomBuilder.VisualModes; @@ -9,68 +12,157 @@ using CodeImp.DoomBuilder.VisualModes; namespace CodeImp.DoomBuilder.BuilderModes { - public static class BuilderModesTools + // A struct, which contains information about visual sides connected to start and end of given visual side + internal class SortedVisualSide + { + internal readonly BaseVisualGeometrySidedef Side; + internal readonly Vector2D Start; + internal readonly Vector2D End; + internal Rectangle Bounds; + internal readonly Dictionary NextSides; + internal readonly Dictionary PreviousSides; + internal readonly int Index; + private static int index; + + //Initial texture coordinates + private readonly float OffsetX; + private readonly float OffsetY; + private readonly float ScaleX; + private readonly float ScaleY; + + internal SortedVisualSide(BaseVisualGeometrySidedef side) + { + Side = side; + Bounds = BuilderModesTools.GetSidedefPartSize(side); + Index = index++; + + if (side.Sidedef.Line.Front == side.Sidedef) + { + Start = side.Sidedef.Line.Start.Position; + End = side.Sidedef.Line.End.Position; + } + else + { + Start = side.Sidedef.Line.End.Position; + End = side.Sidedef.Line.Start.Position; + } + + switch (side.GeometryType) + { + case VisualGeometryType.WALL_UPPER: + OffsetX = UDMFTools.GetFloat(side.Sidedef.Fields, "offsetx_top"); + OffsetY = UDMFTools.GetFloat(side.Sidedef.Fields, "offsety_top"); + ScaleX = UDMFTools.GetFloat(side.Sidedef.Fields, "scalex_top", 1.0f); + ScaleY = UDMFTools.GetFloat(side.Sidedef.Fields, "scaley_top", 1.0f); + break; + + case VisualGeometryType.WALL_MIDDLE: + OffsetX = UDMFTools.GetFloat(side.Sidedef.Fields, "offsetx_mid"); + OffsetY = UDMFTools.GetFloat(side.Sidedef.Fields, "offsety_mid"); + ScaleX = UDMFTools.GetFloat(side.Sidedef.Fields, "scalex_mid", 1.0f); + ScaleY = UDMFTools.GetFloat(side.Sidedef.Fields, "scaley_mid", 1.0f); + break; + + case VisualGeometryType.WALL_MIDDLE_3D: + Sidedef cs = side.GetControlLinedef().Front; + OffsetX = UDMFTools.GetFloat(cs.Fields, "offsetx_mid"); + OffsetY = UDMFTools.GetFloat(cs.Fields, "offsety_mid"); + ScaleX = UDMFTools.GetFloat(cs.Fields, "scalex_mid", 1.0f); + ScaleY = UDMFTools.GetFloat(cs.Fields, "scaley_mid", 1.0f); + break; + + case VisualGeometryType.WALL_LOWER: + OffsetX = UDMFTools.GetFloat(side.Sidedef.Fields, "offsetx_bottom"); + OffsetY = UDMFTools.GetFloat(side.Sidedef.Fields, "offsety_bottom"); + ScaleX = UDMFTools.GetFloat(side.Sidedef.Fields, "scalex_bottom", 1.0f); + ScaleY = UDMFTools.GetFloat(side.Sidedef.Fields, "scaley_bottom", 1.0f); + break; + } + + NextSides = new Dictionary(); + PreviousSides = new Dictionary(); + } + + internal void OnTextureFit(FitTextureOptions options) + { + options.Bounds = Bounds; + options.InitialOffsetX = OffsetX; + options.InitialOffsetY = OffsetY; + options.InitialScaleX = ScaleX; + options.InitialScaleY = ScaleY; + + Side.OnTextureFit(options); + } + } + + internal static class BuilderModesTools { #region ================== Sidedef - internal static Rectangle GetSidedefPartSize(BaseVisualGeometrySidedef side, VisualGeometryType type) + internal static Rectangle GetSidedefPartSize(BaseVisualGeometrySidedef side) { - if(type == VisualGeometryType.WALL_MIDDLE_3D) + if(side.GeometryType == VisualGeometryType.WALL_MIDDLE_3D) { - Rectangle rect = new Rectangle(0, 0, 1, 0); + Rectangle rect = new Rectangle(0, 0, Math.Max(1, (int)Math.Round(side.Sidedef.Line.Length)), 0); Linedef cl = side.GetControlLinedef(); + if(cl.Front != null && cl.Front.Sector != null) { - // Use ceiling height for vavoom-type 3d floors. Also, FloorHeight is > CeilHeight for these... + // Use floor height for vavoom-type 3d floors, because FloorHeight should be > CeilHeight for this type of 3d floor. if (cl.Args[1] == 0) { - rect.Y = cl.Front.Sector.CeilHeight; + rect.Y = -cl.Front.Sector.FloorHeight; rect.Height = cl.Front.Sector.FloorHeight - cl.Front.Sector.CeilHeight; } else { - rect.Y = cl.Front.Sector.FloorHeight; + rect.Y = -cl.Front.Sector.CeilHeight; rect.Height = cl.Front.GetMiddleHeight(); } - } else { - rect.Y = side.Sidedef.Sector.FloorHeight; + rect.Y = -side.Sidedef.Sector.CeilHeight; rect.Height = side.Sidedef.GetMiddleHeight(); } return rect; } - return GetSidedefPartSize(side.Sidedef, type); + return GetSidedefPartSize(side.Sidedef, side.GeometryType); } public static Rectangle GetSidedefPartSize(Sidedef side, VisualGeometryType type) { - Rectangle rect = new Rectangle(0, 0, 1, 0); + Rectangle rect = new Rectangle(0, 0, Math.Max(1, (int)Math.Round(side.Line.Length)), 0); switch(type) { case VisualGeometryType.WALL_LOWER: - rect.Y = side.Sector.FloorHeight; - rect.Height = side.GetLowHeight(); - break; - - case VisualGeometryType.WALL_UPPER: - if(side.Other != null && side.Other.Sector != null) + if (side.LowRequired()) { - rect.Y = side.Other.Sector.CeilHeight; - rect.Height = side.GetHighHeight(); - } - else - { - rect.Height = 0; + rect.Y = -side.Other.Sector.FloorHeight; + rect.Height = side.GetLowHeight(); } break; + case VisualGeometryType.WALL_UPPER: + if(side.HighRequired()) + { + rect.Y = -side.Sector.CeilHeight; + rect.Height = side.GetHighHeight(); + } + break; + case VisualGeometryType.WALL_MIDDLE: - rect.Y = side.Sector.FloorHeight; + if(side.MiddleRequired()) + { + rect.Y = -side.Sector.CeilHeight; + } + else if (side.Other.Sector != null) // Double-sided + { + rect.Y = -Math.Min(side.Sector.CeilHeight, side.Other.Sector.CeilHeight); + } rect.Height = side.GetMiddleHeight(); break; @@ -81,6 +173,124 @@ namespace CodeImp.DoomBuilder.BuilderModes return rect; } + public static List SortVisualSides(IEnumerable tosort) + { + List result = new List(); + + // Sort by texture + Dictionary> sidesbytexture = new Dictionary>(); + foreach (BaseVisualGeometrySidedef side in tosort) + { + long texturelong; + if (side is VisualLower) texturelong = side.Sidedef.LongLowTexture; + else if (side is VisualUpper) texturelong = side.Sidedef.LongHighTexture; + else texturelong = side.Sidedef.LongMiddleTexture; + + if(texturelong == MapSet.EmptyLongName) continue; //not interested... + + if(!sidesbytexture.ContainsKey(texturelong)) sidesbytexture.Add(texturelong, new List()); + sidesbytexture[texturelong].Add(side); + } + + // Connect sides + foreach (KeyValuePair> pair in sidesbytexture) + { + IEnumerable group = ConnectSides(pair.Value); + result.AddRange(group); + } + + return result; + } + + // Connect sides, left to right + // NextSides - sides connected to the right (Start) vertex, + // PreviousSides - sides connected to the left (End) vertex + private static IEnumerable ConnectSides(List allsides) + { + List result = new List(); + List sides = new List(allsides.Count); + foreach (BaseVisualGeometrySidedef side in allsides) + { + sides.Add(new SortedVisualSide(side)); + } + + foreach(SortedVisualSide curside in sides) + { + // Find sides connected to the end of curside + foreach(SortedVisualSide nextside in sides) + { + if(curside.Index == nextside.Index) continue; + if(nextside.Start == curside.End && nextside.End != curside.Start) + { + // Add both ways + if(!nextside.PreviousSides.ContainsKey(curside)) nextside.PreviousSides.Add(curside, false); + if(!curside.NextSides.ContainsKey(nextside)) curside.NextSides.Add(nextside, false); + } + } + + // Find sides connected to the start of curside + foreach(SortedVisualSide prevside in sides) + { + if(curside.Index == prevside.Index) continue; + if(prevside.End == curside.Start && prevside.Start != curside.End) + { + // Add both ways + if(!prevside.NextSides.ContainsKey(curside)) prevside.NextSides.Add(curside, false); + if(!curside.PreviousSides.ContainsKey(prevside)) curside.PreviousSides.Add(prevside, false); + } + } + + result.Add(curside); + } + + // Try to find the left-most side + SortedVisualSide start = result[0]; + foreach (SortedVisualSide side in result) + { + if (side.PreviousSides.Count == 0) + { + start = side; + break; + } + } + + // Set horizontal offsets... + ApplyHorizontalOffset(start, null, true, new Dictionary()); + + return result; + } + + private static void ApplyHorizontalOffset(SortedVisualSide side, SortedVisualSide prevside, bool forward, Dictionary processed) + { + // Set offset + if (!processed.ContainsKey(side.Index)) + { + if (prevside != null) + { + if (forward) + side.Bounds.X = prevside.Bounds.X + (int)Math.Round(prevside.Side.Sidedef.Line.Length); + else + side.Bounds.X = prevside.Bounds.X - (int)Math.Round(side.Side.Sidedef.Line.Length); + } + + processed.Add(side.Index, false); + } + + // Repeat for NextSides + foreach (KeyValuePair pair in side.NextSides) + { + if (!processed.ContainsKey(pair.Key.Index)) + ApplyHorizontalOffset(pair.Key, side, true, processed); + } + + // Repeat for PreviousSides + foreach(KeyValuePair pair in side.PreviousSides) + { + if(!processed.ContainsKey(pair.Key.Index)) + ApplyHorizontalOffset(pair.Key, side, false, processed); + } + } + #endregion } } diff --git a/Source/Plugins/BuilderModes/Interface/FitTexturesForm.Designer.cs b/Source/Plugins/BuilderModes/Interface/FitTexturesForm.Designer.cs new file mode 100644 index 00000000..434b79fe --- /dev/null +++ b/Source/Plugins/BuilderModes/Interface/FitTexturesForm.Designer.cs @@ -0,0 +1,257 @@ +namespace CodeImp.DoomBuilder.BuilderModes +{ + partial class FitTexturesForm + { + /// + /// 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.labelhorizrepeat = new System.Windows.Forms.Label(); + this.repeatgroup = new System.Windows.Forms.GroupBox(); + this.labelvertrepeat = new System.Windows.Forms.Label(); + this.horizrepeat = new System.Windows.Forms.NumericUpDown(); + this.vertrepeat = new System.Windows.Forms.NumericUpDown(); + this.resethoriz = new System.Windows.Forms.Button(); + this.resetvert = new System.Windows.Forms.Button(); + this.cbfitwidth = new System.Windows.Forms.CheckBox(); + this.accept = new System.Windows.Forms.Button(); + this.cancel = new System.Windows.Forms.Button(); + this.cbfitheight = new System.Windows.Forms.CheckBox(); + this.cbfitconnected = new System.Windows.Forms.CheckBox(); + this.groupBox2 = new System.Windows.Forms.GroupBox(); + this.repeatgroup.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.horizrepeat)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.vertrepeat)).BeginInit(); + this.groupBox2.SuspendLayout(); + this.SuspendLayout(); + // + // labelhorizrepeat + // + this.labelhorizrepeat.AutoSize = true; + this.labelhorizrepeat.Location = new System.Drawing.Point(23, 26); + this.labelhorizrepeat.Name = "labelhorizrepeat"; + this.labelhorizrepeat.Size = new System.Drawing.Size(57, 13); + this.labelhorizrepeat.TabIndex = 0; + this.labelhorizrepeat.Text = "Horizontal:"; + // + // repeatgroup + // + this.repeatgroup.Controls.Add(this.resetvert); + this.repeatgroup.Controls.Add(this.resethoriz); + this.repeatgroup.Controls.Add(this.vertrepeat); + this.repeatgroup.Controls.Add(this.horizrepeat); + this.repeatgroup.Controls.Add(this.labelvertrepeat); + this.repeatgroup.Controls.Add(this.labelhorizrepeat); + this.repeatgroup.Location = new System.Drawing.Point(12, 107); + this.repeatgroup.Name = "repeatgroup"; + this.repeatgroup.Size = new System.Drawing.Size(183, 80); + this.repeatgroup.TabIndex = 1; + this.repeatgroup.TabStop = false; + this.repeatgroup.Text = " Texture Repeating "; + // + // labelvertrepeat + // + this.labelvertrepeat.AutoSize = true; + this.labelvertrepeat.Location = new System.Drawing.Point(33, 52); + this.labelvertrepeat.Name = "labelvertrepeat"; + this.labelvertrepeat.Size = new System.Drawing.Size(45, 13); + this.labelvertrepeat.TabIndex = 1; + this.labelvertrepeat.Text = "Vertical:"; + // + // horizrepeat + // + this.horizrepeat.Location = new System.Drawing.Point(84, 22); + this.horizrepeat.Maximum = new decimal(new int[] { + 512, + 0, + 0, + 0}); + this.horizrepeat.Minimum = new decimal(new int[] { + 1, + 0, + 0, + 0}); + this.horizrepeat.Name = "horizrepeat"; + this.horizrepeat.Size = new System.Drawing.Size(60, 20); + this.horizrepeat.TabIndex = 2; + this.horizrepeat.Value = new decimal(new int[] { + 1, + 0, + 0, + 0}); + this.horizrepeat.ValueChanged += new System.EventHandler(this.repeat_ValueChanged); + // + // vertrepeat + // + this.vertrepeat.Location = new System.Drawing.Point(84, 48); + this.vertrepeat.Maximum = new decimal(new int[] { + 512, + 0, + 0, + 0}); + this.vertrepeat.Minimum = new decimal(new int[] { + 1, + 0, + 0, + 0}); + this.vertrepeat.Name = "vertrepeat"; + this.vertrepeat.Size = new System.Drawing.Size(60, 20); + this.vertrepeat.TabIndex = 3; + this.vertrepeat.Value = new decimal(new int[] { + 1, + 0, + 0, + 0}); + this.vertrepeat.ValueChanged += new System.EventHandler(this.repeat_ValueChanged); + // + // resethoriz + // + this.resethoriz.Image = global::CodeImp.DoomBuilder.BuilderModes.Properties.Resources.Reset; + this.resethoriz.Location = new System.Drawing.Point(150, 20); + this.resethoriz.Name = "resethoriz"; + this.resethoriz.Size = new System.Drawing.Size(24, 24); + this.resethoriz.TabIndex = 4; + this.resethoriz.UseVisualStyleBackColor = true; + this.resethoriz.Click += new System.EventHandler(this.resethoriz_Click); + // + // resetvert + // + this.resetvert.Image = global::CodeImp.DoomBuilder.BuilderModes.Properties.Resources.Reset; + this.resetvert.Location = new System.Drawing.Point(150, 46); + this.resetvert.Name = "resetvert"; + this.resetvert.Size = new System.Drawing.Size(24, 24); + this.resetvert.TabIndex = 5; + this.resetvert.UseVisualStyleBackColor = true; + this.resetvert.Click += new System.EventHandler(this.resetvert_Click); + // + // cbfitwidth + // + this.cbfitwidth.AutoSize = true; + this.cbfitwidth.Location = new System.Drawing.Point(10, 19); + this.cbfitwidth.Name = "cbfitwidth"; + this.cbfitwidth.Size = new System.Drawing.Size(65, 17); + this.cbfitwidth.TabIndex = 2; + this.cbfitwidth.Text = "Fit width"; + this.cbfitwidth.UseVisualStyleBackColor = true; + this.cbfitwidth.CheckedChanged += new System.EventHandler(this.cbfitwidth_CheckedChanged); + // + // accept + // + this.accept.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.accept.Location = new System.Drawing.Point(106, 194); + this.accept.Name = "accept"; + this.accept.Size = new System.Drawing.Size(88, 24); + this.accept.TabIndex = 6; + this.accept.Text = "Apply"; + this.accept.UseVisualStyleBackColor = true; + this.accept.Click += new System.EventHandler(this.accept_Click); + // + // cancel + // + this.cancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.cancel.Location = new System.Drawing.Point(12, 194); + this.cancel.Name = "cancel"; + this.cancel.Size = new System.Drawing.Size(88, 24); + this.cancel.TabIndex = 7; + this.cancel.Text = "Cancel"; + this.cancel.UseVisualStyleBackColor = true; + this.cancel.Click += new System.EventHandler(this.cancel_Click); + // + // cbfitheight + // + this.cbfitheight.AutoSize = true; + this.cbfitheight.Location = new System.Drawing.Point(10, 42); + this.cbfitheight.Name = "cbfitheight"; + this.cbfitheight.Size = new System.Drawing.Size(69, 17); + this.cbfitheight.TabIndex = 8; + this.cbfitheight.Text = "Fit height"; + this.cbfitheight.UseVisualStyleBackColor = true; + this.cbfitheight.CheckedChanged += new System.EventHandler(this.cbfitheight_CheckedChanged); + // + // cbfitconnected + // + this.cbfitconnected.AutoSize = true; + this.cbfitconnected.Location = new System.Drawing.Point(10, 65); + this.cbfitconnected.Name = "cbfitconnected"; + this.cbfitconnected.Size = new System.Drawing.Size(168, 17); + this.cbfitconnected.TabIndex = 9; + this.cbfitconnected.Text = "Fit across connected surfaces"; + this.cbfitconnected.UseVisualStyleBackColor = true; + this.cbfitconnected.CheckedChanged += new System.EventHandler(this.repeat_ValueChanged); + // + // groupBox2 + // + this.groupBox2.Controls.Add(this.cbfitwidth); + this.groupBox2.Controls.Add(this.cbfitconnected); + this.groupBox2.Controls.Add(this.cbfitheight); + this.groupBox2.Location = new System.Drawing.Point(12, 12); + this.groupBox2.Name = "groupBox2"; + this.groupBox2.Size = new System.Drawing.Size(183, 89); + this.groupBox2.TabIndex = 10; + this.groupBox2.TabStop = false; + this.groupBox2.Text = " Options "; + // + // FitTexturesForm + // + this.AcceptButton = this.accept; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(206, 223); + this.Controls.Add(this.groupBox2); + this.Controls.Add(this.cancel); + this.Controls.Add(this.accept); + this.Controls.Add(this.repeatgroup); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "FitTexturesForm"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Fit Textures"; + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FitTexturesForm_FormClosing); + this.repeatgroup.ResumeLayout(false); + this.repeatgroup.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.horizrepeat)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.vertrepeat)).EndInit(); + this.groupBox2.ResumeLayout(false); + this.groupBox2.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Label labelhorizrepeat; + private System.Windows.Forms.GroupBox repeatgroup; + private System.Windows.Forms.Button resethoriz; + private System.Windows.Forms.NumericUpDown vertrepeat; + private System.Windows.Forms.NumericUpDown horizrepeat; + private System.Windows.Forms.Label labelvertrepeat; + private System.Windows.Forms.Button resetvert; + private System.Windows.Forms.CheckBox cbfitwidth; + private System.Windows.Forms.Button accept; + private System.Windows.Forms.Button cancel; + private System.Windows.Forms.CheckBox cbfitheight; + private System.Windows.Forms.CheckBox cbfitconnected; + private System.Windows.Forms.GroupBox groupBox2; + } +} \ No newline at end of file diff --git a/Source/Plugins/BuilderModes/Interface/FitTexturesForm.cs b/Source/Plugins/BuilderModes/Interface/FitTexturesForm.cs new file mode 100644 index 00000000..7b6d897f --- /dev/null +++ b/Source/Plugins/BuilderModes/Interface/FitTexturesForm.cs @@ -0,0 +1,271 @@ +#region ================== Namespaces + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Imaging; +using System.Windows.Forms; +using CodeImp.DoomBuilder.Windows; + +#endregion + +namespace CodeImp.DoomBuilder.BuilderModes +{ + internal struct FitTextureOptions + { + public int HorizontalRepeat; + public int VerticalRepeat; + public bool FitWidth; + public bool FitHeight; + public bool FitAcrossSurfaces; + public Rectangle GlobalBounds; + public Rectangle Bounds; + + //Initial texture coordinats + public float InitialOffsetX; + public float InitialOffsetY; + public float InitialScaleX; + public float InitialScaleY; + } + + internal partial class FitTexturesForm : DelayedForm + { + #region ================== Event handlers + + #endregion + + #region ================== Variables + + private static Point location = Point.Empty; + private bool blockupdate; + + // Settings + private static int horizontalrepeat = 1; + private static int verticalrepeat = 1; + private static bool fitacrosssurfaces = true; + private static bool fitwidth = true; + private static bool fitheight = true; + + //Surface stuff + private List strips; + private Rectangle bounds; + + #endregion + + #region ================== Constructor + + public FitTexturesForm() + { + InitializeComponent(); + + if (!location.IsEmpty) + { + this.StartPosition = FormStartPosition.Manual; + this.Location = location; + } + } + + #endregion + + #region ================== Methods + + public void Setup(IEnumerable sides) + { + // Get shapes + strips = BuilderModesTools.SortVisualSides(sides); + + // No dice... + if(strips.Count == 0) + { + General.Interface.DisplayStatus(StatusType.Warning, "Failed to setup sidedef chains..."); + this.DialogResult = DialogResult.Cancel; + this.Close(); + return; + } + + // Create bounds + int minx = int.MaxValue; + int maxx = int.MinValue; + int miny = int.MaxValue; + int maxy = int.MinValue; + + foreach(SortedVisualSide side in strips) + { + if(side.Bounds.X < minx) minx = side.Bounds.X; + if(side.Bounds.X + side.Bounds.Width > maxx) maxx = side.Bounds.X + side.Bounds.Width; + if(side.Bounds.Y < miny) miny = side.Bounds.Y; + if(side.Bounds.Y + side.Bounds.Height > maxy) maxy = side.Bounds.Y + side.Bounds.Height; + } + + bounds = new Rectangle(minx, miny, maxx-minx, maxy-miny); + + // Normalize Y-offset + foreach (SortedVisualSide side in strips) side.Bounds.Y -= bounds.Y; + bounds.Y = 0; + +#if DEBUG + //debug + DrawDebugUV(); +#endif + + // Restore settings + blockupdate = true; + + horizrepeat.Value = horizontalrepeat; + vertrepeat.Value = verticalrepeat; + cbfitconnected.Checked = fitacrosssurfaces; + cbfitwidth.Checked = fitwidth; + cbfitheight.Checked = fitheight; + UpdateRepeatGroup(); + + blockupdate = false; + + //trigger update + UpdateChanges(); + } + + private void UpdateChanges() + { + // Apply changes + FitTextureOptions options = new FitTextureOptions + { + GlobalBounds = bounds, + FitAcrossSurfaces = cbfitconnected.Checked, + FitWidth = cbfitwidth.Checked, + FitHeight = cbfitheight.Checked, + HorizontalRepeat = (int)horizrepeat.Value, + VerticalRepeat = (int)vertrepeat.Value + }; + + foreach(SortedVisualSide side in strips) side.OnTextureFit(options); + } + + private void UpdateRepeatGroup() + { + // Disable whole group? + repeatgroup.Enabled = cbfitwidth.Checked || cbfitheight.Checked; + if(!repeatgroup.Enabled) return; + + // Update control status + labelhorizrepeat.Enabled = cbfitwidth.Checked; + horizrepeat.Enabled = cbfitwidth.Checked; + resethoriz.Enabled = cbfitwidth.Checked; + + labelvertrepeat.Enabled = cbfitheight.Checked; + vertrepeat.Enabled = cbfitheight.Checked; + resetvert.Enabled = cbfitheight.Checked; + } + + #endregion + + #region ================== Events + + private void FitTexturesForm_FormClosing(object sender, FormClosingEventArgs e) + { + location = this.Location; + + // Store settings + if (this.DialogResult == DialogResult.OK) + { + horizontalrepeat = (int)horizrepeat.Value; + verticalrepeat = (int)vertrepeat.Value; + fitacrosssurfaces = cbfitwidth.Checked; + fitwidth = cbfitwidth.Checked; + fitheight = cbfitheight.Checked; + } + } + + private void resethoriz_Click(object sender, EventArgs e) + { + horizrepeat.Value = 1; + } + + private void resetvert_Click(object sender, EventArgs e) + { + vertrepeat.Value = 1; + } + + private void repeat_ValueChanged(object sender, EventArgs e) + { + if(blockupdate) return; + UpdateChanges(); + } + + private void accept_Click(object sender, EventArgs e) + { + this.DialogResult = DialogResult.OK; + this.Close(); + } + + private void cancel_Click(object sender, EventArgs e) + { + this.DialogResult = DialogResult.Cancel; + this.Close(); + } + + private void cbfitwidth_CheckedChanged(object sender, EventArgs e) + { + if(blockupdate) return; + UpdateRepeatGroup(); + UpdateChanges(); + } + + private void cbfitheight_CheckedChanged(object sender, EventArgs e) + { + if(blockupdate) return; + UpdateRepeatGroup(); + UpdateChanges(); + } + + #endregion + + #region ================== Debug + +#if DEBUG + private void DrawDebugUV() + { + const int margin = 20; + + //find bounds + int minx = int.MaxValue; + int maxx = int.MinValue; + int miny = int.MaxValue; + int maxy = int.MinValue; + + foreach(SortedVisualSide side in strips) + { + if(side.Bounds.X < minx) minx = side.Bounds.X; + if(side.Bounds.X + side.Bounds.Width > maxx) maxx = side.Bounds.X + side.Bounds.Width; + if(side.Bounds.Y < miny) miny = side.Bounds.Y; + if(side.Bounds.Y + side.Bounds.Height > maxy) maxy = side.Bounds.Y + side.Bounds.Height; + } + + Bitmap bmp = new Bitmap(maxx - minx + margin * 2, maxy - miny + margin * 2); + + using(Graphics g = Graphics.FromImage(bmp)) + { + int i = 0; + + foreach(SortedVisualSide side in strips) + { + Color c = General.Colors.BrightColors[General.Random(0, General.Colors.BrightColors.Length - 1)].ToColor(); + Pen p = new Pen(c); + Brush b = new SolidBrush(c); + + int x = side.Bounds.X - minx + margin; + int y = side.Bounds.Y - miny + margin; + + g.DrawRectangle(p, x, y, side.Bounds.Width, side.Bounds.Height); + g.DrawString(i++ + ": line " + side.Side.Sidedef.Line.Index + "; x:" + side.Bounds.X + " y:" + side.Bounds.Y, this.Font, b, x + 2, y + 2); + } + } + + bmp.Save("testuv.png", ImageFormat.Png); + + General.Interface.DisplayStatus(StatusType.Info, "Saved test image!"); + } +#endif + + #endregion + } +} diff --git a/Source/Plugins/BuilderModes/Interface/FitTexturesForm.resx b/Source/Plugins/BuilderModes/Interface/FitTexturesForm.resx new file mode 100644 index 00000000..ff31a6db --- /dev/null +++ b/Source/Plugins/BuilderModes/Interface/FitTexturesForm.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/BuilderModes/Resources/Actions.cfg b/Source/Plugins/BuilderModes/Resources/Actions.cfg index 33f933a8..f8232935 100644 --- a/Source/Plugins/BuilderModes/Resources/Actions.cfg +++ b/Source/Plugins/BuilderModes/Resources/Actions.cfg @@ -908,39 +908,15 @@ visualautoaligntoselectiony //mxd visualfittextures { - title = "Fit Texture"; + title = "Fit Textures"; category = "visual"; - description = "Scales texture to match size of selected surface."; + description = "Scales textures to match the size of selected surfaces."; allowkeys = true; allowmouse = true; allowscroll = true; default = 393281; //Ctrl-Alt-A } -//mxd -visualfittexturesx -{ - title = "Fit Texture's Width"; - category = "visual"; - description = "Scales width of a texture to match width of selected surface."; - allowkeys = true; - allowmouse = true; - allowscroll = true; - default = 262209; //Alt-A -} - -//mxd -visualfittexturesy -{ - title = "Fit Texture's Height"; - category = "visual"; - description = "Scales height of a texture to match height of selected surface."; - allowkeys = true; - allowmouse = true; - allowscroll = true; - default = 327745; //Alt-Shift-A -} - toggleupperunpegged { title = "Toggle Upper Unpegged"; @@ -986,7 +962,7 @@ resettexture { title = "Reset Texture Offsets"; category = "visual"; - description = "Resets the texture offsets on the targeted or selected sidedef."; + description = "Resets the texture offsets on targeted or selected sidedefs."; allowkeys = true; allowmouse = true; allowscroll = true; @@ -997,7 +973,7 @@ resettextureudmf { title = "Reset Local Texture Offsets (UDMF)"; category = "visual"; - description = "Resets upper/middle/lower texture offsets and scale on the targeted or selected sidedef. Resets texture offsets, rotation and scale on targeted or selected floors/ceilings."; + description = "Resets upper/middle/lower texture offsets and scale on targeted or selected sidedefs. Resets texture offsets, rotation and scale on targeted or selected floors/ceilings."; allowkeys = true; allowmouse = true; allowscroll = true; diff --git a/Source/Plugins/BuilderModes/Resources/Hints.cfg b/Source/Plugins/BuilderModes/Resources/Hints.cfg index 6d74f548..10701fcf 100644 --- a/Source/Plugins/BuilderModes/Resources/Hints.cfg +++ b/Source/Plugins/BuilderModes/Resources/Hints.cfg @@ -129,7 +129,7 @@ group sidedefs "Use buildermodes_texturecopy, buildermodes_texturepaste and buildermodes_floodfilltextures to copy, paste and flood-fill highlighted texture" "Use buildermodes_texturecopyoffsets and buildermodes_texturepasteoffsets to copy and paste texture offsets" "Use buildermodes_visualautoalignx, buildermodes_visualautoalign or buildermodes_visualautoalign to auto align textures on X, Y and XY axis" -"Use buildermodes_visualfittexturesx, buildermodes_visualfittexturesy or buildermodes_visualfittextures to fit texture's width, height or both into it's surface (UDMF only)" +"Use buildermodes_visualfittextures to fit texture's width or height to selected surfaces (UDMF only)" "Use buildermodes_resettexture to reset global texture offsets" "Use buildermodes_resettextureudmf to reset local texture offsets and scale (UDMF only)" "Use buildermodes_toggleupperunpegged or buildermodes_togglelowerunpegged to toggle Upper or Lower Unpegged setting" diff --git a/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySector.cs b/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySector.cs index 4126aa4e..3bb67984 100644 --- a/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySector.cs +++ b/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySector.cs @@ -99,7 +99,7 @@ namespace CodeImp.DoomBuilder.BuilderModes public virtual void SelectNeighbours(bool select, bool withSameTexture, bool withSameHeight) { } //mxd // This swaps triangles so that the plane faces the other way - protected void SwapTriangleVertices(WorldVertex[] verts) + protected static void SwapTriangleVertices(WorldVertex[] verts) { // Swap some vertices to flip all triangles for(int i = 0; i < verts.Length; i += 3) @@ -260,7 +260,7 @@ namespace CodeImp.DoomBuilder.BuilderModes //do we need to align this? (and also grab texture scale while we are at it) float scaleX, scaleY; - bool isFloor = (geoType == VisualGeometryType.FLOOR); + bool isFloor = (geometrytype == VisualGeometryType.FLOOR); if(mode.HighlightedTarget is VisualFloor) { @@ -333,7 +333,7 @@ namespace CodeImp.DoomBuilder.BuilderModes //mxd protected void AlignTextureToSlopeLine(Linedef slopeSource, float slopeAngle, bool isFront, bool alignx, bool aligny) { - bool isFloor = (geoType == VisualGeometryType.FLOOR); + bool isFloor = (geometrytype == VisualGeometryType.FLOOR); Sector.Sector.Fields.BeforeFieldsChange(); float sourceAngle = (float)Math.Round(General.ClampAngle(isFront ? -Angle2D.RadToDeg(slopeSource.Angle) + 90 : -Angle2D.RadToDeg(slopeSource.Angle) - 90), 1); @@ -426,7 +426,7 @@ namespace CodeImp.DoomBuilder.BuilderModes // Unused public virtual void OnEditBegin() { } - public virtual void OnTextureFit(bool fitWidth, bool fitHeight) { } //mxd + public virtual void OnTextureFit(FitTextureOptions options) { } //mxd public virtual void OnToggleUpperUnpegged() { } public virtual void OnToggleLowerUnpegged() { } public virtual void OnResetTextureOffset() { } diff --git a/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySidedef.cs b/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySidedef.cs index 682bfd6e..6137c014 100644 --- a/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySidedef.cs +++ b/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySidedef.cs @@ -18,16 +18,16 @@ using System; using System.Collections.Generic; +using System.Drawing; using System.Windows.Forms; -using CodeImp.DoomBuilder.Config; using CodeImp.DoomBuilder.Data; +using CodeImp.DoomBuilder.Geometry; +using CodeImp.DoomBuilder.GZBuilder.Tools; using CodeImp.DoomBuilder.IO; using CodeImp.DoomBuilder.Map; using CodeImp.DoomBuilder.Rendering; -using CodeImp.DoomBuilder.Geometry; +using CodeImp.DoomBuilder.Types; using CodeImp.DoomBuilder.VisualModes; -using System.Drawing; -using CodeImp.DoomBuilder.GZBuilder.Tools; #endregion @@ -43,7 +43,7 @@ namespace CodeImp.DoomBuilder.BuilderModes #region ================== Variables - protected BaseVisualMode mode; + protected readonly BaseVisualMode mode; protected Plane top; protected Plane bottom; @@ -236,7 +236,7 @@ namespace CodeImp.DoomBuilder.BuilderModes // This splits a polygon with a plane and returns the other part as a new polygon // The polygon is expected to be convex and clockwise - protected WallPolygon SplitPoly(ref WallPolygon poly, Plane p, bool keepfront) + protected static WallPolygon SplitPoly(ref WallPolygon poly, Plane p, bool keepfront) { const float NEAR_ZERO = 0.01f; WallPolygon front = new WallPolygon(poly.Count); @@ -312,7 +312,7 @@ namespace CodeImp.DoomBuilder.BuilderModes // This crops a polygon with a plane and keeps only a certain part of the polygon - protected void CropPoly(ref WallPolygon poly, Plane p, bool keepfront) + protected static void CropPoly(ref WallPolygon poly, Plane p, bool keepfront) { const float NEAR_ZERO = 0.01f; float sideswitch = keepfront ? 1 : -1; @@ -372,7 +372,7 @@ namespace CodeImp.DoomBuilder.BuilderModes } //mxd - protected float GetRoundedTextureOffset(float oldValue, float offset, float scale, float textureSize) + protected static float GetRoundedTextureOffset(float oldValue, float offset, float scale, float textureSize) { if(offset == 0f) return oldValue; float scaledOffset = offset * scale; @@ -383,7 +383,7 @@ namespace CodeImp.DoomBuilder.BuilderModes } //mxd - protected void OnTextureChanged() + private void OnTextureChanged() { //check for 3d floors if(Sidedef.Line.Action == 160) @@ -400,7 +400,6 @@ namespace CodeImp.DoomBuilder.BuilderModes } } } - } //mxd @@ -408,7 +407,7 @@ namespace CodeImp.DoomBuilder.BuilderModes { if(Sidedef.Sector == null || (!withSameTexture && !withSameHeight)) return; - Rectangle rect = BuilderModesTools.GetSidedefPartSize(this, geoType); + Rectangle rect = BuilderModesTools.GetSidedefPartSize(this); if(rect.Height == 0) return; if(select && !selected) @@ -477,8 +476,8 @@ namespace CodeImp.DoomBuilder.BuilderModes && line.Front.HighRequired() && BuilderModesTools.GetSidedefPartSize(line.Front, VisualGeometryType.WALL_UPPER).IntersectsWith(rect)); - addFrontMiddle = (line.Front.MiddleTexture == texture - && line.Front.MiddleRequired() + addFrontMiddle = (line.Front.MiddleTexture == texture + && (line.Front.MiddleRequired() || line.Back != null) && line.Front.GetMiddleHeight() > 0 && BuilderModesTools.GetSidedefPartSize(line.Front, VisualGeometryType.WALL_MIDDLE).IntersectsWith(rect)); @@ -495,7 +494,7 @@ namespace CodeImp.DoomBuilder.BuilderModes && BuilderModesTools.GetSidedefPartSize(line.Back, VisualGeometryType.WALL_UPPER).IntersectsWith(rect)); addBackMiddle = (line.Back.MiddleTexture == texture - && line.Back.MiddleRequired() + && (line.Back.MiddleRequired() || line.Front != null) && line.Back.GetMiddleHeight() > 0 && BuilderModesTools.GetSidedefPartSize(line.Back, VisualGeometryType.WALL_MIDDLE).IntersectsWith(rect)); @@ -600,6 +599,96 @@ namespace CodeImp.DoomBuilder.BuilderModes { return selected; } + + //mxd + protected void FitTexture(FitTextureOptions options) + { + // Create undo name + string s; + if(options.FitWidth && options.FitHeight) s = "width and height"; + else if(options.FitWidth) s = "width"; + else s = "height"; + + //create undo + mode.CreateUndo("Fit texture (" + s + ")", UndoGroup.TextureOffsetChange, Sector.Sector.FixedIndex); + Sidedef.Fields.BeforeFieldsChange(); + + // Fit width + if(options.FitWidth) + { + float scalex, offsetx; + + if(options.FitAcrossSurfaces) + { + scalex = Texture.ScaledWidth / (Sidedef.Line.Length * (options.GlobalBounds.Width / Sidedef.Line.Length)) * options.HorizontalRepeat; + offsetx = (float)Math.Round((options.Bounds.X * scalex - Sidedef.OffsetX) % Texture.Width, General.Map.FormatInterface.VertexDecimals); + } + else + { + scalex = Texture.ScaledWidth / Sidedef.Line.Length * options.HorizontalRepeat; + offsetx = -Sidedef.OffsetX; + } + + UDMFTools.SetFloat(Sidedef.Fields, "scalex_" + partname, (float)Math.Round(scalex, General.Map.FormatInterface.VertexDecimals), 1.0f); + UDMFTools.SetFloat(Sidedef.Fields, "offsetx_" + partname, offsetx, 0.0f); + } + else + { + // Restore initial offsets + UDMFTools.SetFloat(Sidedef.Fields, "scalex_" + partname, options.InitialScaleX, 1.0f); + UDMFTools.SetFloat(Sidedef.Fields, "offsetx_" + partname, options.InitialOffsetX, 0.0f); + } + + // Fit height + if(options.FitHeight) + { + if(Sidedef.Sector != null) + { + float scaley, offsety; + + if(options.FitAcrossSurfaces) + { + scaley = Texture.ScaledHeight / (options.Bounds.Height * ((float)options.GlobalBounds.Height / options.Bounds.Height)) * options.VerticalRepeat; + + if(this is VisualLower) // Special cases, special cases... + { + offsety = Tools.GetSidedefOffsetY(Sidedef, geometrytype, -Sidedef.OffsetY, scaley, true) % Texture.Height; + } + else if(this is VisualMiddleDouble) + { + if (Sidedef.Line.IsFlagSet(General.Map.Config.LowerUnpeggedFlag)) + { + //offsety = Tools.GetSidedefOffsetY(Sidedef, geometrytype, options.Bounds.Y * scaley - Sidedef.OffsetY, scaley, true) - (options.Bounds.Height + Sidedef.GetHighHeight()) * scaley; + offsety = (options.Bounds.Y - /*options.Bounds.Height -*/ Sidedef.GetHighHeight()) * scaley - Sidedef.OffsetY; + //offsety = Tools.GetSidedefOffsetY(Sidedef, geometrytype, offsety, scaley, true); + } + else + { + offsety = options.Bounds.Y * scaley - Sidedef.OffsetY; + } + } + else + { + offsety = Tools.GetSidedefOffsetY(Sidedef, geometrytype, options.Bounds.Y * scaley - Sidedef.OffsetY, scaley, true) % Texture.Height; + } + } + else + { + scaley = Texture.ScaledHeight / options.Bounds.Height * options.VerticalRepeat; + offsety = Tools.GetSidedefOffsetY(Sidedef, geometrytype, -Sidedef.OffsetY, scaley, true) % Texture.Height; + } + + UDMFTools.SetFloat(Sidedef.Fields, "scaley_" + partname, (float)Math.Round(scaley, General.Map.FormatInterface.VertexDecimals), 1.0f); + UDMFTools.SetFloat(Sidedef.Fields, "offsety_" + partname, (float)Math.Round(offsety, General.Map.FormatInterface.VertexDecimals), 0.0f); + } + } + else + { + // Restore initial offsets + UDMFTools.SetFloat(Sidedef.Fields, "scaley_" + partname, options.InitialScaleY, 1.0f); + UDMFTools.SetFloat(Sidedef.Fields, "offsety_" + partname, options.InitialOffsetY, 0.0f); + } + } #endregion @@ -615,7 +704,7 @@ namespace CodeImp.DoomBuilder.BuilderModes protected abstract void MoveTextureOffset(Point xy); protected abstract Point GetTextureOffset(); public virtual void SelectNeighbours(bool select, bool withSameTexture, bool withSameHeight) { } //mxd - public virtual void OnTextureFit(bool fitWidth, bool fitHeight) { } //mxd + public virtual void OnTextureFit(FitTextureOptions options) { } //mxd // Insert middle texture public virtual void OnInsert() @@ -1178,6 +1267,15 @@ namespace CodeImp.DoomBuilder.BuilderModes float offsety = dragdeltaz.GetLength(); if((Math.Sign(dragdeltaxy.x) < 0) || (Math.Sign(dragdeltaxy.y) < 0) || (Math.Sign(dragdeltaxy.z) < 0)) offsetx = -offsetx; if((Math.Sign(dragdeltaz.x) < 0) || (Math.Sign(dragdeltaz.y) < 0) || (Math.Sign(dragdeltaz.z) < 0)) offsety = -offsety; + + //mxd. Modify by surface scale? + if (General.Map.UDMF) + { + float sx = UDMFTools.GetFloat(Sidedef.Fields, "scalex_" + partname, 1.0f); + float sy = UDMFTools.GetFloat(Sidedef.Fields, "scaley_" + partname, 1.0f); + if (Math.Abs(sx) < 1) offsetx *= sx; + if (Math.Abs(sy) < 1) offsety *= sy; + } // Apply offsets if(General.Interface.CtrlState && General.Interface.ShiftState) @@ -1226,7 +1324,33 @@ namespace CodeImp.DoomBuilder.BuilderModes // Sector brightness change public virtual void OnChangeTargetBrightness(bool up) { - if(!Sector.Changed) + //mxd. Change UDMF wall light? + if (General.Map.UDMF) + { + int light = Sidedef.Fields.GetValue("light", 0); + bool absolute = Sidedef.Fields.GetValue("lightabsolute", false); + int newLight; + + if(up) + newLight = General.Map.Config.BrightnessLevels.GetNextHigher(light, absolute); + else + newLight = General.Map.Config.BrightnessLevels.GetNextLower(light, absolute); + + if(newLight == light) return; + + //create undo + mode.CreateUndo("Change wall brightness", UndoGroup.SurfaceBrightnessChange, Sector.Sector.FixedIndex); + Sidedef.Fields.BeforeFieldsChange(); + + //apply changes + Sidedef.Fields["light"] = new UniValue(UniversalType.Integer, newLight); + mode.SetActionResult("Changed wall brightness to " + newLight + "."); + Sector.Sector.UpdateCache(); + + //rebuild sector + Sector.UpdateSectorGeometry(false); + } + else if(!Sector.Changed) { // Change brightness mode.CreateUndo("Change sector brightness", UndoGroup.SectorBrightnessChange, Sector.Sector.FixedIndex); @@ -1279,7 +1403,7 @@ namespace CodeImp.DoomBuilder.BuilderModes Sidedef.OffsetX = (Sidedef.OffsetX - horizontal); if (Texture != null) Sidedef.OffsetX %= Texture.Width; Sidedef.OffsetY = (Sidedef.OffsetY - vertical); - if(geoType != VisualGeometryType.WALL_MIDDLE && Texture != null) Sidedef.OffsetY %= Texture.Height; + if(geometrytype != VisualGeometryType.WALL_MIDDLE && Texture != null) Sidedef.OffsetY %= Texture.Height; mode.SetActionResult("Changed texture offsets to " + Sidedef.OffsetX + ", " + Sidedef.OffsetY + "."); } diff --git a/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs b/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs index b35c9caa..935eccfb 100644 --- a/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs +++ b/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs @@ -294,8 +294,7 @@ namespace CodeImp.DoomBuilder.BuilderModes selectionchanged = false; - if(singleselection) - ClearSelection(); + if(singleselection) ClearSelection(); UpdateChangedObjects(); ShowTargetInfo(); @@ -2115,11 +2114,15 @@ namespace CodeImp.DoomBuilder.BuilderModes foreach(BaseVisualThing vt in things) { if(vt.Thing.Sector == null) continue; - ThingTypeInfo ti = General.Map.Data.GetThingInfo(vt.Thing.Type); - int zvalue = (int)(vt.Thing.Sector.FloorHeight + vt.Thing.Position.z); - if(zvalue != vt.Thing.Sector.CeilHeight - ti.Height) - vt.OnChangeTargetHeight((int)(vt.Thing.Sector.CeilHeight - ti.Height) - zvalue); + if (vt.Info.Hangs) + { + vt.OnMove(new Vector3D(vt.Thing.Position, 0)); + } + else + { + vt.OnMove(new Vector3D(vt.Thing.Position, vt.Thing.Sector.CeilHeight - vt.Info.Height)); + } } } @@ -2327,8 +2330,14 @@ namespace CodeImp.DoomBuilder.BuilderModes { if(vt.Thing.Sector == null) continue; - if(vt.Thing.Position.z != 0) - vt.OnChangeTargetHeight((int)-vt.Thing.Position.z); + if (vt.Info.Hangs) + { + vt.OnMove(new Vector3D(vt.Thing.Position, vt.Thing.Sector.CeilHeight - vt.Thing.Sector.FloorHeight - vt.Info.Height)); + } + else + { + vt.OnMove(new Vector3D(vt.Thing.Position, 0)); + } } } @@ -2770,31 +2779,32 @@ namespace CodeImp.DoomBuilder.BuilderModes //mxd [BeginAction("visualfittextures")] - public void TextureFit() + private void FitTextures() { PreAction(UndoGroup.None); + + // Get selection List objs = GetSelectedObjects(false, true, false, false); - foreach(IVisualEventReceiver i in objs) i.OnTextureFit(true, true); - PostAction(); - } + List sides = new List(); + foreach(IVisualEventReceiver side in objs) + { + if(side is BaseVisualGeometrySidedef) sides.Add(side as BaseVisualGeometrySidedef); + } - //mxd - [BeginAction("visualfittexturesx")] - public void TextureFitX() - { - PreAction(UndoGroup.None); - List objs = GetSelectedObjects(false, true, false, false); - foreach(IVisualEventReceiver i in objs) i.OnTextureFit(true, false); - PostAction(); - } + if(sides.Count == 0) + { + General.Interface.DisplayStatus(StatusType.Warning, "Fit Textures action requires selected sidedefs."); + return; + } + + // Show form + FitTexturesForm form = new FitTexturesForm(); + form.Setup(sides); + + // Undo changes? + if(form.ShowDialog((Form)General.Interface) == DialogResult.Cancel) + General.Map.UndoRedo.WithdrawUndo(); - //mxd - [BeginAction("visualfittexturesy")] - public void TextureFitY() - { - PreAction(UndoGroup.None); - List objs = GetSelectedObjects(false, true, false, false); - foreach(IVisualEventReceiver i in objs) i.OnTextureFit(false, true); PostAction(); } @@ -3698,15 +3708,26 @@ namespace CodeImp.DoomBuilder.BuilderModes } else { - offset = Tools.GetSidedefMiddleOffsetY(j.sidedef, offset, j.scaleY, true); + offset = Tools.GetSidedefMiddleOffsetY(j.sidedef, offset, j.scaleY, true) % texture.Height; - //mxd. Clamp offset if this part is middle single or wrapped middle double - if(j.sidedef.Other == null || j.sidedef.IsFlagSet("wrapmidtex") || j.sidedef.Line.IsFlagSet("wrapmidtex")) + if(j.sidedef.Other != null && !j.sidedef.IsFlagSet("wrapmidtex") && !j.sidedef.Line.IsFlagSet("wrapmidtex")) { - offset %= texture.Height; + //mxd. This should be doublesided non-wrapped line. Find the nearset aligned position + float curoffset = UDMFTools.GetFloat(j.sidedef.Fields, "offsety_mid"); + offset += texture.Height * (int)Math.Round((curoffset - offset) / texture.Height); + + // Make sure the surface stays between floor and ceiling + if (offset < -texture.Height) + { + offset += texture.Height; + } + else if(offset + texture.Height > j.sidedef.GetMiddleHeight()) + { + offset -= texture.Height; + } } - j.sidedef.Fields["offsety_mid"] = new UniValue(UniversalType.Float, offset);//mxd + j.sidedef.Fields["offsety_mid"] = new UniValue(UniversalType.Float, offset); //mxd } } } diff --git a/Source/Plugins/BuilderModes/VisualModes/BaseVisualThing.cs b/Source/Plugins/BuilderModes/VisualModes/BaseVisualThing.cs index 41f0c6d1..10b484c3 100644 --- a/Source/Plugins/BuilderModes/VisualModes/BaseVisualThing.cs +++ b/Source/Plugins/BuilderModes/VisualModes/BaseVisualThing.cs @@ -38,7 +38,7 @@ namespace CodeImp.DoomBuilder.BuilderModes #region ================== Variables - protected BaseVisualMode mode; + private readonly BaseVisualMode mode; private ThingTypeInfo info; private bool isloaded; @@ -60,7 +60,8 @@ namespace CodeImp.DoomBuilder.BuilderModes #region ================== Properties public bool Changed { get { return changed; } set { changed |= value; } } - + public ThingTypeInfo Info { get { return info; } } //mxd + #endregion #region ================== Constructor / Setup @@ -473,7 +474,7 @@ namespace CodeImp.DoomBuilder.BuilderModes public virtual void OnProcess(float deltatime) { } public virtual void OnTextureFloodfill() { } public virtual void OnInsert() { } - public virtual void OnTextureFit(bool fitWidth, bool fitHeight) { } //mxd + public virtual void OnTextureFit(FitTextureOptions options) { } //mxd public virtual void ApplyTexture(string texture) { } public virtual void ApplyUpperUnpegged(bool set) { } public virtual void ApplyLowerUnpegged(bool set) { } @@ -572,7 +573,7 @@ namespace CodeImp.DoomBuilder.BuilderModes if((General.Map.UndoRedo.NextUndo == null) || (General.Map.UndoRedo.NextUndo.TicketID != undoticket)) undoticket = mode.CreateUndo("Change thing height"); - Thing.Move(Thing.Position + new Vector3D(0.0f, 0.0f, amount)); + Thing.Move(Thing.Position + new Vector3D(0.0f, 0.0f, (info.Hangs ? -amount : amount))); mode.SetActionResult("Changed thing height to " + Thing.Position.z + "."); diff --git a/Source/Plugins/BuilderModes/VisualModes/BaseVisualVertex.cs b/Source/Plugins/BuilderModes/VisualModes/BaseVisualVertex.cs index 72c33616..6caa6623 100644 --- a/Source/Plugins/BuilderModes/VisualModes/BaseVisualVertex.cs +++ b/Source/Plugins/BuilderModes/VisualModes/BaseVisualVertex.cs @@ -238,7 +238,7 @@ namespace CodeImp.DoomBuilder.BuilderModes public virtual void OnCopyTextureOffsets() { } public virtual void OnPasteTextureOffsets() { } public virtual void OnTextureAlign(bool alignx, bool aligny) { } - public virtual void OnTextureFit(bool fitWidth, bool fitHeight) { } //mxd + public virtual void OnTextureFit(FitTextureOptions options) { } //mxd public virtual void OnToggleUpperUnpegged() { } public virtual void OnToggleLowerUnpegged() { } public virtual void OnResetTextureOffset() { } diff --git a/Source/Plugins/BuilderModes/VisualModes/IVisualEventReceiver.cs b/Source/Plugins/BuilderModes/VisualModes/IVisualEventReceiver.cs index 598e9fdb..8d6c97ba 100644 --- a/Source/Plugins/BuilderModes/VisualModes/IVisualEventReceiver.cs +++ b/Source/Plugins/BuilderModes/VisualModes/IVisualEventReceiver.cs @@ -44,7 +44,7 @@ namespace CodeImp.DoomBuilder.BuilderModes void OnCopyProperties(); void OnPasteProperties(); void OnTextureAlign(bool alignx, bool aligny); - void OnTextureFit(bool fitWidth, bool fitHeight); //mxd + void OnTextureFit(FitTextureOptions options); //mxd void OnTextureFloodfill(); void OnToggleUpperUnpegged(); void OnToggleLowerUnpegged(); diff --git a/Source/Plugins/BuilderModes/VisualModes/NullVisualEventReceiver.cs b/Source/Plugins/BuilderModes/VisualModes/NullVisualEventReceiver.cs index c2eff000..3b75f8b7 100644 --- a/Source/Plugins/BuilderModes/VisualModes/NullVisualEventReceiver.cs +++ b/Source/Plugins/BuilderModes/VisualModes/NullVisualEventReceiver.cs @@ -45,7 +45,7 @@ namespace CodeImp.DoomBuilder.BuilderModes public void OnCopyProperties() { } public void OnPasteProperties() { } public void OnTextureAlign(bool alignx, bool aligny) { } - public void OnTextureFit(bool fitWidth, bool fitHeight) { } //mxd + public void OnTextureFit(FitTextureOptions options) { } //mxd public void OnTextureFloodfill() { } public void OnToggleUpperUnpegged() { } public void OnToggleLowerUnpegged() { } diff --git a/Source/Plugins/BuilderModes/VisualModes/VisualCeiling.cs b/Source/Plugins/BuilderModes/VisualModes/VisualCeiling.cs index 60aff033..a3062d9f 100644 --- a/Source/Plugins/BuilderModes/VisualModes/VisualCeiling.cs +++ b/Source/Plugins/BuilderModes/VisualModes/VisualCeiling.cs @@ -54,7 +54,8 @@ namespace CodeImp.DoomBuilder.BuilderModes public VisualCeiling(BaseVisualMode mode, VisualSector vs) : base(mode, vs) { //mxd - geoType = VisualGeometryType.CEILING; + geometrytype = VisualGeometryType.CEILING; + partname = "ceiling"; //mxd if(mode.UseSelectionFromClassicMode && vs != null && vs.Sector.Selected && (General.Map.ViewMode == ViewMode.CeilingTextures || General.Map.ViewMode == ViewMode.Normal)) diff --git a/Source/Plugins/BuilderModes/VisualModes/VisualFloor.cs b/Source/Plugins/BuilderModes/VisualModes/VisualFloor.cs index e4021098..9d554781 100644 --- a/Source/Plugins/BuilderModes/VisualModes/VisualFloor.cs +++ b/Source/Plugins/BuilderModes/VisualModes/VisualFloor.cs @@ -54,7 +54,8 @@ namespace CodeImp.DoomBuilder.BuilderModes public VisualFloor(BaseVisualMode mode, VisualSector vs) : base(mode, vs) { //mxd - geoType = VisualGeometryType.FLOOR; + geometrytype = VisualGeometryType.FLOOR; + partname = "floor"; //mxd if(mode.UseSelectionFromClassicMode && vs != null && vs.Sector.Selected @@ -243,7 +244,7 @@ namespace CodeImp.DoomBuilder.BuilderModes mode.SetActionResult("Texture offsets reset."); Sector.Sector.Fields.BeforeFieldsChange(); - string[] keys = new string[] { "xpanningfloor", "ypanningfloor", "xscalefloor", "yscalefloor", "rotationfloor" }; + string[] keys = new[] { "xpanningfloor", "ypanningfloor", "xscalefloor", "yscalefloor", "rotationfloor" }; foreach(string key in keys) { diff --git a/Source/Plugins/BuilderModes/VisualModes/VisualLower.cs b/Source/Plugins/BuilderModes/VisualModes/VisualLower.cs index 4211f1ce..5bebc23f 100644 --- a/Source/Plugins/BuilderModes/VisualModes/VisualLower.cs +++ b/Source/Plugins/BuilderModes/VisualModes/VisualLower.cs @@ -51,7 +51,8 @@ namespace CodeImp.DoomBuilder.BuilderModes public VisualLower(BaseVisualMode mode, VisualSector vs, Sidedef s) : base(mode, vs, s) { //mxd - geoType = VisualGeometryType.WALL_LOWER; + geometrytype = VisualGeometryType.WALL_LOWER; + partname = "bottom"; // We have no destructor GC.SuppressFinalize(this); @@ -302,69 +303,11 @@ namespace CodeImp.DoomBuilder.BuilderModes } //mxd - public override void OnChangeTargetBrightness(bool up) - { - if(!General.Map.UDMF) - { - base.OnChangeTargetBrightness(up); - return; - } - - int light = Sidedef.Fields.GetValue("light", 0); - bool absolute = Sidedef.Fields.GetValue("lightabsolute", false); - int newLight; - - if(up) - newLight = General.Map.Config.BrightnessLevels.GetNextHigher(light, absolute); - else - newLight = General.Map.Config.BrightnessLevels.GetNextLower(light, absolute); - - if(newLight == light) return; - - //create undo - mode.CreateUndo("Change lower wall brightness", UndoGroup.SurfaceBrightnessChange, Sector.Sector.FixedIndex); - Sidedef.Fields.BeforeFieldsChange(); - - //apply changes - Sidedef.Fields["light"] = new UniValue(UniversalType.Integer, newLight); - mode.SetActionResult("Changed lower wall brightness to " + newLight + "."); - Sector.Sector.UpdateCache(); - - //rebuild sector - Sector.UpdateSectorGeometry(false); - } - - //mxd - public override void OnTextureFit(bool fitWidth, bool fitHeight) + public override void OnTextureFit(FitTextureOptions options) { if(!General.Map.UDMF) return; if(!Sidedef.LowRequired() || string.IsNullOrEmpty(Sidedef.LowTexture) || Sidedef.LowTexture == "-" || !Texture.IsImageLoaded) return; - - string s; - if(fitWidth && fitHeight) s = "width and height"; - else if(fitWidth) s = "width"; - else s = "height"; - - //create undo - mode.CreateUndo("Fit texture (" + s + ")", UndoGroup.TextureOffsetChange, Sector.Sector.FixedIndex); - Sidedef.Fields.BeforeFieldsChange(); - - if(fitWidth) - { - float scaleX = Texture.ScaledWidth / Sidedef.Line.Length; - UDMFTools.SetFloat(Sidedef.Fields, "scalex_bottom", scaleX, 1.0f); - UDMFTools.SetFloat(Sidedef.Fields, "offsetx_bottom", -Sidedef.OffsetX, 0.0f); - } - - if(fitHeight && Sidedef.Sector != null && Sidedef.Other.Sector != null) - { - float scaleY = (float)Texture.Height / (Sidedef.Other.Sector.FloorHeight - Sidedef.Sector.FloorHeight); - UDMFTools.SetFloat(Sidedef.Fields, "scaley_bottom", scaleY, 1.0f); - - float offsetY = Tools.GetSidedefBottomOffsetY(Sidedef, -Sidedef.OffsetY, scaleY, true) % Texture.Height; - UDMFTools.SetFloat(Sidedef.Fields, "offsety_bottom", offsetY, 0.0f); - } - + FitTexture(options); Setup(); } diff --git a/Source/Plugins/BuilderModes/VisualModes/VisualMiddle3D.cs b/Source/Plugins/BuilderModes/VisualModes/VisualMiddle3D.cs index e99ea39d..30c6d451 100644 --- a/Source/Plugins/BuilderModes/VisualModes/VisualMiddle3D.cs +++ b/Source/Plugins/BuilderModes/VisualModes/VisualMiddle3D.cs @@ -52,7 +52,8 @@ namespace CodeImp.DoomBuilder.BuilderModes public VisualMiddle3D(BaseVisualMode mode, VisualSector vs, Sidedef s) : base(mode, vs, s) { //mxd - geoType = VisualGeometryType.WALL_MIDDLE_3D; + geometrytype = VisualGeometryType.WALL_MIDDLE_3D; + partname = "mid"; // We have no destructor GC.SuppressFinalize(this); diff --git a/Source/Plugins/BuilderModes/VisualModes/VisualMiddleBack.cs b/Source/Plugins/BuilderModes/VisualModes/VisualMiddleBack.cs index 2fe1c2aa..472da905 100644 --- a/Source/Plugins/BuilderModes/VisualModes/VisualMiddleBack.cs +++ b/Source/Plugins/BuilderModes/VisualModes/VisualMiddleBack.cs @@ -29,7 +29,8 @@ namespace CodeImp.DoomBuilder.BuilderModes { : base(mode, vs, s) { //mxd - geoType = VisualGeometryType.WALL_MIDDLE; + geometrytype = VisualGeometryType.WALL_MIDDLE; + partname = "mid"; // We have no destructor GC.SuppressFinalize(this); @@ -345,39 +346,6 @@ namespace CodeImp.DoomBuilder.BuilderModes { return new Point((int)oldx, (int)oldy); } - //mxd - public override void OnChangeTargetBrightness(bool up) - { - if(!General.Map.UDMF) - { - base.OnChangeTargetBrightness(up); - return; - } - - int light = Sidedef.Fields.GetValue("light", 0); - bool absolute = Sidedef.Fields.GetValue("lightabsolute", false); - int newLight; - - if(up) - newLight = General.Map.Config.BrightnessLevels.GetNextHigher(light, absolute); - else - newLight = General.Map.Config.BrightnessLevels.GetNextLower(light, absolute); - - if(newLight == light) return; - - //create undo - mode.CreateUndo("Change middle wall brightness", UndoGroup.SurfaceBrightnessChange, Sector.Sector.FixedIndex); - Sidedef.Fields.BeforeFieldsChange(); - - //apply changes - Sidedef.Fields["light"] = new UniValue(UniversalType.Integer, newLight); - mode.SetActionResult("Changed middle wall brightness to " + newLight + "."); - Sector.Sector.UpdateCache(); - - //rebuild sector - Sector.UpdateSectorGeometry(false); - } - //mxd public override Linedef GetControlLinedef() { diff --git a/Source/Plugins/BuilderModes/VisualModes/VisualMiddleDouble.cs b/Source/Plugins/BuilderModes/VisualModes/VisualMiddleDouble.cs index d2fb3b20..05907905 100644 --- a/Source/Plugins/BuilderModes/VisualModes/VisualMiddleDouble.cs +++ b/Source/Plugins/BuilderModes/VisualModes/VisualMiddleDouble.cs @@ -55,7 +55,8 @@ namespace CodeImp.DoomBuilder.BuilderModes public VisualMiddleDouble(BaseVisualMode mode, VisualSector vs, Sidedef s) : base(mode, vs, s) { //mxd - geoType = VisualGeometryType.WALL_MIDDLE; + geometrytype = VisualGeometryType.WALL_MIDDLE; + partname = "mid"; // Set render pass this.RenderPass = RenderPass.Mask; @@ -360,69 +361,11 @@ namespace CodeImp.DoomBuilder.BuilderModes } //mxd - public override void OnChangeTargetBrightness(bool up) - { - if(!General.Map.UDMF) - { - base.OnChangeTargetBrightness(up); - return; - } - - int light = Sidedef.Fields.GetValue("light", 0); - bool absolute = Sidedef.Fields.GetValue("lightabsolute", false); - int newLight; - - if(up) - newLight = General.Map.Config.BrightnessLevels.GetNextHigher(light, absolute); - else - newLight = General.Map.Config.BrightnessLevels.GetNextLower(light, absolute); - - if(newLight == light) return; - - //create undo - mode.CreateUndo("Change middle wall brightness", UndoGroup.SurfaceBrightnessChange, Sector.Sector.FixedIndex); - Sidedef.Fields.BeforeFieldsChange(); - - //apply changes - Sidedef.Fields["light"] = new UniValue(UniversalType.Integer, newLight); - mode.SetActionResult("Changed middle wall brightness to " + newLight + "."); - Sector.Sector.UpdateCache(); - - //rebuild sector - Sector.UpdateSectorGeometry(false); - } - - //mxd - public override void OnTextureFit(bool fitWidth, bool fitHeight) + public override void OnTextureFit(FitTextureOptions options) { if(!General.Map.UDMF) return; if(string.IsNullOrEmpty(Sidedef.MiddleTexture) || Sidedef.MiddleTexture == "-" || !Texture.IsImageLoaded) return; - - string s; - if(fitWidth && fitHeight) s = "width and height"; - else if(fitWidth) s = "width"; - else s = "height"; - - //create undo - mode.CreateUndo("Fit texture (" + s + ")", UndoGroup.TextureOffsetChange, Sector.Sector.FixedIndex); - Sidedef.Fields.BeforeFieldsChange(); - - if(fitWidth) - { - float scaleX = Texture.ScaledWidth / Sidedef.Line.Length; - UDMFTools.SetFloat(Sidedef.Fields, "scalex_mid", scaleX, 1.0f); - UDMFTools.SetFloat(Sidedef.Fields, "offsetx_mid", -Sidedef.OffsetX, 0.0f); - } - - if(fitHeight && Sidedef.Sector != null) - { - float scaleY = Texture.ScaledHeight / (Sidedef.Sector.CeilHeight - Sidedef.Sector.FloorHeight); - UDMFTools.SetFloat(Sidedef.Fields, "scaley_mid", scaleY, 1.0f); - - float offsetY = Tools.GetSidedefMiddleOffsetY(Sidedef, -Sidedef.OffsetY, scaleY, true) % Texture.Height; - UDMFTools.SetFloat(Sidedef.Fields, "offsety_mid", offsetY, 0.0f); - } - + FitTexture(options); Setup(); } diff --git a/Source/Plugins/BuilderModes/VisualModes/VisualMiddleSingle.cs b/Source/Plugins/BuilderModes/VisualModes/VisualMiddleSingle.cs index cdca8e46..096cd5be 100644 --- a/Source/Plugins/BuilderModes/VisualModes/VisualMiddleSingle.cs +++ b/Source/Plugins/BuilderModes/VisualModes/VisualMiddleSingle.cs @@ -51,7 +51,8 @@ namespace CodeImp.DoomBuilder.BuilderModes public VisualMiddleSingle(BaseVisualMode mode, VisualSector vs, Sidedef s) : base(mode, vs, s) { //mxd - geoType = VisualGeometryType.WALL_MIDDLE; + geometrytype = VisualGeometryType.WALL_MIDDLE; + partname = "mid"; // We have no destructor GC.SuppressFinalize(this); @@ -293,69 +294,11 @@ namespace CodeImp.DoomBuilder.BuilderModes } //mxd - public override void OnChangeTargetBrightness(bool up) - { - if(!General.Map.UDMF) - { - base.OnChangeTargetBrightness(up); - return; - } - - int light = Sidedef.Fields.GetValue("light", 0); - bool absolute = Sidedef.Fields.GetValue("lightabsolute", false); - int newLight; - - if(up) - newLight = General.Map.Config.BrightnessLevels.GetNextHigher(light, absolute); - else - newLight = General.Map.Config.BrightnessLevels.GetNextLower(light, absolute); - - if(newLight == light) return; - - //create undo - mode.CreateUndo("Change middle wall brightness", UndoGroup.SurfaceBrightnessChange, Sector.Sector.FixedIndex); - Sidedef.Fields.BeforeFieldsChange(); - - //apply changes - Sidedef.Fields["light"] = new UniValue(UniversalType.Integer, newLight); - mode.SetActionResult("Changed middle wall brightness to " + newLight + "."); - Sector.Sector.UpdateCache(); - - //rebuild sector - Sector.UpdateSectorGeometry(false); - } - - //mxd - public override void OnTextureFit(bool fitWidth, bool fitHeight) + public override void OnTextureFit(FitTextureOptions options) { if(!General.Map.UDMF) return; if(string.IsNullOrEmpty(Sidedef.MiddleTexture) || Sidedef.MiddleTexture == "-" || !Texture.IsImageLoaded) return; - - string s; - if(fitWidth && fitHeight) s = "width and height"; - else if(fitWidth) s = "width"; - else s = "height"; - - //create undo - mode.CreateUndo("Fit texture (" + s + ")", UndoGroup.TextureOffsetChange, Sector.Sector.FixedIndex); - Sidedef.Fields.BeforeFieldsChange(); - - if(fitWidth) - { - float scaleX = Texture.ScaledWidth / Sidedef.Line.Length; - UDMFTools.SetFloat(Sidedef.Fields, "scalex_mid", scaleX, 1.0f); - UDMFTools.SetFloat(Sidedef.Fields, "offsetx_mid", -Sidedef.OffsetX, 0.0f); - } - - if(fitHeight && Sidedef.Sector != null) - { - float scaleY = Texture.ScaledHeight / (Sidedef.Sector.CeilHeight - Sidedef.Sector.FloorHeight); - UDMFTools.SetFloat(Sidedef.Fields, "scaley_mid", scaleY, 1.0f); - - float offsetY = Tools.GetSidedefMiddleOffsetY(Sidedef, -Sidedef.OffsetY, scaleY, true) % Texture.Height; - UDMFTools.SetFloat(Sidedef.Fields, "offsety_mid", offsetY, 0.0f); - } - + FitTexture(options); Setup(); } diff --git a/Source/Plugins/BuilderModes/VisualModes/VisualSidedefParts.cs b/Source/Plugins/BuilderModes/VisualModes/VisualSidedefParts.cs index b8a7e10c..5e48aa76 100644 --- a/Source/Plugins/BuilderModes/VisualModes/VisualSidedefParts.cs +++ b/Source/Plugins/BuilderModes/VisualModes/VisualSidedefParts.cs @@ -25,12 +25,12 @@ namespace CodeImp.DoomBuilder.BuilderModes internal struct VisualSidedefParts { // Members - public VisualUpper upper; - public VisualLower lower; - public VisualMiddleDouble middledouble; - public VisualMiddleSingle middlesingle; - public List middle3d; - public List middleback;//mxd + public readonly VisualUpper upper; + public readonly VisualLower lower; + public readonly VisualMiddleDouble middledouble; + public readonly VisualMiddleSingle middlesingle; + public readonly List middle3d; + public readonly List middleback;//mxd // Constructor public VisualSidedefParts(VisualUpper u, VisualLower l, VisualMiddleDouble m, List e, List eb) @@ -40,7 +40,7 @@ namespace CodeImp.DoomBuilder.BuilderModes this.middledouble = m; this.middlesingle = null; this.middle3d = e; - this.middleback = eb;//mxd + this.middleback = eb; //mxd } // Constructor @@ -63,13 +63,11 @@ namespace CodeImp.DoomBuilder.BuilderModes if(upper != null) upper.Setup(); if(middle3d != null) { - foreach(VisualMiddle3D m in middle3d) - m.Setup(); + foreach(VisualMiddle3D m in middle3d) m.Setup(); } if(middleback != null) { - foreach(VisualMiddleBack m in middleback) - m.Setup(); + foreach(VisualMiddleBack m in middleback) m.Setup(); } } @@ -82,13 +80,11 @@ namespace CodeImp.DoomBuilder.BuilderModes if(upper != null) upper.Selected = false; if(middle3d != null) { - foreach(VisualMiddle3D m in middle3d) - m.Selected = false; + foreach(VisualMiddle3D m in middle3d) m.Selected = false; } if(middleback != null) { - foreach(VisualMiddleBack m in middleback) - m.Selected = false; + foreach(VisualMiddleBack m in middleback) m.Selected = false; } } } diff --git a/Source/Plugins/BuilderModes/VisualModes/VisualUpper.cs b/Source/Plugins/BuilderModes/VisualModes/VisualUpper.cs index 4f6074cb..ec60ba4d 100644 --- a/Source/Plugins/BuilderModes/VisualModes/VisualUpper.cs +++ b/Source/Plugins/BuilderModes/VisualModes/VisualUpper.cs @@ -51,7 +51,8 @@ namespace CodeImp.DoomBuilder.BuilderModes public VisualUpper(BaseVisualMode mode, VisualSector vs, Sidedef s) : base(mode, vs, s) { //mxd - geoType = VisualGeometryType.WALL_UPPER; + geometrytype = VisualGeometryType.WALL_UPPER; + partname = "top"; // We have no destructor GC.SuppressFinalize(this); @@ -293,69 +294,11 @@ namespace CodeImp.DoomBuilder.BuilderModes } //mxd - public override void OnChangeTargetBrightness(bool up) - { - if(!General.Map.UDMF) - { - base.OnChangeTargetBrightness(up); - return; - } - - int light = Sidedef.Fields.GetValue("light", 0); - bool absolute = Sidedef.Fields.GetValue("lightabsolute", false); - int newLight; - - if(up) - newLight = General.Map.Config.BrightnessLevels.GetNextHigher(light, absolute); - else - newLight = General.Map.Config.BrightnessLevels.GetNextLower(light, absolute); - - if(newLight == light) return; - - //create undo - mode.CreateUndo("Change upper wall brightness", UndoGroup.SurfaceBrightnessChange, Sector.Sector.FixedIndex); - Sidedef.Fields.BeforeFieldsChange(); - - //apply changes - Sidedef.Fields["light"] = new UniValue(UniversalType.Integer, newLight); - mode.SetActionResult("Changed upper wall brightness to " + newLight + "."); - Sector.Sector.UpdateCache(); - - //rebuild sector - Sector.UpdateSectorGeometry(false); - } - - //mxd - public override void OnTextureFit(bool fitWidth, bool fitHeight) + public override void OnTextureFit(FitTextureOptions options) { if(!General.Map.UDMF) return; if(!Sidedef.HighRequired() || string.IsNullOrEmpty(Sidedef.HighTexture) || Sidedef.HighTexture == "-" || !Texture.IsImageLoaded) return; - - string s; - if(fitWidth && fitHeight) s = "width and height"; - else if(fitWidth) s = "width"; - else s = "height"; - - //create undo - mode.CreateUndo("Fit texture (" + s + ")", UndoGroup.TextureOffsetChange, Sector.Sector.FixedIndex); - Sidedef.Fields.BeforeFieldsChange(); - - if(fitWidth) - { - float scaleX = Texture.ScaledWidth / Sidedef.Line.Length; - UDMFTools.SetFloat(Sidedef.Fields, "scalex_top", scaleX, 1.0f); - UDMFTools.SetFloat(Sidedef.Fields, "offsetx_top", -Sidedef.OffsetX, 0.0f); - } - - if(fitHeight && Sidedef.Sector != null && Sidedef.Other.Sector != null) - { - float scaleY = (float)Texture.Height / (Sidedef.Sector.CeilHeight - Sidedef.Other.Sector.CeilHeight); - UDMFTools.SetFloat(Sidedef.Fields, "scaley_top", scaleY, 1.0f); - - float offsetY = Tools.GetSidedefTopOffsetY(Sidedef, -Sidedef.OffsetY, scaleY, true) % Texture.Height; - UDMFTools.SetFloat(Sidedef.Fields, "offsety_top", offsetY, 0.0f); - } - + FitTexture(options); Setup(); }