From 13068b1137c18aa570ddbc48c4d95697da49745b Mon Sep 17 00:00:00 2001
From: MaxED <j.maxed@gmail.com>
Date: Wed, 13 Jul 2016 21:53:48 +0000
Subject: [PATCH] Added, Visual mode: added support for ROLLCENTER sprite
 rendering flag, updated ROLLSPRITE implementation. Fixed, DECORATE support:
 the editor was unable to determine actor sprite when the actor itself had no
 sprites defined and the actor it inherited from was only defined in the game
 configuration. Fixed, Drag geometry modes: linedefs without both sides were
 removed after dragging them when "Replace with Dragged Geometry" mode was
 active. Updated ZDoom_DECORATE.cfg.

---
 Build/Scripting/ZDoom_DECORATE.cfg            |  6 ++
 Source/Core/Config/ThingTypeInfo.cs           | 12 ++-
 Source/Core/Map/MapSet.cs                     | 46 +++++-----
 Source/Core/VisualModes/VisualThing.cs        | 83 ++++++++++++++++---
 Source/Core/ZDoom/ActorStructure.cs           | 66 ++++-----------
 .../VisualModes/BaseVisualThing.cs            | 39 +++++----
 6 files changed, 145 insertions(+), 107 deletions(-)

diff --git a/Build/Scripting/ZDoom_DECORATE.cfg b/Build/Scripting/ZDoom_DECORATE.cfg
index afc4c4428..76c793570 100644
--- a/Build/Scripting/ZDoom_DECORATE.cfg
+++ b/Build/Scripting/ZDoom_DECORATE.cfg
@@ -747,6 +747,12 @@ properties
 
 constants
 {
+//rendering
+	FLATSPRITE;
+	ROLLSPRITE;
+	WALLSPRITE;
+	DONTFLIP;
+	ROLLCENTER;
 //pointers
 	AAPTR_DEFAULT;
 	AAPTR_NULL;
diff --git a/Source/Core/Config/ThingTypeInfo.cs b/Source/Core/Config/ThingTypeInfo.cs
index 6bba25ad2..d9ab5a397 100644
--- a/Source/Core/Config/ThingTypeInfo.cs
+++ b/Source/Core/Config/ThingTypeInfo.cs
@@ -89,6 +89,7 @@ namespace CodeImp.DoomBuilder.Config
 		//mxd. GZDoom rendering properties
 		private ThingRenderMode rendermode;
 		private bool rollsprite;
+		private bool rollcenter;
 		private bool dontflip;
 		
 		#endregion
@@ -129,6 +130,7 @@ namespace CodeImp.DoomBuilder.Config
 		//mxd. GZDoom rendering properties
 		public ThingRenderMode RenderMode { get { return rendermode; } }
 		public bool RollSprite { get { return rollsprite; } }
+		public bool RollCenter { get { return rollcenter; } }
 		public bool DontFlip { get { return dontflip; } }
 
 		#endregion
@@ -396,6 +398,7 @@ namespace CodeImp.DoomBuilder.Config
 			this.rendermode = other.rendermode;
 			this.dontflip = other.dontflip;
 			this.rollsprite = other.rollsprite;
+			this.rollcenter = other.rollcenter;
 
 			// We have no destructor
 			GC.SuppressFinalize(this);
@@ -460,13 +463,13 @@ namespace CodeImp.DoomBuilder.Config
 			
 			// Set sprite
 			StateStructure.FrameInfo info = actor.FindSuitableSprite(); //mxd
-			if(!locksprite && !string.IsNullOrEmpty(info.Sprite)) //mxd. Added locksprite property
+			if(!locksprite && info != null) //mxd. Added locksprite property
 				sprite = info.Sprite;
 			else if(string.IsNullOrEmpty(sprite))//mxd
 				sprite = DataManager.INTERNAL_PREFIX + "unknownthing";
 
 			//mxd. Store dynamic light name
-			lightname = info.LightName;
+			lightname = (info != null ? info.LightName : string.Empty);
 
 			//mxd. Create sprite frame
 			this.spriteframe = new[] { new SpriteFrameInfo { Sprite = sprite, SpriteLongName = Lump.MakeLongName(sprite, true) } };
@@ -514,7 +517,7 @@ namespace CodeImp.DoomBuilder.Config
 			}
 
 			//mxd. BRIGHT
