From f9b559795139dc970a5bb2ad017e9d960b843901 Mon Sep 17 00:00:00 2001 From: MaxED Date: Fri, 2 Sep 2016 19:18:37 +0000 Subject: [PATCH] Fixed several cases when certain texture manipulation-related actions caused a crash when performed on not-yet-loaded textures. --- Source/Core/Geometry/Tools.cs | 28 +-- Source/Core/Map/Linedef.cs | 6 +- Source/Core/Map/Sidedef.cs | 9 +- .../VisualModes/BaseVisualGeometrySector.cs | 8 +- .../VisualModes/BaseVisualGeometrySidedef.cs | 32 ++- .../VisualModes/BaseVisualMode.cs | 183 ++++++++++++------ .../BuilderModes/VisualModes/VisualCeiling.cs | 1 + .../BuilderModes/VisualModes/VisualFloor.cs | 1 + .../BuilderModes/VisualModes/VisualLower.cs | 5 +- .../VisualModes/VisualMiddle3D.cs | 2 +- .../VisualModes/VisualMiddleDouble.cs | 5 +- .../BuilderModes/VisualModes/VisualUpper.cs | 5 +- 12 files changed, 184 insertions(+), 101 deletions(-) diff --git a/Source/Core/Geometry/Tools.cs b/Source/Core/Geometry/Tools.cs index e897a317..c18745a5 100644 --- a/Source/Core/Geometry/Tools.cs +++ b/Source/Core/Geometry/Tools.cs @@ -1588,7 +1588,7 @@ namespace CodeImp.DoomBuilder.Geometry else if(l.Front.LowRequired() && l.Front.LongLowTexture != MapSet.EmptyLongName && General.Map.Data.GetTextureExists(l.Front.LongLowTexture)) texture = General.Map.Data.GetTextureImage(l.Front.LongLowTexture); - if(texture != null) + if(texture != null && texture.IsImageLoaded) l.Front.OffsetX = (int)Math.Round((reversed ? totalLength - curLength - l.Length : curLength)) % texture.Width; } @@ -1603,7 +1603,7 @@ namespace CodeImp.DoomBuilder.Geometry else if(l.Back.LowRequired() && l.Back.LongLowTexture != MapSet.EmptyLongName && General.Map.Data.GetTextureExists(l.Back.LongLowTexture)) texture = General.Map.Data.GetTextureImage(l.Back.LongLowTexture); - if(texture != null) + if(texture != null && texture.IsImageLoaded) l.Back.OffsetX = (int)Math.Round((reversed ? totalLength - curLength - l.Length : curLength)) % texture.Width; } @@ -1623,24 +1623,24 @@ namespace CodeImp.DoomBuilder.Geometry if(l.Front.MiddleRequired() && l.Front.LongMiddleTexture != MapSet.EmptyLongName && General.Map.Data.GetTextureExists(l.Front.LongMiddleTexture)) { ImageData texture = General.Map.Data.GetTextureImage(l.Front.LongMiddleTexture); - float offset = (int)Math.Round((reversed ? totalLength - curLength - l.Length : curLength)) % texture.Width; - + float offset = (int)Math.Round((reversed ? totalLength - curLength - l.Length : curLength)); + if(texture.IsImageLoaded) offset %= texture.Width; if(offset > 0) UniFields.SetFloat(l.Front.Fields, "offsetx_mid", offset); } if(l.Front.HighRequired() && l.Front.LongHighTexture != MapSet.EmptyLongName && General.Map.Data.GetTextureExists(l.Front.LongHighTexture)) { ImageData texture = General.Map.Data.GetTextureImage(l.Front.LongHighTexture); - float offset = (int)Math.Round((reversed ? totalLength - curLength - l.Length : curLength)) % texture.Width; - + float offset = (int)Math.Round((reversed ? totalLength - curLength - l.Length : curLength)); + if(texture.IsImageLoaded) offset %= texture.Width; if(offset > 0) UniFields.SetFloat(l.Front.Fields, "offsetx_top", offset); } if(l.Front.LowRequired() && l.Front.LongLowTexture != MapSet.EmptyLongName && General.Map.Data.GetTextureExists(l.Front.LongLowTexture)) { ImageData texture = General.Map.Data.GetTextureImage(l.Front.LongLowTexture); - float offset = (int)Math.Round((reversed ? totalLength - curLength - l.Length : curLength)) % texture.Width; - + float offset = (int)Math.Round((reversed ? totalLength - curLength - l.Length : curLength)); + if(texture.IsImageLoaded) offset %= texture.Width; if(offset > 0) UniFields.SetFloat(l.Front.Fields, "offsetx_bottom", offset); } } @@ -1650,24 +1650,24 @@ namespace CodeImp.DoomBuilder.Geometry if(l.Back.MiddleRequired() && l.Back.LongMiddleTexture != MapSet.EmptyLongName && General.Map.Data.GetTextureExists(l.Back.LongMiddleTexture)) { ImageData texture = General.Map.Data.GetTextureImage(l.Back.LongMiddleTexture); - float offset = (int)Math.Round((reversed ? totalLength - curLength - l.Length : curLength)) % texture.Width; - + float offset = (int)Math.Round((reversed ? totalLength - curLength - l.Length : curLength)); + if(texture.IsImageLoaded) offset %= texture.Width; if(offset > 0) UniFields.SetFloat(l.Back.Fields, "offsetx_mid", offset); } if(l.Back.HighRequired() && l.Back.LongHighTexture != MapSet.EmptyLongName && General.Map.Data.GetTextureExists(l.Back.LongHighTexture)) { ImageData texture = General.Map.Data.GetTextureImage(l.Back.LongHighTexture); - float offset = (int)Math.Round((reversed ? totalLength - curLength - l.Length : curLength)) % texture.Width; - + float offset = (int)Math.Round((reversed ? totalLength - curLength - l.Length : curLength)); + if(texture.IsImageLoaded) offset %= texture.Width; if(offset > 0) UniFields.SetFloat(l.Back.Fields, "offsetx_top", offset); } if(l.Back.LowRequired() && l.Back.LongLowTexture != MapSet.EmptyLongName && General.Map.Data.GetTextureExists(l.Back.LongLowTexture)) { ImageData texture = General.Map.Data.GetTextureImage(l.Back.LongLowTexture); - float offset = (int)Math.Round((reversed ? totalLength - curLength - l.Length : curLength)) % texture.Width; - + float offset = (int)Math.Round((reversed ? totalLength - curLength - l.Length : curLength)); + if(texture.IsImageLoaded) offset %= texture.Width; if(offset > 0) UniFields.SetFloat(l.Back.Fields, "offsetx_bottom", offset); } } diff --git a/Source/Core/Map/Linedef.cs b/Source/Core/Map/Linedef.cs index 7925813d..7b9774f5 100644 --- a/Source/Core/Map/Linedef.cs +++ b/Source/Core/Map/Linedef.cs @@ -1378,7 +1378,8 @@ namespace CodeImp.DoomBuilder.Map texture = General.Map.Data.GetTextureImage(newline.front.LowTexture); //clamp offsetX - if(texture != null) newline.front.OffsetX %= texture.Width; + if(texture != null && texture.IsImageLoaded) + newline.front.OffsetX %= texture.Width; } if((oldline.back != null) && (newline.back != null)) @@ -1394,7 +1395,8 @@ namespace CodeImp.DoomBuilder.Map texture = General.Map.Data.GetTextureImage(newline.back.LowTexture); //clamp offsetX - if(texture != null) newline.back.OffsetX %= texture.Width; + if(texture != null && texture.IsImageLoaded) + newline.back.OffsetX %= texture.Width; } break; diff --git a/Source/Core/Map/Sidedef.cs b/Source/Core/Map/Sidedef.cs index 9664a3ae..63e07abf 100644 --- a/Source/Core/Map/Sidedef.cs +++ b/Source/Core/Map/Sidedef.cs @@ -751,7 +751,8 @@ namespace CodeImp.DoomBuilder.Map float scaleTop = Fields.GetValue("scalex_top", 1.0f); float value = Fields.GetValue("offsetx_top", 0f); - float result = (float)(Math.Round(value + offset * scaleTop) % texture.Width); + float result = (float)(Math.Round(value + offset * scaleTop)); + if(texture.IsImageLoaded) result %= texture.Width; UniFields.SetFloat(Fields, "offsetx_top", result); } @@ -762,7 +763,8 @@ namespace CodeImp.DoomBuilder.Map float scaleMid = Fields.GetValue("scalex_mid", 1.0f); float value = Fields.GetValue("offsetx_mid", 0f); - float result = (float)(Math.Round(value + offset * scaleMid) % texture.Width); + float result = (float)(Math.Round(value + offset * scaleMid)); + if(texture.IsImageLoaded) result %= texture.Width; UniFields.SetFloat(Fields, "offsetx_mid", result); } @@ -773,7 +775,8 @@ namespace CodeImp.DoomBuilder.Map float scaleLow = Fields.GetValue("scalex_bottom", 1.0f); float value = Fields.GetValue("offsetx_bottom", 0f); - float result = (float)(Math.Round(value + offset * scaleLow) % texture.Width); + float result = (float)(Math.Round(value + offset * scaleLow)); + if(texture.IsImageLoaded) result %= texture.Width; UniFields.SetFloat(Fields, "offsetx_bottom", result); } } diff --git a/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySector.cs b/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySector.cs index a03f405c..7d37882a 100644 --- a/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySector.cs +++ b/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySector.cs @@ -300,13 +300,13 @@ namespace CodeImp.DoomBuilder.BuilderModes if(alignx) { - if(Texture != null) offset.x %= Texture.Width / scaleX; + if(Texture != null && Texture.IsImageLoaded) offset.x %= Texture.Width / scaleX; UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "xpanningfloor" : "xpanningceiling"), (float)Math.Round(-offset.x), 0f); } if(aligny) { - if(Texture != null) offset.y %= Texture.Height / scaleY; + if(Texture != null && Texture.IsImageLoaded) offset.y %= Texture.Height / scaleY; UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "ypanningfloor" : "ypanningceiling"), (float)Math.Round(offset.y), 0f); } @@ -390,13 +390,13 @@ namespace CodeImp.DoomBuilder.BuilderModes if(alignx) { - if(Texture != null) offset.x %= Texture.Width / scaleX; + if(Texture != null && Texture.IsImageLoaded) offset.x %= Texture.Width / scaleX; UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "xpanningfloor" : "xpanningceiling"), (float)Math.Round(-offset.x), 0f); } if(aligny) { - if(Texture != null) offset.y %= Texture.Height / scaleY; + if(Texture != null && Texture.IsImageLoaded) offset.y %= Texture.Height / scaleY; UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "ypanningfloor" : "ypanningceiling"), (float)Math.Round(offset.y), 0f); } diff --git a/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySidedef.cs b/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySidedef.cs index 92e60c00..159f56df 100644 --- a/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySidedef.cs +++ b/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySidedef.cs @@ -640,7 +640,8 @@ namespace CodeImp.DoomBuilder.BuilderModes if(options.FitAcrossSurfaces) { scalex = Texture.ScaledWidth / (linelength * (options.GlobalBounds.Width / linelength)) * options.HorizontalRepeat; - offsetx = (float)Math.Round((options.Bounds.X * scalex - Sidedef.OffsetX - options.ControlSideOffsetX) % Texture.Width, General.Map.FormatInterface.VertexDecimals); + offsetx = (float)Math.Round((options.Bounds.X * scalex - Sidedef.OffsetX - options.ControlSideOffsetX), General.Map.FormatInterface.VertexDecimals); + if(Texture.IsImageLoaded) offsetx %= Texture.Width; } else { @@ -682,17 +683,24 @@ namespace CodeImp.DoomBuilder.BuilderModes } else { - offsety = Tools.GetSidedefOffsetY(Sidedef, geometrytype, options.Bounds.Y * scaley - Sidedef.OffsetY - options.ControlSideOffsetY, scaley, true) % Texture.Height; + offsety = Tools.GetSidedefOffsetY(Sidedef, geometrytype, options.Bounds.Y * scaley - Sidedef.OffsetY - options.ControlSideOffsetY, scaley, true); + if(Texture.IsImageLoaded) offsety %= Texture.Height; } } else { scaley = Texture.ScaledHeight / options.Bounds.Height * options.VerticalRepeat; - if(this is VisualLower) // Special cases, special cases... + // Special cases, special cases... + if(this is VisualLower) + { offsety = GetLowerOffsetY(scaley); + } else - offsety = Tools.GetSidedefOffsetY(Sidedef, geometrytype, -Sidedef.OffsetY - options.ControlSideOffsetY, scaley, true) % Texture.Height; + { + offsety = Tools.GetSidedefOffsetY(Sidedef, geometrytype, -Sidedef.OffsetY - options.ControlSideOffsetY, scaley, true); + if(Texture.IsImageLoaded) offsety %= Texture.Height; + } } UniFields.SetFloat(controlside.Fields, "scaley_" + partname, (float)Math.Round(scaley, General.Map.FormatInterface.VertexDecimals), 1.0f); @@ -710,9 +718,14 @@ namespace CodeImp.DoomBuilder.BuilderModes //mxd. Oh so special cases... private float GetLowerOffsetY(float scaley) { + float offsety; if(Sidedef.Line.IsFlagSet(General.Map.Config.LowerUnpeggedFlag)) - return ((-Sidedef.OffsetY - Sidedef.GetMiddleHeight() - Sidedef.GetHighHeight()) * scaley) % Texture.Height; - return (-Sidedef.OffsetY * scaley) % Texture.Height; + offsety = (-Sidedef.OffsetY - Sidedef.GetMiddleHeight() - Sidedef.GetHighHeight()) * scaley; + else + offsety = -Sidedef.OffsetY * scaley; + + if(Texture.IsImageLoaded) offsety %= Texture.Height; + return offsety; } #endregion @@ -1468,10 +1481,11 @@ namespace CodeImp.DoomBuilder.BuilderModes else { //mxd. Apply classic offsets + bool textureloaded = (Texture != null && Texture.IsImageLoaded); Sidedef.OffsetX = (Sidedef.OffsetX - horizontal); - if(Texture != null) Sidedef.OffsetX %= Texture.Width; + if(textureloaded) Sidedef.OffsetX %= Texture.Width; Sidedef.OffsetY = (Sidedef.OffsetY - vertical); - if(geometrytype != VisualGeometryType.WALL_MIDDLE && Texture != null) Sidedef.OffsetY %= Texture.Height; + if(geometrytype != VisualGeometryType.WALL_MIDDLE && textureloaded) Sidedef.OffsetY %= Texture.Height; mode.SetActionResult("Changed texture offsets to " + Sidedef.OffsetX + ", " + Sidedef.OffsetY + "."); @@ -1488,7 +1502,7 @@ namespace CodeImp.DoomBuilder.BuilderModes //mxd public virtual void OnChangeScale(int incrementX, int incrementY) { - if(!General.Map.UDMF || !Texture.IsImageLoaded) return; + if(!General.Map.UDMF || Texture == null || !Texture.IsImageLoaded) return; if((General.Map.UndoRedo.NextUndo == null) || (General.Map.UndoRedo.NextUndo.TicketID != undoticket)) undoticket = mode.CreateUndo("Change wall scale"); diff --git a/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs b/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs index 820178e5..0525a68a 100644 --- a/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs +++ b/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs @@ -3996,9 +3996,17 @@ namespace CodeImp.DoomBuilder.BuilderModes offset -= j.sidedef.OffsetX; if(matchtop) - j.sidedef.Fields["offsetx_top"] = new UniValue(UniversalType.Float, (float)Math.Round(offset % General.Map.Data.GetTextureImage(j.sidedef.LongHighTexture).Width, General.Map.FormatInterface.VertexDecimals)); + { + ImageData tex = General.Map.Data.GetTextureImage(j.sidedef.LongHighTexture); + int texwidth = (tex != null && tex.IsImageLoaded) ? tex.Width : 1; + j.sidedef.Fields["offsetx_top"] = new UniValue(UniversalType.Float, (float)Math.Round(offset % texwidth, General.Map.FormatInterface.VertexDecimals)); + } if(matchbottom) - j.sidedef.Fields["offsetx_bottom"] = new UniValue(UniversalType.Float, (float)Math.Round(offset % General.Map.Data.GetTextureImage(j.sidedef.LongLowTexture).Width, General.Map.FormatInterface.VertexDecimals)); + { + ImageData tex = General.Map.Data.GetTextureImage(j.sidedef.LongLowTexture); + int texwidth = (tex != null && tex.IsImageLoaded) ? tex.Width : 1; + j.sidedef.Fields["offsetx_bottom"] = new UniValue(UniversalType.Float, (float)Math.Round(offset % texwidth, General.Map.FormatInterface.VertexDecimals)); + } if(matchmid) { if(j.sidedef.Index != j.controlSide.Index) //mxd. if it's a part of 3d-floor @@ -4007,7 +4015,9 @@ namespace CodeImp.DoomBuilder.BuilderModes offset -= j.controlSide.Fields.GetValue("offsetx_mid", 0.0f); } - j.sidedef.Fields["offsetx_mid"] = new UniValue(UniversalType.Float, (float)Math.Round(offset % General.Map.Data.GetTextureImage(j.controlSide.LongMiddleTexture).Width, General.Map.FormatInterface.VertexDecimals)); + ImageData tex = General.Map.Data.GetTextureImage(j.controlSide.LongMiddleTexture); + int texwidth = (tex != null && tex.IsImageLoaded) ? tex.Width : 1; + j.sidedef.Fields["offsetx_mid"] = new UniValue(UniversalType.Float, (float)Math.Round(offset % texwidth, General.Map.FormatInterface.VertexDecimals)); } } @@ -4017,9 +4027,19 @@ namespace CodeImp.DoomBuilder.BuilderModes offset -= j.sidedef.OffsetY; //mxd if(matchtop) - j.sidedef.Fields["offsety_top"] = new UniValue(UniversalType.Float, (float)Math.Round(Tools.GetSidedefTopOffsetY(j.sidedef, offset, j.scaleY / scaley, true) % General.Map.Data.GetTextureImage(j.sidedef.LongHighTexture).Height, General.Map.FormatInterface.VertexDecimals)); //mxd + { + ImageData tex = General.Map.Data.GetTextureImage(j.sidedef.LongHighTexture); + int texheight = (tex != null && tex.IsImageLoaded) ? tex.Height : 1; + j.sidedef.Fields["offsety_top"] = new UniValue(UniversalType.Float, + (float)Math.Round(Tools.GetSidedefTopOffsetY(j.sidedef, offset, j.scaleY / scaley, true) % texheight, General.Map.FormatInterface.VertexDecimals)); //mxd + } if(matchbottom) - j.sidedef.Fields["offsety_bottom"] = new UniValue(UniversalType.Float, (float)Math.Round(Tools.GetSidedefBottomOffsetY(j.sidedef, offset, j.scaleY / scaley, true) % General.Map.Data.GetTextureImage(j.sidedef.LongLowTexture).Height, General.Map.FormatInterface.VertexDecimals)); //mxd + { + ImageData tex = General.Map.Data.GetTextureImage(j.sidedef.LongLowTexture); + int texheight = (tex != null && tex.IsImageLoaded) ? tex.Height : 1; + j.sidedef.Fields["offsety_bottom"] = new UniValue(UniversalType.Float, + (float)Math.Round(Tools.GetSidedefBottomOffsetY(j.sidedef, offset, j.scaleY / scaley, true) % texheight, General.Map.FormatInterface.VertexDecimals)); //mxd + } if(matchmid) { //mxd. Side is part of a 3D floor? @@ -4027,43 +4047,51 @@ namespace CodeImp.DoomBuilder.BuilderModes { offset -= j.controlSide.OffsetY; offset -= j.controlSide.Fields.GetValue("offsety_mid", 0.0f); - j.sidedef.Fields["offsety_mid"] = new UniValue(UniversalType.Float, (float)Math.Round(offset % General.Map.Data.GetTextureImage(j.controlSide.LongMiddleTexture).Height, General.Map.FormatInterface.VertexDecimals)); + + ImageData tex = General.Map.Data.GetTextureImage(j.controlSide.LongMiddleTexture); + int texheight = (tex != null && tex.IsImageLoaded) ? tex.Height : 1; + j.sidedef.Fields["offsety_mid"] = new UniValue(UniversalType.Float, + (float)Math.Round(offset % texheight, General.Map.FormatInterface.VertexDecimals)); } else { - ImageData midtex = General.Map.Data.GetTextureImage(j.sidedef.LongMiddleTexture); + ImageData tex = General.Map.Data.GetTextureImage(j.sidedef.LongMiddleTexture); offset = Tools.GetSidedefMiddleOffsetY(j.sidedef, offset, j.scaleY / scaley, true); - bool startisnonwrappedmidtex = (start.Sidedef.Other != null && start.GeometryType == VisualGeometryType.WALL_MIDDLE && !start.Sidedef.IsFlagSet("wrapmidtex") && !start.Sidedef.Line.IsFlagSet("wrapmidtex")); - bool cursideisnonwrappedmidtex = (j.sidedef.Other != null && !j.sidedef.IsFlagSet("wrapmidtex") && !j.sidedef.Line.IsFlagSet("wrapmidtex")); - - //mxd. Only clamp when the texture is wrapped - if(!cursideisnonwrappedmidtex) offset %= midtex.Height; - - if(!startisnonwrappedmidtex && cursideisnonwrappedmidtex) + if(tex != null && tex.IsImageLoaded) { - //mxd. This should be doublesided non-wrapped line. Find the nearset aligned position - float curoffset = UniFields.GetFloat(j.sidedef.Fields, "offsety_mid") + j.sidedef.OffsetY; - offset += midtex.Height * (float)Math.Round(curoffset / midtex.Height - 0.5f * Math.Sign(j.scaleY)); + bool startisnonwrappedmidtex = (start.Sidedef.Other != null && start.GeometryType == VisualGeometryType.WALL_MIDDLE && !start.Sidedef.IsFlagSet("wrapmidtex") && !start.Sidedef.Line.IsFlagSet("wrapmidtex")); + bool cursideisnonwrappedmidtex = (j.sidedef.Other != null && !j.sidedef.IsFlagSet("wrapmidtex") && !j.sidedef.Line.IsFlagSet("wrapmidtex")); + + //mxd. Only clamp when the texture is wrapped + if(!cursideisnonwrappedmidtex) offset %= tex.Height; - // Make sure the surface stays between floor and ceiling - if(j.sidedef.Line.IsFlagSet(General.Map.Config.LowerUnpeggedFlag) || Math.Sign(j.scaleY) == -1) + if(!startisnonwrappedmidtex && cursideisnonwrappedmidtex) { - if(offset < -midtex.Height) - offset += midtex.Height; - else if(offset > j.sidedef.GetMiddleHeight()) - offset -= midtex.Height; - } - else - { - if(offset < -(j.sidedef.GetMiddleHeight() + midtex.Height)) - offset += midtex.Height; - else if(offset > midtex.Height) - offset -= midtex.Height; + //mxd. This should be doublesided non-wrapped line. Find the nearset aligned position + float curoffset = UniFields.GetFloat(j.sidedef.Fields, "offsety_mid") + j.sidedef.OffsetY; + offset += tex.Height * (float)Math.Round(curoffset / tex.Height - 0.5f * Math.Sign(j.scaleY)); + + // Make sure the surface stays between floor and ceiling + if(j.sidedef.Line.IsFlagSet(General.Map.Config.LowerUnpeggedFlag) || Math.Sign(j.scaleY) == -1) + { + if(offset < -tex.Height) + offset += tex.Height; + else if(offset > j.sidedef.GetMiddleHeight()) + offset -= tex.Height; + } + else + { + if(offset < -(j.sidedef.GetMiddleHeight() + tex.Height)) + offset += tex.Height; + else if(offset > tex.Height) + offset -= tex.Height; + } } } - j.sidedef.Fields["offsety_mid"] = new UniValue(UniversalType.Float, (float)Math.Round(offset, General.Map.FormatInterface.VertexDecimals)); //mxd + j.sidedef.Fields["offsety_mid"] = new UniValue(UniversalType.Float, + (float)Math.Round(offset, General.Map.FormatInterface.VertexDecimals)); //mxd } } } @@ -4092,9 +4120,19 @@ namespace CodeImp.DoomBuilder.BuilderModes offset -= j.sidedef.OffsetX; if(matchtop) - j.sidedef.Fields["offsetx_top"] = new UniValue(UniversalType.Float, (float)Math.Round(offset % General.Map.Data.GetTextureImage(j.sidedef.LongHighTexture).Width, General.Map.FormatInterface.VertexDecimals)); + { + ImageData tex = General.Map.Data.GetTextureImage(j.sidedef.LongHighTexture); + int texwidth = (tex != null && tex.IsImageLoaded) ? tex.Width : 1; + j.sidedef.Fields["offsetx_top"] = new UniValue(UniversalType.Float, + (float)Math.Round(offset % texwidth, General.Map.FormatInterface.VertexDecimals)); + } if(matchbottom) - j.sidedef.Fields["offsetx_bottom"] = new UniValue(UniversalType.Float, (float)Math.Round(offset % General.Map.Data.GetTextureImage(j.sidedef.LongLowTexture).Width, General.Map.FormatInterface.VertexDecimals)); + { + ImageData tex = General.Map.Data.GetTextureImage(j.sidedef.LongLowTexture); + int texwidth = (tex != null && tex.IsImageLoaded) ? tex.Width : 1; + j.sidedef.Fields["offsetx_bottom"] = new UniValue(UniversalType.Float, + (float)Math.Round(offset % texwidth, General.Map.FormatInterface.VertexDecimals)); + } if(matchmid) { if(j.sidedef.Index != j.controlSide.Index) //mxd @@ -4103,7 +4141,10 @@ namespace CodeImp.DoomBuilder.BuilderModes offset -= j.controlSide.Fields.GetValue("offsetx_mid", 0.0f); } - j.sidedef.Fields["offsetx_mid"] = new UniValue(UniversalType.Float, (float)Math.Round(offset % General.Map.Data.GetTextureImage(j.controlSide.LongMiddleTexture).Width, General.Map.FormatInterface.VertexDecimals)); + ImageData tex = General.Map.Data.GetTextureImage(j.controlSide.LongMiddleTexture); + int texwidth = (tex != null && tex.IsImageLoaded) ? tex.Width : 1; + j.sidedef.Fields["offsetx_mid"] = new UniValue(UniversalType.Float, + (float)Math.Round(offset % texwidth, General.Map.FormatInterface.VertexDecimals)); } } @@ -4113,9 +4154,19 @@ namespace CodeImp.DoomBuilder.BuilderModes offset -= j.sidedef.OffsetY; //mxd if(matchtop) - j.sidedef.Fields["offsety_top"] = new UniValue(UniversalType.Float, (float)Math.Round(Tools.GetSidedefTopOffsetY(j.sidedef, offset, j.scaleY / scaley, true) % General.Map.Data.GetTextureImage(j.sidedef.LongHighTexture).Height, General.Map.FormatInterface.VertexDecimals)); //mxd + { + ImageData tex = General.Map.Data.GetTextureImage(j.sidedef.LongHighTexture); + int texheight = (tex != null && tex.IsImageLoaded) ? tex.Height : 1; + j.sidedef.Fields["offsety_top"] = new UniValue(UniversalType.Float, + (float)Math.Round(Tools.GetSidedefTopOffsetY(j.sidedef, offset, j.scaleY / scaley, true) % texheight, General.Map.FormatInterface.VertexDecimals)); //mxd + } if(matchbottom) - j.sidedef.Fields["offsety_bottom"] = new UniValue(UniversalType.Float, (float)Math.Round(Tools.GetSidedefBottomOffsetY(j.sidedef, offset, j.scaleY / scaley, true) % General.Map.Data.GetTextureImage(j.sidedef.LongLowTexture).Height, General.Map.FormatInterface.VertexDecimals)); //mxd + { + ImageData tex = General.Map.Data.GetTextureImage(j.sidedef.LongLowTexture); + int texheight = (tex != null && tex.IsImageLoaded) ? tex.Height : 1; + j.sidedef.Fields["offsety_bottom"] = new UniValue(UniversalType.Float, + (float)Math.Round(Tools.GetSidedefBottomOffsetY(j.sidedef, offset, j.scaleY / scaley, true) % texheight, General.Map.FormatInterface.VertexDecimals)); //mxd + } if(matchmid) { //mxd. Side is part of a 3D floor? @@ -4123,43 +4174,51 @@ namespace CodeImp.DoomBuilder.BuilderModes { offset -= j.controlSide.OffsetY; offset -= j.controlSide.Fields.GetValue("offsety_mid", 0.0f); - j.sidedef.Fields["offsety_mid"] = new UniValue(UniversalType.Float, (float)Math.Round(offset % General.Map.Data.GetTextureImage(j.controlSide.LongMiddleTexture).Height, General.Map.FormatInterface.VertexDecimals)); //mxd + + ImageData tex = General.Map.Data.GetTextureImage(j.controlSide.LongMiddleTexture); + int texheight = (tex != null && tex.IsImageLoaded) ? tex.Height : 1; + j.sidedef.Fields["offsety_mid"] = new UniValue(UniversalType.Float, + (float)Math.Round(offset % texheight, General.Map.FormatInterface.VertexDecimals)); //mxd } else { - ImageData midtex = General.Map.Data.GetTextureImage(j.sidedef.LongMiddleTexture); + ImageData tex = General.Map.Data.GetTextureImage(j.sidedef.LongMiddleTexture); offset = Tools.GetSidedefMiddleOffsetY(j.sidedef, offset, j.scaleY / scaley, true); - bool startisnonwrappedmidtex = (start.Sidedef.Other != null && start.GeometryType == VisualGeometryType.WALL_MIDDLE && !start.Sidedef.IsFlagSet("wrapmidtex") && !start.Sidedef.Line.IsFlagSet("wrapmidtex")); - bool cursideisnonwrappedmidtex = (j.sidedef.Other != null && !j.sidedef.IsFlagSet("wrapmidtex") && !j.sidedef.Line.IsFlagSet("wrapmidtex")); - - //mxd. Only clamp when the texture is wrapped - if(!cursideisnonwrappedmidtex) offset %= midtex.Height; - - if(!startisnonwrappedmidtex && cursideisnonwrappedmidtex) + if(tex != null && tex.IsImageLoaded) { - //mxd. This should be doublesided non-wrapped line. Find the nearset aligned position - float curoffset = UniFields.GetFloat(j.sidedef.Fields, "offsety_mid") + j.sidedef.OffsetY; - offset += midtex.Height * (float)Math.Round(curoffset / midtex.Height - 0.5f * Math.Sign(j.scaleY)); + bool startisnonwrappedmidtex = (start.Sidedef.Other != null && start.GeometryType == VisualGeometryType.WALL_MIDDLE && !start.Sidedef.IsFlagSet("wrapmidtex") && !start.Sidedef.Line.IsFlagSet("wrapmidtex")); + bool cursideisnonwrappedmidtex = (j.sidedef.Other != null && !j.sidedef.IsFlagSet("wrapmidtex") && !j.sidedef.Line.IsFlagSet("wrapmidtex")); + + //mxd. Only clamp when the texture is wrapped + if(!cursideisnonwrappedmidtex) offset %= tex.Height; - // Make sure the surface stays between floor and ceiling - if(j.sidedef.Line.IsFlagSet(General.Map.Config.LowerUnpeggedFlag) || Math.Sign(j.scaleY) == -1) + if(!startisnonwrappedmidtex && cursideisnonwrappedmidtex) { - if(offset < -midtex.Height) - offset += midtex.Height; - else if(offset > j.sidedef.GetMiddleHeight()) - offset -= midtex.Height; - } - else - { - if(offset < -(j.sidedef.GetMiddleHeight() + midtex.Height)) - offset += midtex.Height; - else if(offset > midtex.Height) - offset -= midtex.Height; + //mxd. This should be doublesided non-wrapped line. Find the nearset aligned position + float curoffset = UniFields.GetFloat(j.sidedef.Fields, "offsety_mid") + j.sidedef.OffsetY; + offset += tex.Height * (float)Math.Round(curoffset / tex.Height - 0.5f * Math.Sign(j.scaleY)); + + // Make sure the surface stays between floor and ceiling + if(j.sidedef.Line.IsFlagSet(General.Map.Config.LowerUnpeggedFlag) || Math.Sign(j.scaleY) == -1) + { + if(offset < -tex.Height) + offset += tex.Height; + else if(offset > j.sidedef.GetMiddleHeight()) + offset -= tex.Height; + } + else + { + if(offset < -(j.sidedef.GetMiddleHeight() + tex.Height)) + offset += tex.Height; + else if(offset > tex.Height) + offset -= tex.Height; + } } } - j.sidedef.Fields["offsety_mid"] = new UniValue(UniversalType.Float, (float)Math.Round(offset, General.Map.FormatInterface.VertexDecimals)); //mxd + j.sidedef.Fields["offsety_mid"] = new UniValue(UniversalType.Float, + (float)Math.Round(offset, General.Map.FormatInterface.VertexDecimals)); //mxd } } } diff --git a/Source/Plugins/BuilderModes/VisualModes/VisualCeiling.cs b/Source/Plugins/BuilderModes/VisualModes/VisualCeiling.cs index f7446713..8fa32612 100644 --- a/Source/Plugins/BuilderModes/VisualModes/VisualCeiling.cs +++ b/Source/Plugins/BuilderModes/VisualModes/VisualCeiling.cs @@ -265,6 +265,7 @@ namespace CodeImp.DoomBuilder.BuilderModes //mxd. Texture scale change protected override void ChangeTextureScale(int incrementX, int incrementY) { + if(Texture == null || !Texture.IsImageLoaded) return; Sector s = GetControlSector(); float scaleX = s.Fields.GetValue("xscaleceiling", 1.0f); float scaleY = s.Fields.GetValue("yscaleceiling", 1.0f); diff --git a/Source/Plugins/BuilderModes/VisualModes/VisualFloor.cs b/Source/Plugins/BuilderModes/VisualModes/VisualFloor.cs index 8d35c116..e07a4e1c 100644 --- a/Source/Plugins/BuilderModes/VisualModes/VisualFloor.cs +++ b/Source/Plugins/BuilderModes/VisualModes/VisualFloor.cs @@ -236,6 +236,7 @@ namespace CodeImp.DoomBuilder.BuilderModes //mxd. Texture scale change protected override void ChangeTextureScale(int incrementX, int incrementY) { + if(Texture == null || !Texture.IsImageLoaded) return; Sector s = GetControlSector(); float scaleX = s.Fields.GetValue("xscalefloor", 1.0f); float scaleY = s.Fields.GetValue("yscalefloor", 1.0f); diff --git a/Source/Plugins/BuilderModes/VisualModes/VisualLower.cs b/Source/Plugins/BuilderModes/VisualModes/VisualLower.cs index 3178aabc..5cbf6eb7 100644 --- a/Source/Plugins/BuilderModes/VisualModes/VisualLower.cs +++ b/Source/Plugins/BuilderModes/VisualModes/VisualLower.cs @@ -249,8 +249,9 @@ namespace CodeImp.DoomBuilder.BuilderModes float oldy = Sidedef.Fields.GetValue("offsety_bottom", 0.0f); float scalex = Sidedef.Fields.GetValue("scalex_bottom", 1.0f); float scaley = Sidedef.Fields.GetValue("scaley_bottom", 1.0f); - Sidedef.Fields["offsetx_bottom"] = new UniValue(UniversalType.Float, GetRoundedTextureOffset(oldx, xy.X, scalex, Texture != null ? Texture.Width : -1)); //mxd - Sidedef.Fields["offsety_bottom"] = new UniValue(UniversalType.Float, GetRoundedTextureOffset(oldy, xy.Y, scaley, Texture != null ? Texture.Height : -1)); //mxd + bool textureloaded = (Texture != null && Texture.IsImageLoaded); //mxd + Sidedef.Fields["offsetx_bottom"] = new UniValue(UniversalType.Float, GetRoundedTextureOffset(oldx, xy.X, scalex, textureloaded ? Texture.Width : -1)); //mxd + Sidedef.Fields["offsety_bottom"] = new UniValue(UniversalType.Float, GetRoundedTextureOffset(oldy, xy.Y, scaley, textureloaded ? Texture.Height : -1)); //mxd } protected override Point GetTextureOffset() diff --git a/Source/Plugins/BuilderModes/VisualModes/VisualMiddle3D.cs b/Source/Plugins/BuilderModes/VisualModes/VisualMiddle3D.cs index 10fb532f..3e0a45cd 100644 --- a/Source/Plugins/BuilderModes/VisualModes/VisualMiddle3D.cs +++ b/Source/Plugins/BuilderModes/VisualModes/VisualMiddle3D.cs @@ -434,7 +434,7 @@ namespace CodeImp.DoomBuilder.BuilderModes //mxd. Only control sidedef scale is used by GZDoom public override void OnChangeScale(int incrementX, int incrementY) { - if(!General.Map.UDMF || !Texture.IsImageLoaded) return; + if(!General.Map.UDMF || Texture == null || !Texture.IsImageLoaded) return; if((General.Map.UndoRedo.NextUndo == null) || (General.Map.UndoRedo.NextUndo.TicketID != undoticket)) undoticket = mode.CreateUndo("Change wall scale"); diff --git a/Source/Plugins/BuilderModes/VisualModes/VisualMiddleDouble.cs b/Source/Plugins/BuilderModes/VisualModes/VisualMiddleDouble.cs index 04e37acd..ff975f5e 100644 --- a/Source/Plugins/BuilderModes/VisualModes/VisualMiddleDouble.cs +++ b/Source/Plugins/BuilderModes/VisualModes/VisualMiddleDouble.cs @@ -348,10 +348,11 @@ namespace CodeImp.DoomBuilder.BuilderModes float oldy = Sidedef.Fields.GetValue("offsety_mid", 0.0f); float scalex = Sidedef.Fields.GetValue("scalex_mid", 1.0f); float scaley = Sidedef.Fields.GetValue("scaley_mid", 1.0f); - Sidedef.Fields["offsetx_mid"] = new UniValue(UniversalType.Float, GetRoundedTextureOffset(oldx, xy.X, scalex, Texture != null ? Texture.Width : -1)); //mxd + bool textureloaded = (Texture != null && Texture.IsImageLoaded); //mxd + Sidedef.Fields["offsetx_mid"] = new UniValue(UniversalType.Float, GetRoundedTextureOffset(oldx, xy.X, scalex, textureloaded ? Texture.Width : -1)); //mxd //mxd. Don't clamp offsetY of clipped mid textures - bool dontClamp = (Texture == null || (!Sidedef.IsFlagSet("wrapmidtex") && !Sidedef.Line.IsFlagSet("wrapmidtex"))); + bool dontClamp = (!textureloaded || (!Sidedef.IsFlagSet("wrapmidtex") && !Sidedef.Line.IsFlagSet("wrapmidtex"))); Sidedef.Fields["offsety_mid"] = new UniValue(UniversalType.Float, GetRoundedTextureOffset(oldy, xy.Y, scaley, dontClamp ? -1 : Texture.Height)); } diff --git a/Source/Plugins/BuilderModes/VisualModes/VisualUpper.cs b/Source/Plugins/BuilderModes/VisualModes/VisualUpper.cs index 205140fe..1f77944e 100644 --- a/Source/Plugins/BuilderModes/VisualModes/VisualUpper.cs +++ b/Source/Plugins/BuilderModes/VisualModes/VisualUpper.cs @@ -251,8 +251,9 @@ namespace CodeImp.DoomBuilder.BuilderModes float oldy = Sidedef.Fields.GetValue("offsety_top", 0.0f); float scalex = Sidedef.Fields.GetValue("scalex_top", 1.0f); float scaley = Sidedef.Fields.GetValue("scaley_top", 1.0f); - Sidedef.Fields["offsetx_top"] = new UniValue(UniversalType.Float, GetRoundedTextureOffset(oldx, xy.X, scalex, Texture != null ? Texture.Width : -1)); //mxd - Sidedef.Fields["offsety_top"] = new UniValue(UniversalType.Float, GetRoundedTextureOffset(oldy, xy.Y, scaley, Texture != null ? Texture.Height : -1)); //mxd + bool textureloaded = (Texture != null && Texture.IsImageLoaded); //mxd + Sidedef.Fields["offsetx_top"] = new UniValue(UniversalType.Float, GetRoundedTextureOffset(oldx, xy.X, scalex, textureloaded ? Texture.Width : -1)); //mxd + Sidedef.Fields["offsety_top"] = new UniValue(UniversalType.Float, GetRoundedTextureOffset(oldy, xy.Y, scaley, textureloaded ? Texture.Height : -1)); //mxd } protected override Point GetTextureOffset()