From c3392f83999959fae31a09de1c045391d4601d5a Mon Sep 17 00:00:00 2001 From: MaxED Date: Mon, 11 Apr 2016 23:05:16 +0000 Subject: [PATCH] Added, Visual mode: thing sprites are now angle-dependent. --- Source/Core/Controls/DebugConsole.cs | 33 +- Source/Core/Rendering/Renderer3D.cs | 42 ++- Source/Core/VisualModes/VisualThing.cs | 305 ++++++++++-------- .../VisualModes/BaseVisualThing.cs | 210 ++++++------ 4 files changed, 325 insertions(+), 265 deletions(-) diff --git a/Source/Core/Controls/DebugConsole.cs b/Source/Core/Controls/DebugConsole.cs index 6ef52a65..37594c0a 100644 --- a/Source/Core/Controls/DebugConsole.cs +++ b/Source/Core/Controls/DebugConsole.cs @@ -95,21 +95,16 @@ namespace CodeImp.DoomBuilder #region ================== Methods - public static void Write(string text) - { - Write(DebugMessageType.INFO, text); - } - - public static void WriteLine(string text) - { - Write(DebugMessageType.INFO, text + Environment.NewLine); - } - - public static void Write(DebugMessageType type, string text) + public static void SetText(string text) { Write(DebugMessageType.INFO, text, false); } // Useful to display frequently updated text without flickering + public static void WriteLine(string text) { Write(DebugMessageType.INFO, text + Environment.NewLine, true); } + public static void WriteLine(DebugMessageType type, string text) { Write(type, text + Environment.NewLine, true); } + public static void Write(string text) { Write(DebugMessageType.INFO, text, true); } + public static void Write(DebugMessageType type, string text) { Write(type, text, true); } + public static void Write(DebugMessageType type, string text, bool append) { if(me != null && me.InvokeRequired) { - me.Invoke(new Action(Write), new object[] { type, text }); + me.Invoke(new Action(Write), new object[] { type, text, append }); } else { @@ -117,16 +112,11 @@ namespace CodeImp.DoomBuilder messages.Add(new KeyValuePair(type, text)); if(me != null && (me.filters & type) == type) { - me.AddMessage(type, text, true); + me.AddMessage(type, text, true, append); } } } - public static void WriteLine(DebugMessageType type, string text) - { - Write(type, text + Environment.NewLine); - } - public static void Clear() { if(me != null && me.InvokeRequired) @@ -226,12 +216,13 @@ namespace CodeImp.DoomBuilder #endif } - private void AddMessage(DebugMessageType type, string text, bool scroll) + private void AddMessage(DebugMessageType type, string text, bool scroll, bool append) { text = textheaders[type] + text; console.SelectionStart = console.TextLength; console.SelectionColor = textcolors[type]; - console.AppendText(text); + if(append) console.AppendText(text); + else console.Text = text; if(scroll && autoscroll.Checked) console.ScrollToCaret(); } @@ -257,7 +248,7 @@ namespace CodeImp.DoomBuilder { if((filters & pair.Key) == pair.Key && CheckTextFilter(pair.Value, searchbox.Text)) { - AddMessage(pair.Key, pair.Value, false); + AddMessage(pair.Key, pair.Value, false, true); } } diff --git a/Source/Core/Rendering/Renderer3D.cs b/Source/Core/Rendering/Renderer3D.cs index f77d339a..7c6dd991 100644 --- a/Source/Core/Rendering/Renderer3D.cs +++ b/Source/Core/Rendering/Renderer3D.cs @@ -1107,6 +1107,7 @@ namespace CodeImp.DoomBuilder.Rendering // Render things collected foreach(VisualThing t in thingspass) { + t.UpdateSpriteFrame(); // Set correct texture, geobuffer and triangles count if(t.Texture is UnknownImage) continue; // Change blend mode? @@ -1720,28 +1721,35 @@ namespace CodeImp.DoomBuilder.Rendering } } // Gather regular things - else if(t.Texture != null) //Must have a texture! + else { - //mxd - switch(t.RenderPass) + //mxd. Set correct texture, geobuffer and triangles count + t.UpdateSpriteFrame(); + + //Must have a texture! + if(t.Texture != null) { - case RenderPass.Solid: - if(!solidthings.ContainsKey(t.Texture)) solidthings.Add(t.Texture, new List()); - solidthings[t.Texture].Add(t); - break; + //mxd + switch(t.RenderPass) + { + case RenderPass.Solid: + if(!solidthings.ContainsKey(t.Texture)) solidthings.Add(t.Texture, new List()); + solidthings[t.Texture].Add(t); + break; - case RenderPass.Mask: - if(!maskedthings.ContainsKey(t.Texture)) maskedthings.Add(t.Texture, new List()); - maskedthings[t.Texture].Add(t); - break; + case RenderPass.Mask: + if(!maskedthings.ContainsKey(t.Texture)) maskedthings.Add(t.Texture, new List()); + maskedthings[t.Texture].Add(t); + break; - case RenderPass.Additive: - case RenderPass.Alpha: - translucentthings.Add(t); - break; + case RenderPass.Additive: + case RenderPass.Alpha: + translucentthings.Add(t); + break; - default: - throw new NotImplementedException("Thing rendering of " + t.RenderPass + " render pass is not implemented!"); + default: + throw new NotImplementedException("Thing rendering of " + t.RenderPass + " render pass is not implemented!"); + } } } diff --git a/Source/Core/VisualModes/VisualThing.cs b/Source/Core/VisualModes/VisualThing.cs index 3434a5c9..faf98b83 100644 --- a/Source/Core/VisualModes/VisualThing.cs +++ b/Source/Core/VisualModes/VisualThing.cs @@ -48,17 +48,18 @@ namespace CodeImp.DoomBuilder.VisualModes //mxd. Info protected ThingTypeInfo info; - // Texture - private ImageData texture; + // Textures + protected ImageData[] textures; // Geometry - private WorldVertex[] vertices; - private VertexBuffer geobuffer; + private WorldVertex[][] vertices; + private VertexBuffer[] geobuffers; private VertexBuffer cagebuffer; //mxd private int cagelength; //mxd private bool updategeo; private bool updatecage; //mxd - private int triangles; + private int[] triangles; + private int spriteframe; //mxd // Rendering private RenderPass renderpass; @@ -97,17 +98,17 @@ namespace CodeImp.DoomBuilder.VisualModes #region ================== Properties - internal VertexBuffer GeometryBuffer { get { return geobuffer; } } + internal VertexBuffer GeometryBuffer { get { return geobuffers[spriteframe]; } } internal VertexBuffer CageBuffer { get { return cagebuffer; } } //mxd internal int CageLength { get { return cagelength; } } //mxd internal bool NeedsUpdateGeo { get { return updategeo; } } - internal int Triangles { get { return triangles; } } + internal int Triangles { get { return triangles[spriteframe]; } } internal Matrix Position { get { return position; } } internal Color4 CageColor { get { return cagecolor; } } public ThingTypeInfo Info { get { return info; } } //mxd //mxd - internal int VertexColor { get { return vertices.Length > 0 ? vertices[0].c : 0;} } + internal int VertexColor { get { return vertices.Length > 0 && vertices[0].Length > 0 ? vertices[0][0].c : 0; } } public int CameraDistance { get { return cameradistance; } } public float FogFactor { get { return fogfactor; } } public Vector3 Center @@ -142,7 +143,7 @@ namespace CodeImp.DoomBuilder.VisualModes /// /// Image to use as texture on the geometry. /// - public ImageData Texture { get { return texture; } set { texture = value; } } + public ImageData Texture { get { return textures[spriteframe]; } } /// /// Disposed or not? @@ -186,8 +187,12 @@ namespace CodeImp.DoomBuilder.VisualModes if(!isdisposed) { // Clean up - if(geobuffer != null) geobuffer.Dispose(); - geobuffer = null; + if(geobuffers != null) //mxd + { + foreach(VertexBuffer buffer in geobuffers) buffer.Dispose(); + geobuffers = null; + } + if(cagebuffer != null) cagebuffer.Dispose(); //mxd cagebuffer = null; //mxd @@ -213,8 +218,18 @@ namespace CodeImp.DoomBuilder.VisualModes public void UnloadResource() { // Trash geometry buffers - if(geobuffer != null) geobuffer.Dispose(); - geobuffer = null; + if(geobuffers != null) //mxd + { + foreach(VertexBuffer buffer in geobuffers) buffer.Dispose(); + geobuffers = null; + } + + if(textures != null) //mxd + { + foreach(ImageData texture in textures) texture.Dispose(); + textures = null; + } + if(cagebuffer != null) cagebuffer.Dispose(); //mxd cagebuffer = null; //mxd updategeo = true; @@ -256,132 +271,143 @@ namespace CodeImp.DoomBuilder.VisualModes } // This sets the vertices for the thing sprite - protected void SetVertices(ICollection verts, Plane floor, Plane ceiling) + protected void SetVertices(WorldVertex[][] verts, Plane floor, Plane ceiling) { // Copy vertices - vertices = new WorldVertex[verts.Count]; - verts.CopyTo(vertices, 0); - triangles = vertices.Length / 3; + vertices = new WorldVertex[verts.Length][]; + triangles = new int[verts.Length]; + + //mxd + for(int i = 0; i < verts.Length; i++) + { + vertices[i] = new WorldVertex[verts[i].Length]; + verts[i].CopyTo(vertices[i], 0); + triangles[i] = vertices[i].Length / 3; + } + updategeo = true; //mxd. Do some GLOOME shenanigans... - if(triangles < 2) return; - float localcenterz = vertices[1].z * 0.5f; - Matrix m; - - switch(info.RenderMode) + for(int c = 0; c < vertices.Length; c++) { - // TODO: Currently broken in GLOOME... - case Thing.SpriteRenderMode.WALL_SPRITE: - m = Matrix.Translation(0f, 0f, -localcenterz) * Matrix.RotationY(Thing.RollRad) * Matrix.RotationZ(thing.Angle) * Matrix.Translation(0f, 0f, localcenterz); - for(int i = 0; i < vertices.Length; i++) - { - Vector4 transformed = Vector3.Transform(new Vector3(vertices[i].x, vertices[i].y, vertices[i].z), m); - vertices[i].x = transformed.X; - vertices[i].y = transformed.Y; - vertices[i].z = transformed.Z; - } - break; + if(triangles[c] < 2) continue; + float localcenterz = vertices[c][1].z * 0.5f; + Matrix m; - case Thing.SpriteRenderMode.FLOOR_SPRITE: - Matrix floorrotation = Matrix.RotationZ(info.RollSprite ? Thing.RollRad : 0f) - * Matrix.RotationY(Thing.Angle) - * Matrix.RotationX(Angle2D.PIHALF); - - m = Matrix.Translation(0f, 0f, -localcenterz) * floorrotation * Matrix.Translation(0f, 0f, localcenterz); - - for(int i = 0; i < vertices.Length; i++) - { - Vector4 transformed = Vector3.Transform(new Vector3(vertices[i].x, vertices[i].y, vertices[i].z), m); - vertices[i].x = transformed.X; - vertices[i].y = transformed.Y; - vertices[i].z = transformed.Z; - } - - // TODO: this won't work on things with AbsoluteZ flag - // TODO: +ROLLSPRITE implies +STICKTOPLANE? - if(info.StickToPlane || info.RollSprite) - { - // Calculate vertical offset - float floorz = floor.GetZ(Thing.Position); - float ceilz = ceiling.GetZ(Thing.Position); - - if(!float.IsNaN(floorz) && !float.IsNaN(ceilz)) + switch(info.RenderMode) + { + // TODO: Currently broken in GLOOME... + case Thing.SpriteRenderMode.WALL_SPRITE: + m = Matrix.Translation(0f, 0f, -localcenterz) * Matrix.RotationY(Thing.RollRad) * Matrix.RotationZ(thing.Angle) * Matrix.Translation(0f, 0f, localcenterz); + for(int i = 0; i < vertices[c].Length; i++) { - float voffset; - if(info.Hangs) - { - float thingz = ceilz - Thing.Position.z + Thing.Height; - voffset = 0.01f - floorz - General.Clamp(thingz, 0, ceilz - floorz); - } - else - { - voffset = 0.01f - floorz - General.Clamp(Thing.Position.z, 0, ceilz - floorz); - } - - // Apply it - for(int i = 0; i < vertices.Length; i++) - vertices[i].z = floor.GetZ(vertices[i].x + Thing.Position.x, vertices[i].y + Thing.Position.y) + voffset; + Vector4 transformed = Vector3.Transform(new Vector3(vertices[c][i].x, vertices[c][i].y, vertices[c][i].z), m); + vertices[c][i].x = transformed.X; + vertices[c][i].y = transformed.Y; + vertices[c][i].z = transformed.Z; } - } - break; + break; - case Thing.SpriteRenderMode.CEILING_SPRITE: - Matrix ceilrotation = Matrix.RotationZ(info.RollSprite ? Thing.RollRad : 0f) - * Matrix.RotationY(Thing.Angle) - * Matrix.RotationX(Angle2D.PIHALF); + case Thing.SpriteRenderMode.FLOOR_SPRITE: + Matrix floorrotation = Matrix.RotationZ(info.RollSprite ? Thing.RollRad : 0f) + * Matrix.RotationY(Thing.Angle) + * Matrix.RotationX(Angle2D.PIHALF); - m = Matrix.Translation(0f, 0f, -localcenterz) * ceilrotation * Matrix.Translation(0f, 0f, localcenterz); - - for(int i = 0; i < vertices.Length; i++) - { - Vector4 transformed = Vector3.Transform(new Vector3(vertices[i].x, vertices[i].y, vertices[i].z), m); - vertices[i].x = transformed.X; - vertices[i].y = transformed.Y; - vertices[i].z = transformed.Z; - } + m = Matrix.Translation(0f, 0f, -localcenterz) * floorrotation * Matrix.Translation(0f, 0f, localcenterz); - // TODO: this won't work on things with AbsoluteZ flag - // TODO: +ROLLSPRITE implies +STICKTOPLANE? - if(info.StickToPlane || info.RollSprite) - { - // Calculate vertical offset - float floorz = floor.GetZ(Thing.Position); - float ceilz = ceiling.GetZ(Thing.Position); - - if(!float.IsNaN(floorz) && !float.IsNaN(ceilz)) + for(int i = 0; i < vertices[c].Length; i++) { - float voffset; - if(info.Hangs) - { - float thingz = ceilz - Math.Max(0, Thing.Position.z) - Thing.Height; - voffset = -0.01f - General.Clamp(thingz, 0, ceilz - floorz); - } - else - { - voffset = -0.01f - floorz - General.Clamp(Thing.Position.z, 0, ceilz - floorz); - } - - // Apply it - for(int i = 0; i < vertices.Length; i++) - vertices[i].z = ceiling.GetZ(vertices[i].x + Thing.Position.x, vertices[i].y + Thing.Position.y) + voffset; + Vector4 transformed = Vector3.Transform(new Vector3(vertices[c][i].x, vertices[c][i].y, vertices[c][i].z), m); + vertices[c][i].x = transformed.X; + vertices[c][i].y = transformed.Y; + vertices[c][i].z = transformed.Z; } - } - break; - default: - if(info.RollSprite) - { - m = Matrix.Translation(0f, 0f, -localcenterz) * Matrix.RotationY(Thing.RollRad) * Matrix.Translation(0f, 0f, localcenterz); - for(int i = 0; i < vertices.Length; i++) + // TODO: this won't work on things with AbsoluteZ flag + // TODO: +ROLLSPRITE implies +STICKTOPLANE? + if(info.StickToPlane || info.RollSprite) { - Vector4 transformed = Vector3.Transform(new Vector3(vertices[i].x, vertices[i].y, vertices[i].z), m); - vertices[i].x = transformed.X; - vertices[i].y = transformed.Y; - vertices[i].z = transformed.Z; + // Calculate vertical offset + float floorz = floor.GetZ(Thing.Position); + float ceilz = ceiling.GetZ(Thing.Position); + + if(!float.IsNaN(floorz) && !float.IsNaN(ceilz)) + { + float voffset; + if(info.Hangs) + { + float thingz = ceilz - Thing.Position.z + Thing.Height; + voffset = 0.01f - floorz - General.Clamp(thingz, 0, ceilz - floorz); + } + else + { + voffset = 0.01f - floorz - General.Clamp(Thing.Position.z, 0, ceilz - floorz); + } + + // Apply it + for(int i = 0; i < vertices[c].Length; i++) + vertices[c][i].z = floor.GetZ(vertices[c][i].x + Thing.Position.x, vertices[c][i].y + Thing.Position.y) + voffset; + } } - } - break; + break; + + case Thing.SpriteRenderMode.CEILING_SPRITE: + Matrix ceilrotation = Matrix.RotationZ(info.RollSprite ? Thing.RollRad : 0f) + * Matrix.RotationY(Thing.Angle) + * Matrix.RotationX(Angle2D.PIHALF); + + m = Matrix.Translation(0f, 0f, -localcenterz) * ceilrotation * Matrix.Translation(0f, 0f, localcenterz); + + 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), m); + vertices[c][i].x = transformed.X; + vertices[c][i].y = transformed.Y; + vertices[c][i].z = transformed.Z; + } + + // TODO: this won't work on things with AbsoluteZ flag + // TODO: +ROLLSPRITE implies +STICKTOPLANE? + if(info.StickToPlane || info.RollSprite) + { + // Calculate vertical offset + float floorz = floor.GetZ(Thing.Position); + float ceilz = ceiling.GetZ(Thing.Position); + + if(!float.IsNaN(floorz) && !float.IsNaN(ceilz)) + { + float voffset; + if(info.Hangs) + { + float thingz = ceilz - Math.Max(0, Thing.Position.z) - Thing.Height; + voffset = -0.01f - General.Clamp(thingz, 0, ceilz - floorz); + } + else + { + voffset = -0.01f - floorz - General.Clamp(Thing.Position.z, 0, ceilz - floorz); + } + + // Apply it + for(int i = 0; i < vertices[c].Length; i++) + vertices[c][i].z = ceiling.GetZ(vertices[c][i].x + Thing.Position.x, vertices[c][i].y + Thing.Position.y) + voffset; + } + } + break; + + default: + if(info.RollSprite) + { + m = Matrix.Translation(0f, 0f, -localcenterz) * Matrix.RotationY(Thing.RollRad) * Matrix.Translation(0f, 0f, localcenterz); + 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), m); + vertices[c][i].x = transformed.X; + vertices[c][i].y = transformed.Y; + vertices[c][i].z = transformed.Z; + } + } + break; + } } } @@ -391,22 +417,26 @@ namespace CodeImp.DoomBuilder.VisualModes // Do we need to update the geometry buffer? if(updategeo) { - // Trash geometry buffer - if(geobuffer != null) geobuffer.Dispose(); - geobuffer = null; + //mxd. Trash geometry buffers + if(geobuffers != null) + foreach(VertexBuffer geobuffer in geobuffers) geobuffer.Dispose(); // Any vertics? if(vertices.Length > 0) { - // Make a new buffer - geobuffer = new VertexBuffer(General.Map.Graphics.Device, WorldVertex.Stride * vertices.Length, - Usage.WriteOnly | Usage.Dynamic, VertexFormat.None, Pool.Default); + geobuffers = new VertexBuffer[vertices.Length]; + for(int i = 0; i < vertices.Length; i++) + { + // Make a new buffer + geobuffers[i] = new VertexBuffer(General.Map.Graphics.Device, WorldVertex.Stride * vertices[i].Length, + Usage.WriteOnly | Usage.Dynamic, VertexFormat.None, Pool.Default); - // Fill the buffer - DataStream bufferstream = geobuffer.Lock(0, WorldVertex.Stride * vertices.Length, LockFlags.Discard); - bufferstream.WriteRange(vertices); - geobuffer.Unlock(); - bufferstream.Dispose(); + // Fill the buffer + DataStream bufferstream = geobuffers[i].Lock(0, WorldVertex.Stride * vertices[i].Length, LockFlags.Discard); + bufferstream.WriteRange(vertices[i]); + geobuffers[i].Unlock(); + bufferstream.Dispose(); + } } //mxd. Check if thing is light @@ -707,6 +737,15 @@ namespace CodeImp.DoomBuilder.VisualModes boundingBox[7] = new Vector3D(position_v3.X - width, position_v3.Y + width, Center.Z + h2); boundingBox[8] = new Vector3D(position_v3.X + width, position_v3.Y + width, Center.Z + h2); } + + //mxd. This updates the sprite frame to be rendered + internal void UpdateSpriteFrame() + { + if(textures.Length != 8) + spriteframe = 0; + else + spriteframe = (General.ClampAngle((int)Angle2D.RadToDeg((General.Map.VisualCamera.Position - thing.Position).GetAngleXY()) - thing.AngleDoom + 292)) / 45; // Convert to [0..7] range; 292 == 270 + 45/2 + } /// /// This is called when the thing must be tested for line intersection. This should reject diff --git a/Source/Plugins/BuilderModes/VisualModes/BaseVisualThing.cs b/Source/Plugins/BuilderModes/VisualModes/BaseVisualThing.cs index 46936a06..617b9ed9 100644 --- a/Source/Plugins/BuilderModes/VisualModes/BaseVisualThing.cs +++ b/Source/Plugins/BuilderModes/VisualModes/BaseVisualThing.cs @@ -42,7 +42,7 @@ namespace CodeImp.DoomBuilder.BuilderModes private bool isloaded; private bool nointeraction; //mxd - private ImageData sprite; + private ImageData[] sprites; private float cageradius2; private Vector2D pos2d; private Vector3D boxp1; @@ -76,11 +76,12 @@ namespace CodeImp.DoomBuilder.BuilderModes //mxd. When true, the thing can be moved below floor/above ceiling nointeraction = (info.Actor != null && info.Actor.GetFlagValue("nointeraction", false)); - // Find sprite texture - if(info.Sprite.Length > 0) + //mxd. Find sprite textures + sprites = new ImageData[info.SpriteFrame.Length]; + for(int i = 0; i < info.SpriteFrame.Length; i++) { - sprite = General.Map.Data.GetSpriteImage(info.Sprite); - if(sprite != null) sprite.AddReference(); + sprites[i] = General.Map.Data.GetSpriteImage(info.SpriteFrame[i].Sprite); + if(sprites[i] != null) sprites[i].AddReference(); } //mxd @@ -191,98 +192,103 @@ namespace CodeImp.DoomBuilder.BuilderModes sizeless = false; } - if(sprite != null) + Plane floor = new Plane(); //mxd + Plane ceiling = new Plane(); //mxd + if(Thing.Sector != null) { - Plane floor = new Plane(); //mxd - Plane ceiling = new Plane(); //mxd - if(Thing.Sector != null) + SectorData sd = mode.GetSectorData(Thing.Sector); + floor = sd.Floor.plane; //mxd + ceiling = sd.Ceiling.plane; //mxd + + if(!info.Bright) { - SectorData sd = mode.GetSectorData(Thing.Sector); - floor = sd.Floor.plane; //mxd - ceiling = sd.Ceiling.plane; //mxd + Vector3D thingpos = new Vector3D(Thing.Position.x, Thing.Position.y, Thing.Position.z + sd.Floor.plane.GetZ(Thing.Position)); + SectorLevel level = sd.GetLevelAboveOrAt(thingpos); - if(!info.Bright) + //mxd. Let's use point on floor plane instead of Thing.Sector.FloorHeight; + if(nointeraction && level == null && sd.LightLevels.Count > 0) level = sd.LightLevels[sd.LightLevels.Count - 1]; + + //mxd. Use the light level of the highest surface when a thing is above highest sector level. + if(level != null) { - Vector3D thingpos = new Vector3D(Thing.Position.x, Thing.Position.y, Thing.Position.z + sd.Floor.plane.GetZ(Thing.Position)); - SectorLevel level = sd.GetLevelAboveOrAt(thingpos); + // TECH: In GZDoom, ceiling glow doesn't affect thing brightness + // Use sector brightness for color shading + int brightness = level.brightnessbelow; - //mxd. Let's use point on floor plane instead of Thing.Sector.FloorHeight; - if(nointeraction && level == null && sd.LightLevels.Count > 0) level = sd.LightLevels[sd.LightLevels.Count - 1]; - - //mxd. Use the light level of the highest surface when a thing is above highest sector level. - if(level != null) + // Level is glowing + if(level.affectedbyglow && level.type == SectorLevelType.Floor) { - // TECH: In GZDoom, ceiling glow doesn't affect thing brightness - // Use sector brightness for color shading - int brightness = level.brightnessbelow; - - // Level is glowing - if(level.affectedbyglow && level.type == SectorLevelType.Floor) + // Extrafloor glow doesn't affect thing brightness + if(level.sector == Thing.Sector) { - // Extrafloor glow doesn't affect thing brightness - if(level.sector == Thing.Sector) - { - float planez = level.plane.GetZ(thingpos); + float planez = level.plane.GetZ(thingpos); - // Get glow brightness - int glowbrightness = sd.FloorGlow.Brightness / 2; - SectorLevel nexthigher = sd.GetLevelAbove(new Vector3D(thingpos, planez)); + // Get glow brightness + int glowbrightness = sd.FloorGlow.Brightness / 2; + SectorLevel nexthigher = sd.GetLevelAbove(new Vector3D(thingpos, planez)); - // Interpolate thing brightness between glow and regular ones - if(nexthigher != null) - { - float higherz = nexthigher.plane.GetZ(thingpos); - float delta = General.Clamp(1.0f - (thingpos.z - planez) / (higherz - planez), 0f, 1f); - brightness = (int)((glowbrightness + level.sector.Brightness / 2) * delta + nexthigher.sector.Brightness * (1.0f - delta)); - } - } - } - // Level below this one is glowing. Only possible for floor glow(?) - else if(level.type == SectorLevelType.Glow) - { // Interpolate thing brightness between glow and regular ones - if(sd.Floor != null && sd.FloorGlow != null) + if(nexthigher != null) { - // Get glow brightness - float glowz = level.plane.GetZ(thingpos); - float floorz = floor.GetZ(thingpos); - float delta = General.Clamp((thingpos.z - floorz) / (glowz - floorz), 0f, 1f); - - brightness = (int)((sd.FloorGlow.Brightness / 2 + sd.Floor.sector.Brightness / 2) * (1.0f - delta) + sd.Floor.sector.Brightness * delta); + float higherz = nexthigher.plane.GetZ(thingpos); + float delta = General.Clamp(1.0f - (thingpos.z - planez) / (higherz - planez), 0f, 1f); + brightness = (int)((glowbrightness + level.sector.Brightness / 2) * delta + nexthigher.sector.Brightness * (1.0f - delta)); } } - - PixelColor areabrightness = PixelColor.FromInt(mode.CalculateBrightness(brightness)); - PixelColor areacolor = PixelColor.Modulate(level.colorbelow, areabrightness); - sectorcolor = areacolor.WithAlpha(alpha).ToInt(); - - //mxd. Calculate fogfactor - fogfactor = VisualGeometry.CalculateFogFactor(level.sector.FogMode, brightness); } - } - //TECH: even Bright Thing frames are affected by custom fade... - else - { - Vector3D thingpos = new Vector3D(Thing.Position.x, Thing.Position.y, Thing.Position.z + sd.Floor.plane.GetZ(Thing.Position)); - SectorLevel level = sd.GetLevelAboveOrAt(thingpos); - - if(level != null && level.sector.FogMode > SectorFogMode.CLASSIC) + // Level below this one is glowing. Only possible for floor glow(?) + else if(level.type == SectorLevelType.Glow) { - //mxd. Calculate fogfactor - fogfactor = VisualGeometry.CalculateFogFactor(level.sector.FogMode, level.brightnessbelow); + // Interpolate thing brightness between glow and regular ones + if(sd.Floor != null && sd.FloorGlow != null) + { + // Get glow brightness + float glowz = level.plane.GetZ(thingpos); + float floorz = floor.GetZ(thingpos); + float delta = General.Clamp((thingpos.z - floorz) / (glowz - floorz), 0f, 1f); + + brightness = (int)((sd.FloorGlow.Brightness / 2 + sd.Floor.sector.Brightness / 2) * (1.0f - delta) + sd.Floor.sector.Brightness * delta); + } } + + PixelColor areabrightness = PixelColor.FromInt(mode.CalculateBrightness(brightness)); + PixelColor areacolor = PixelColor.Modulate(level.colorbelow, areabrightness); + sectorcolor = areacolor.WithAlpha(alpha).ToInt(); + + //mxd. Calculate fogfactor + fogfactor = VisualGeometry.CalculateFogFactor(level.sector.FogMode, brightness); } } - + //TECH: even Bright Thing frames are affected by custom fade... + else + { + Vector3D thingpos = new Vector3D(Thing.Position.x, Thing.Position.y, Thing.Position.z + sd.Floor.plane.GetZ(Thing.Position)); + SectorLevel level = sd.GetLevelAboveOrAt(thingpos); + + if(level != null && level.sector.FogMode > SectorFogMode.CLASSIC) + { + //mxd. Calculate fogfactor + fogfactor = VisualGeometry.CalculateFogFactor(level.sector.FogMode, level.brightnessbelow); + } + } + } + + //mxd. Create verts for all sprite angles + WorldVertex[][] allverts = new WorldVertex[info.SpriteFrame.Length][]; + base.textures = new ImageData[info.SpriteFrame.Length]; + + for(int i = 0; i < sprites.Length; i++) + { // Check if the texture is loaded + ImageData sprite = sprites[i]; sprite.LoadImage(); isloaded = sprite.IsImageLoaded; if(isloaded) { float offsetx = 0.0f; float offsety = 0.0f; - - base.Texture = sprite; + + base.textures[i] = sprite; // Determine sprite size and offset float radius = sprite.ScaledWidth * 0.5f; @@ -304,30 +310,34 @@ namespace CodeImp.DoomBuilder.BuilderModes // Make vertices WorldVertex[] verts = new WorldVertex[6]; + //mxd. Sprite mirroring + float ul = (info.SpriteFrame[i].Mirror ? 1f : 0f); + float ur = (info.SpriteFrame[i].Mirror ? 0f : 1f); + if(sizeless) //mxd { float hh = height / 2; - verts[0] = new WorldVertex(-radius + offsetx, 0.0f, offsety - hh, sectorcolor, 0.0f, 1.0f); - verts[1] = new WorldVertex(-radius + offsetx, 0.0f, hh + offsety, sectorcolor, 0.0f, 0.0f); - verts[2] = new WorldVertex(+radius + offsetx, 0.0f, hh + offsety, sectorcolor, 1.0f, 0.0f); + 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[3] = verts[0]; verts[4] = verts[2]; - verts[5] = new WorldVertex(+radius + offsetx, 0.0f, offsety - hh, sectorcolor, 1.0f, 1.0f); + verts[5] = new WorldVertex(+radius + offsetx, 0.0f, offsety - hh, sectorcolor, ur, 1.0f); } else { - verts[0] = new WorldVertex(-radius + offsetx, 0.0f, offsety, sectorcolor, 0.0f, 1.0f); - verts[1] = new WorldVertex(-radius + offsetx, 0.0f, height + offsety, sectorcolor, 0.0f, 0.0f); - verts[2] = new WorldVertex(+radius + offsetx, 0.0f, height + offsety, sectorcolor, 1.0f, 0.0f); + 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[3] = verts[0]; verts[4] = verts[2]; - verts[5] = new WorldVertex(+radius + offsetx, 0.0f, offsety, sectorcolor, 1.0f, 1.0f); + verts[5] = new WorldVertex(+radius + offsetx, 0.0f, offsety, sectorcolor, ur, 1.0f); } - SetVertices(verts, floor, ceiling); + allverts[i] = verts; } else { - base.Texture = General.Map.Data.Hourglass3D; + base.textures[i] = General.Map.Data.Hourglass3D; // Determine sprite size float radius = Math.Min(thingradius, thingheight / 2f); @@ -341,9 +351,12 @@ namespace CodeImp.DoomBuilder.BuilderModes verts[3] = verts[0]; verts[4] = verts[2]; verts[5] = new WorldVertex(+radius, 0.0f, 0.0f, sectorcolor, 1.0f, 1.0f); - SetVertices(verts, floor, ceiling); + allverts[i] = verts; } } + + //mxd + SetVertices(allverts, floor, ceiling); // Determine position Vector3D pos = Thing.Position; @@ -439,10 +452,10 @@ namespace CodeImp.DoomBuilder.BuilderModes { if(!IsDisposed) { - if(sprite != null) + if(sprites != null) //mxd { - sprite.RemoveReference(); - sprite = null; + foreach(ImageData sprite in sprites) sprite.RemoveReference(); + sprites = null; } base.Dispose(); @@ -462,11 +475,12 @@ namespace CodeImp.DoomBuilder.BuilderModes //mxd. When true, the thing can be moved below floor/above ceiling nointeraction = (info.Actor != null && info.Actor.GetFlagValue("nointeraction", false)); - // Find sprite texture - if(info.Sprite.Length > 0) + //mxd. Find sprite textures + sprites = new ImageData[info.SpriteFrame.Length]; + for(int i = 0; i < info.SpriteFrame.Length; i++) { - sprite = General.Map.Data.GetSpriteImage(info.Sprite); - if(sprite != null) sprite.AddReference(); + sprites[i] = General.Map.Data.GetSpriteImage(info.SpriteFrame[i].Sprite); + if(sprites[i] != null) sprites[i].AddReference(); } // Setup visual thing @@ -478,11 +492,18 @@ namespace CodeImp.DoomBuilder.BuilderModes { if(!isloaded) { - // Rebuild sprite geometry when sprite is loaded - if(sprite.IsImageLoaded) + //mxd. Rebuild sprite geometry when all sprites are loaded + bool allloaded = true; + foreach(ImageData sprite in sprites) { - Setup(); + if(!sprite.IsImageLoaded) + { + allloaded = false; + break; + } } + + if(allloaded) Setup(); } // Let the base update @@ -757,13 +778,14 @@ namespace CodeImp.DoomBuilder.BuilderModes //mxd public void OnChangeScale(int incrementX, int incrementY) { - if(!General.Map.UDMF || !sprite.IsImageLoaded) return; + if(!General.Map.UDMF || sprites == null || !sprites[0].IsImageLoaded) return; if((General.Map.UndoRedo.NextUndo == null) || (General.Map.UndoRedo.NextUndo.TicketID != undoticket)) undoticket = mode.CreateUndo("Change thing scale"); float scaleX = Thing.ScaleX; float scaleY = Thing.ScaleY; + ImageData sprite = sprites[0]; if(incrementX != 0) {