-			this.bright = info.Bright || actor.GetFlagValue("bright", false);
+			this.bright = (info != null && info.Bright) || actor.GetFlagValue("bright", false);
 			
 			// Safety
 			if(this.radius < 4f || this.fixedsize) this.radius = THING_FIXED_SIZE;
@@ -528,7 +531,8 @@ namespace CodeImp.DoomBuilder.Config
 			xybillboard = actor.GetFlagValue("forcexybillboard", false); //mxd
 
 			//mxd. GZDoom rendering flags
-			rollsprite = actor.GetFlagValue("rollsprite", false); 
+			rollsprite = actor.GetFlagValue("rollsprite", false);
+			if(rollsprite) rollcenter = actor.GetFlagValue("rollcenter", false);
 			if(actor.GetFlagValue("wallsprite", false)) rendermode = ThingRenderMode.WALLSPRITE;
 			if(actor.GetFlagValue("flatsprite", false))
 			{
diff --git a/Source/Core/Map/MapSet.cs b/Source/Core/Map/MapSet.cs
index f37f997bb..8b7780add 100644
--- a/Source/Core/Map/MapSet.cs
+++ b/Source/Core/Map/MapSet.cs
@@ -3079,40 +3079,34 @@ namespace CodeImp.DoomBuilder.Map
 				foreach(Linedef l in alllines)
 				{
 					// Remove line when it's start, center and end are inside a changed sector and neither side references it
-					if(l.Start != null && l.End != null)
+					if(l.Start != null && l.End != null 
+						&& (l.Front == null || !changedsectors.Contains(l.Front.Sector)) 
+						&& (l.Back == null || !changedsectors.Contains(l.Back.Sector)))
 					{
-						if(l.Front == null && l.Back == null)
-						{
-							l.Dispose();
-						}
-						else if((l.Front == null || !changedsectors.Contains(l.Front.Sector)) &&
-								(l.Back == null || !changedsectors.Contains(l.Back.Sector)))
+						foreach(Sector s in changedsectors)
 						{
-							foreach(Sector s in changedsectors)
+							if(s.Intersect(l.Start.Position) && s.Intersect(l.End.Position) && s.Intersect(l.GetCenterPoint()))
 							{
-								if(s.Intersect(l.Start.Position) && s.Intersect(l.End.Position) && s.Intersect(l.GetCenterPoint()))
-								{
-									Vertex[] tocheck = { l.Start, l.End };
-									l.Dispose();
+								Vertex[] tocheck = { l.Start, l.End };
+								l.Dispose();
 
-									foreach(Vertex v in tocheck)
+								foreach(Vertex v in tocheck)
+								{
+									// If the newly created vertex only has 2 linedefs attached, then merge the linedefs
+									if(!v.IsDisposed && v.Linedefs.Count == 2 && splitverts.Contains(v))
 									{
-										// If the newly created vertex only has 2 linedefs attached, then merge the linedefs
-										if(!v.IsDisposed && v.Linedefs.Count == 2 && splitverts.Contains(v))
-										{
-											Linedef ld1 = General.GetByIndex(v.Linedefs, 0);
-											Linedef ld2 = General.GetByIndex(v.Linedefs, 1);
-											Vertex v2 = (ld2.Start == v) ? ld2.End : ld2.Start;
-											if(ld1.Start == v) ld1.SetStartVertex(v2); else ld1.SetEndVertex(v2);
-											ld2.Dispose();
+										Linedef ld1 = General.GetByIndex(v.Linedefs, 0);
+										Linedef ld2 = General.GetByIndex(v.Linedefs, 1);
+										Vertex v2 = (ld2.Start == v) ? ld2.End : ld2.Start;
+										if(ld1.Start == v) ld1.SetStartVertex(v2); else ld1.SetEndVertex(v2);
+										ld2.Dispose();
 
-											// Trash vertex
-											v.Dispose();
-										}
+										// Trash vertex
+										v.Dispose();
 									}
-
-									break;
 								}
+
+								break;
 							}
 						}
 					}
diff --git a/Source/Core/VisualModes/VisualThing.cs b/Source/Core/VisualModes/VisualThing.cs
index 6c54b6f47..a7f1c0458 100644
--- a/Source/Core/VisualModes/VisualThing.cs
+++ b/Source/Core/VisualModes/VisualThing.cs
@@ -265,7 +265,7 @@ namespace CodeImp.DoomBuilder.VisualModes
 		}
 
 		// This sets the vertices for the thing sprite
-		protected void SetVertices(WorldVertex[][] verts/*, Plane floor, Plane ceiling*/)
+		protected void SetVertices(WorldVertex[][] verts, Vector2D[] offsets/*, Plane floor, Plane ceiling*/)
 		{
 			// Copy vertices
 			vertices = new WorldVertex[verts.Length][];
@@ -285,8 +285,23 @@ namespace CodeImp.DoomBuilder.VisualModes
 			for(int c = 0; c < vertices.Length; c++)
 			{
 				if(triangles[c] < 2) continue;
-				float localcenterz = vertices[c][1].z * 0.5f;
+
 				Matrix transform, rotation;
+				float centerx, centerz;
+
+				// ROLLCENTER flag support
+				if(info.RollSprite && info.RollCenter && thing.Roll != 0)
+				{
+					// Rotate around sprite center
+					centerx = offsets[c].x;
+					centerz = vertices[c][1].z * 0.5f - offsets[c].y;
+				}
+				else
+				{
+					// Sprite center is already where it needs to be
+					centerx = 0f;
+					centerz = 0f;
+				}
 
 				switch(thing.RenderMode)
 				{
@@ -296,9 +311,35 @@ namespace CodeImp.DoomBuilder.VisualModes
 					
 					// Actor becomes a flat sprite which can be tilted with the use of the Pitch actor property.
 					case ThingRenderMode.FLATSPRITE:
-						rotation = (info.RollSprite ? Matrix.RotationY(-thing.RollRad) * Matrix.RotationX(thing.PitchRad) : Matrix.RotationX(thing.PitchRad))
-							* Matrix.RotationZ(thing.Angle);
-						transform = Matrix.Translation(0f, 0f, -localcenterz) * rotation * Matrix.Translation(0f, 0f, localcenterz);
+						transform = Matrix.Identity;
+
+						// Apply roll
+						if(info.RollSprite && thing.Roll != 0)
+						{
+							if(info.RollCenter)
+							{
+								rotation = Matrix.RotationY(-thing.RollRad);
+								transform = Matrix.Translation(-centerx, -centerx, -centerz) * rotation * Matrix.Translation(centerx, centerx, centerz);
+							}
+							else
+							{
+								// Sprite center is already where it needs to be
+								transform = Matrix.RotationY(-thing.RollRad);
+							}
+						}
+
+						// Pitch should be performed from the center of the sprite regardless of ROLLCENTER flag...
+						if(thing.Pitch != 0)
+						{
+							float localcenterz = vertices[c][1].z * 0.5f;
+							rotation = Matrix.RotationX(-thing.PitchRad);
+							transform *= Matrix.Translation(0f, 0f, -localcenterz) * rotation * Matrix.Translation(0f, 0f, localcenterz);
+						}
+
+						// Add thing angle into the mix
+						transform *= Matrix.RotationZ(thing.Angle);
+
+						// Apply transform
 						for(int i = 0; i < vertices[c].Length; i++)
 						{
 							Vector4 transformed = Vector3.Transform(new Vector3(vertices[c][i].x, vertices[c][i].y, vertices[c][i].z), transform);
@@ -310,8 +351,21 @@ namespace CodeImp.DoomBuilder.VisualModes
 
 					// Similar to FLATSPRITE but is not affected by pitch.
 					case ThingRenderMode.WALLSPRITE:
-						rotation = (info.RollSprite ? Matrix.RotationY(-thing.RollRad) * Matrix.RotationZ(thing.Angle) : Matrix.RotationZ(thing.Angle));
-						transform = Matrix.Translation(0f, 0f, -localcenterz) * rotation * Matrix.Translation(0f, 0f, localcenterz);
+						// Apply sprite roll?
+						if(info.RollSprite && thing.Roll != 0)
+						{
+							rotation = Matrix.RotationY(-thing.RollRad) * Matrix.RotationZ(thing.Angle);
+							if(info.RollCenter)
+								transform = Matrix.Translation(-centerx, -centerx, -centerz) * rotation * Matrix.Translation(centerx, centerx, centerz);
+							else
+								transform = rotation; // Sprite center is already where it needs to be
+						}
+						else
+						{
+							transform = Matrix.RotationZ(thing.Angle);
+						}
+
+						// Apply transform
 						for(int i = 0; i < vertices[c].Length; i++)
 						{
 							Vector4 transformed = Vector3.Transform(new Vector3(vertices[c][i].x, vertices[c][i].y, vertices[c][i].z), transform);
@@ -321,7 +375,7 @@ namespace CodeImp.DoomBuilder.VisualModes
 						}
 						break;
 
-					// Some old GLOOME stuff
+					#region Some old GLOOME FLOOR_SPRITE/CEILING_SPRITE support code
 					/*case Thing.SpriteRenderMode.FLOOR_SPRITE:
 						Matrix floorrotation = Matrix.RotationZ(info.RollSprite ? Thing.RollRad : 0f)
 											 * Matrix.RotationY(Thing.Angle)
@@ -407,11 +461,18 @@ namespace CodeImp.DoomBuilder.VisualModes
 							}
 						}
 						break;*/
+					#endregion
 
 					case ThingRenderMode.NORMAL:
-						if(info.RollSprite)
+						if(info.RollSprite && thing.Roll != 0)
 						{
-							transform = Matrix.Translation(0f, 0f, -localcenterz) * Matrix.RotationY(-thing.RollRad) * Matrix.Translation(0f, 0f, localcenterz);
+							rotation = Matrix.RotationY(-thing.RollRad);
+							if(info.RollCenter)
+								transform = Matrix.Translation(-centerx, -centerx, -centerz) * rotation * Matrix.Translation(centerx, centerx, centerz);
+							else
+								transform = rotation; // Sprite center is already where it needs to be
+							
+							// Apply transform
 							for(int i = 0; i < vertices[c].Length; i++)
 							{
 								Vector4 transformed = Vector3.Transform(new Vector3(vertices[c][i].x, vertices[c][i].y, vertices[c][i].z), transform);
@@ -515,7 +576,7 @@ namespace CodeImp.DoomBuilder.VisualModes
 				if(Thing.IsDirectional)
 				{
 					Matrix transform = Matrix.Scaling(thing.Size, thing.Size, thing.Size)
-						* (Matrix.RotationY(-Thing.RollRad) * Matrix.RotationX(Thing.PitchRad) * Matrix.RotationZ(Thing.Angle))
+						* (Matrix.RotationY(-Thing.RollRad) * Matrix.RotationX(-Thing.PitchRad) * Matrix.RotationZ(Thing.Angle))
 						* (sizeless ? position : position * Matrix.Translation(0.0f, 0.0f, thingheight / 2f));
 
 					WorldVertex a0 = new WorldVertex(Vector3D.Transform(0.0f, 0.0f, 0.0f, transform)); //start
diff --git a/Source/Core/ZDoom/ActorStructure.cs b/Source/Core/ZDoom/ActorStructure.cs
index e53f19e0d..81e6537b9 100644
--- a/Source/Core/ZDoom/ActorStructure.cs
+++ b/Source/Core/ZDoom/ActorStructure.cs
@@ -31,7 +31,7 @@ namespace CodeImp.DoomBuilder.ZDoom
 	{
 		#region ================== Constants
 		
-		//private readonly string[] SPRITE_POSTFIXES = new[] {"2C8", "2D8", "2A8", "2B8", "1C1", "1D1", "1A1", "1B1", "A2", "A1", "A0", "2", "1", "0" };
+		private readonly string[] SPRITE_CHECK_STATES = { "idle", "see", "inactive", "spawn" }; //mxd
 		internal const string ACTOR_CLASS_SPECIAL_TOKENS = ":{}\n;,"; //mxd
 
 		#endregion
@@ -476,7 +476,7 @@ namespace CodeImp.DoomBuilder.ZDoom
 					{
 						//states
 						if(states.Count == 0 && !string.IsNullOrEmpty(ti.Value.Sprite))
-							states.Add("spawn", new StateStructure(ti.Value.Sprite.Substring(0, 4)));
+							states.Add("spawn", new StateStructure(ti.Value.Sprite.Substring(0, 5)));
 
 						//flags
 						if(ti.Value.Hangs && !flags.ContainsKey("spawnceiling"))
@@ -668,8 +668,7 @@ namespace CodeImp.DoomBuilder.ZDoom
 		/// </summary>
 		public StateStructure.FrameInfo FindSuitableSprite()
 		{
-			StateStructure.FrameInfo result = new StateStructure.FrameInfo(); //mxd
-			
+			// Info: actual sprites are resolved in ThingTypeInfo.SetupSpriteFrame() - mxd
 			// Sprite forced?
 			if(HasPropertyWithValue("$sprite"))
 			{
@@ -677,65 +676,32 @@ namespace CodeImp.DoomBuilder.ZDoom
 
 				//mxd. Valid when internal or exists
 				if(sprite.StartsWith(DataManager.INTERNAL_PREFIX, StringComparison.OrdinalIgnoreCase) || General.Map.Data.GetSpriteExists(sprite))
-				{
-					result.Sprite = sprite;
-					return result;
-				}
+					return new StateStructure.FrameInfo { Sprite = sprite };
 
 				//mxd. Bitch and moan
 				General.ErrorLogger.Add(ErrorType.Warning, "DECORATE warning in " + classname + ":" + doomednum + ". The sprite \"" + sprite + "\" assigned by the \"$sprite\" property does not exist.");
 			}
 
-			// Try the idle state
-			if(HasState("idle"))
-			{
-				StateStructure s = GetState("idle");
-				StateStructure.FrameInfo info = s.GetSprite(0);
-				if(!string.IsNullOrEmpty(info.Sprite)) result = info;
-			}
-			
-			// Try the see state
-			if(string.IsNullOrEmpty(result.Sprite) && HasState("see"))
-			{
-				StateStructure s = GetState("see");
-				StateStructure.FrameInfo info = s.GetSprite(0);
-				if(!string.IsNullOrEmpty(info.Sprite)) result = info;
-			}
-			
-			// Try the inactive state
-			if(string.IsNullOrEmpty(result.Sprite) && HasState("inactive"))
+			//mxd. Try to get a suitable sprite from our hardcoded states list
+			foreach(string state in SPRITE_CHECK_STATES)
 			{
-				StateStructure s = GetState("inactive");
-				StateStructure.FrameInfo info = s.GetSprite(0);
-				if(!string.IsNullOrEmpty(info.Sprite)) result = info;
-			}
-			
-			// Try the spawn state
-			if(string.IsNullOrEmpty(result.Sprite) && HasState("spawn"))
-			{
-				StateStructure s = GetState("spawn");
+				if(!HasState(state)) continue;
+
+				StateStructure s = GetState(state);
 				StateStructure.FrameInfo info = s.GetSprite(0);
-				if(!string.IsNullOrEmpty(info.Sprite)) result = info;
+				if(!string.IsNullOrEmpty(info.Sprite)) return info;
 			}
 			
 			// Still no sprite found? then just pick the first we can find
-			if(string.IsNullOrEmpty(result.Sprite))
+			Dictionary<string, StateStructure> list = GetAllStates();
+			foreach(StateStructure s in list.Values)
 			{
-				Dictionary<string, StateStructure> list = GetAllStates();
-				foreach(StateStructure s in list.Values)
-				{
-					StateStructure.FrameInfo info = s.GetSprite(0);
-					if(!string.IsNullOrEmpty(info.Sprite))
-					{
-						result = info;
-						break;
-					}
-				}
+				StateStructure.FrameInfo info = s.GetSprite(0);
+				if(!string.IsNullOrEmpty(info.Sprite)) return info;
 			}
 			
-			//mxd. We've found something. Or not...
-			//Info: actual sprites are resolved in ThingTypeInfo.SetupSpriteFrame()
-			return result;
+			//mxd. No dice...
+			return null;
 		}
 		
 		#endregion
diff --git a/Source/Plugins/BuilderModes/VisualModes/BaseVisualThing.cs b/Source/Plugins/BuilderModes/VisualModes/BaseVisualThing.cs
index 9217b07fe..bc4aed30f 100644
--- a/Source/Plugins/BuilderModes/VisualModes/BaseVisualThing.cs
+++ b/Source/Plugins/BuilderModes/VisualModes/BaseVisualThing.cs
@@ -275,19 +275,19 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 			//mxd. Create verts for all sprite angles
 			WorldVertex[][] allverts = new WorldVertex[info.SpriteFrame.Length][];
+			Vector2D[] alloffsets = new Vector2D[info.SpriteFrame.Length];
 			base.textures = new ImageData[info.SpriteFrame.Length];
 			isloaded = true;
 
 			for(int i = 0; i < sprites.Length; i++)
 			{
+				Vector2D offsets = new Vector2D();
+
 				// Check if the texture is loaded
 				ImageData sprite = sprites[i];
 				sprite.LoadImage();
 				if(sprite.IsImageLoaded)
 				{
-					float offsetx = 0.0f;
-					float offsety = 0.0f;
-
 					base.textures[i] = sprite;
 
 					// Determine sprite size and offset
@@ -296,16 +296,16 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					ISpriteImage spriteimg = sprite as ISpriteImage;
 					if(spriteimg != null)
 					{
-						offsetx = radius - spriteimg.OffsetX;
-						offsety = spriteimg.OffsetY - height;
+						offsets.x = radius - spriteimg.OffsetX;
+						offsets.y = spriteimg.OffsetY - height;
 					}
 
 					// Scale by thing type/actor scale
 					// We do this after the offset x/y determination above, because that is entirely in sprite pixels space
 					radius *= info.SpriteScale.Width;
 					height *= info.SpriteScale.Height;
-					offsetx *= info.SpriteScale.Width;
-					offsety *= info.SpriteScale.Height;
+					offsets.x *= info.SpriteScale.Width;
+					offsets.y *= info.SpriteScale.Height;
 
 					// Make vertices
 					WorldVertex[] verts = new WorldVertex[6];
@@ -317,21 +317,21 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					if(sizeless) //mxd
 					{ 
 						float hh = height / 2;
-						verts[0] = new WorldVertex(-radius + offsetx, 0.0f, offsety - hh, sectorcolor, ul, 1.0f);
-						verts[1] = new WorldVertex(-radius + offsetx, 0.0f, hh + offsety, sectorcolor, ul, 0.0f);
-						verts[2] = new WorldVertex(+radius + offsetx, 0.0f, hh + offsety, sectorcolor, ur, 0.0f);
+						verts[0] = new WorldVertex(-radius + offsets.x, 0.0f, offsets.y - hh, sectorcolor, ul, 1.0f);
+						verts[1] = new WorldVertex(-radius + offsets.x, 0.0f, hh + offsets.y, sectorcolor, ul, 0.0f);
+						verts[2] = new WorldVertex(+radius + offsets.x, 0.0f, hh + offsets.y, sectorcolor, ur, 0.0f);
 						verts[3] = verts[0];
 						verts[4] = verts[2];
-						verts[5] = new WorldVertex(+radius + offsetx, 0.0f, offsety - hh, sectorcolor, ur, 1.0f);
+						verts[5] = new WorldVertex(+radius + offsets.x, 0.0f, offsets.y - hh, sectorcolor, ur, 1.0f);
 					} 
 					else 
 					{
-						verts[0] = new WorldVertex(-radius + offsetx, 0.0f, offsety, sectorcolor, ul, 1.0f);
-						verts[1] = new WorldVertex(-radius + offsetx, 0.0f, height + offsety, sectorcolor, ul, 0.0f);
-						verts[2] = new WorldVertex(+radius + offsetx, 0.0f, height + offsety, sectorcolor, ur, 0.0f);
+						verts[0] = new WorldVertex(-radius + offsets.x, 0.0f, offsets.y, sectorcolor, ul, 1.0f);
+						verts[1] = new WorldVertex(-radius + offsets.x, 0.0f, height + offsets.y, sectorcolor, ul, 0.0f);
+						verts[2] = new WorldVertex(+radius + offsets.x, 0.0f, height + offsets.y, sectorcolor, ur, 0.0f);
 						verts[3] = verts[0];
 						verts[4] = verts[2];
-						verts[5] = new WorldVertex(+radius + offsetx, 0.0f, offsety, sectorcolor, ur, 1.0f);
+						verts[5] = new WorldVertex(+radius + offsets.x, 0.0f, offsets.y, sectorcolor, ur, 1.0f);
 					}
 					allverts[i] = verts;
 				}
@@ -344,6 +344,10 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					float radius = Math.Min(thingradius, thingheight / 2f);
 					float height = Math.Min(thingradius * 2f, thingheight);
 
+					//mxd. Determine sprite offsets
+					offsets.x = radius;
+					offsets.y = height / 2;
+
 					// Make vertices
 					WorldVertex[] verts = new WorldVertex[6];
 					verts[0] = new WorldVertex(-radius, 0.0f, 0.0f, sectorcolor, 0.0f, 1.0f);
@@ -354,10 +358,13 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					verts[5] = new WorldVertex(+radius, 0.0f, 0.0f, sectorcolor, 1.0f, 1.0f);
 					allverts[i] = verts;
 				}
+
+				//mxd. Store offsets
+				alloffsets[i] = offsets;
 			}
 
 			//mxd
-			SetVertices(allverts/*, floor, ceiling*/);
+			SetVertices(allverts, alloffsets/*, floor, ceiling*/);
 			
 			// Determine position
 			Vector3D pos = Thing.Position;
-- 
GitLab