Added, Visual mode: thing sprites are now angle-dependent.

This commit is contained in:
MaxED 2016-04-11 23:05:16 +00:00
parent c861f8ecff
commit c3392f8399
4 changed files with 325 additions and 265 deletions

View file

@ -95,21 +95,16 @@ namespace CodeImp.DoomBuilder
#region ================== Methods #region ================== Methods
public static void Write(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); }
Write(DebugMessageType.INFO, text); 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 WriteLine(string text) public static void Write(DebugMessageType type, string text, bool append)
{
Write(DebugMessageType.INFO, text + Environment.NewLine);
}
public static void Write(DebugMessageType type, string text)
{ {
if(me != null && me.InvokeRequired) if(me != null && me.InvokeRequired)
{ {
me.Invoke(new Action<DebugMessageType, string>(Write), new object[] { type, text }); me.Invoke(new Action<DebugMessageType, string, bool>(Write), new object[] { type, text, append });
} }
else else
{ {
@ -117,16 +112,11 @@ namespace CodeImp.DoomBuilder
messages.Add(new KeyValuePair<DebugMessageType, string>(type, text)); messages.Add(new KeyValuePair<DebugMessageType, string>(type, text));
if(me != null && (me.filters & type) == type) 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() public static void Clear()
{ {
if(me != null && me.InvokeRequired) if(me != null && me.InvokeRequired)
@ -226,12 +216,13 @@ namespace CodeImp.DoomBuilder
#endif #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; text = textheaders[type] + text;
console.SelectionStart = console.TextLength; console.SelectionStart = console.TextLength;
console.SelectionColor = textcolors[type]; console.SelectionColor = textcolors[type];
console.AppendText(text); if(append) console.AppendText(text);
else console.Text = text;
if(scroll && autoscroll.Checked) console.ScrollToCaret(); if(scroll && autoscroll.Checked) console.ScrollToCaret();
} }
@ -257,7 +248,7 @@ namespace CodeImp.DoomBuilder
{ {
if((filters & pair.Key) == pair.Key && CheckTextFilter(pair.Value, searchbox.Text)) if((filters & pair.Key) == pair.Key && CheckTextFilter(pair.Value, searchbox.Text))
{ {
AddMessage(pair.Key, pair.Value, false); AddMessage(pair.Key, pair.Value, false, true);
} }
} }

View file

@ -1107,6 +1107,7 @@ namespace CodeImp.DoomBuilder.Rendering
// Render things collected // Render things collected
foreach(VisualThing t in thingspass) foreach(VisualThing t in thingspass)
{ {
t.UpdateSpriteFrame(); // Set correct texture, geobuffer and triangles count
if(t.Texture is UnknownImage) continue; if(t.Texture is UnknownImage) continue;
// Change blend mode? // Change blend mode?
@ -1720,28 +1721,35 @@ namespace CodeImp.DoomBuilder.Rendering
} }
} }
// Gather regular things // Gather regular things
else if(t.Texture != null) //Must have a texture! else
{ {
//mxd //mxd. Set correct texture, geobuffer and triangles count
switch(t.RenderPass) t.UpdateSpriteFrame();
//Must have a texture!
if(t.Texture != null)
{ {
case RenderPass.Solid: //mxd
if(!solidthings.ContainsKey(t.Texture)) solidthings.Add(t.Texture, new List<VisualThing>()); switch(t.RenderPass)
solidthings[t.Texture].Add(t); {
break; case RenderPass.Solid:
if(!solidthings.ContainsKey(t.Texture)) solidthings.Add(t.Texture, new List<VisualThing>());
solidthings[t.Texture].Add(t);
break;
case RenderPass.Mask: case RenderPass.Mask:
if(!maskedthings.ContainsKey(t.Texture)) maskedthings.Add(t.Texture, new List<VisualThing>()); if(!maskedthings.ContainsKey(t.Texture)) maskedthings.Add(t.Texture, new List<VisualThing>());
maskedthings[t.Texture].Add(t); maskedthings[t.Texture].Add(t);
break; break;
case RenderPass.Additive: case RenderPass.Additive:
case RenderPass.Alpha: case RenderPass.Alpha:
translucentthings.Add(t); translucentthings.Add(t);
break; break;
default: default:
throw new NotImplementedException("Thing rendering of " + t.RenderPass + " render pass is not implemented!"); throw new NotImplementedException("Thing rendering of " + t.RenderPass + " render pass is not implemented!");
}
} }
} }

View file

@ -48,17 +48,18 @@ namespace CodeImp.DoomBuilder.VisualModes
//mxd. Info //mxd. Info
protected ThingTypeInfo info; protected ThingTypeInfo info;
// Texture // Textures
private ImageData texture; protected ImageData[] textures;
// Geometry // Geometry
private WorldVertex[] vertices; private WorldVertex[][] vertices;
private VertexBuffer geobuffer; private VertexBuffer[] geobuffers;
private VertexBuffer cagebuffer; //mxd private VertexBuffer cagebuffer; //mxd
private int cagelength; //mxd private int cagelength; //mxd
private bool updategeo; private bool updategeo;
private bool updatecage; //mxd private bool updatecage; //mxd
private int triangles; private int[] triangles;
private int spriteframe; //mxd
// Rendering // Rendering
private RenderPass renderpass; private RenderPass renderpass;
@ -97,17 +98,17 @@ namespace CodeImp.DoomBuilder.VisualModes
#region ================== Properties #region ================== Properties
internal VertexBuffer GeometryBuffer { get { return geobuffer; } } internal VertexBuffer GeometryBuffer { get { return geobuffers[spriteframe]; } }
internal VertexBuffer CageBuffer { get { return cagebuffer; } } //mxd internal VertexBuffer CageBuffer { get { return cagebuffer; } } //mxd
internal int CageLength { get { return cagelength; } } //mxd internal int CageLength { get { return cagelength; } } //mxd
internal bool NeedsUpdateGeo { get { return updategeo; } } 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 Matrix Position { get { return position; } }
internal Color4 CageColor { get { return cagecolor; } } internal Color4 CageColor { get { return cagecolor; } }
public ThingTypeInfo Info { get { return info; } } //mxd public ThingTypeInfo Info { get { return info; } } //mxd
//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 int CameraDistance { get { return cameradistance; } }
public float FogFactor { get { return fogfactor; } } public float FogFactor { get { return fogfactor; } }
public Vector3 Center public Vector3 Center
@ -142,7 +143,7 @@ namespace CodeImp.DoomBuilder.VisualModes
/// <summary> /// <summary>
/// Image to use as texture on the geometry. /// Image to use as texture on the geometry.
/// </summary> /// </summary>
public ImageData Texture { get { return texture; } set { texture = value; } } public ImageData Texture { get { return textures[spriteframe]; } }
/// <summary> /// <summary>
/// Disposed or not? /// Disposed or not?
@ -186,8 +187,12 @@ namespace CodeImp.DoomBuilder.VisualModes
if(!isdisposed) if(!isdisposed)
{ {
// Clean up // Clean up
if(geobuffer != null) geobuffer.Dispose(); if(geobuffers != null) //mxd
geobuffer = null; {
foreach(VertexBuffer buffer in geobuffers) buffer.Dispose();
geobuffers = null;
}
if(cagebuffer != null) cagebuffer.Dispose(); //mxd if(cagebuffer != null) cagebuffer.Dispose(); //mxd
cagebuffer = null; //mxd cagebuffer = null; //mxd
@ -213,8 +218,18 @@ namespace CodeImp.DoomBuilder.VisualModes
public void UnloadResource() public void UnloadResource()
{ {
// Trash geometry buffers // Trash geometry buffers
if(geobuffer != null) geobuffer.Dispose(); if(geobuffers != null) //mxd
geobuffer = null; {
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 if(cagebuffer != null) cagebuffer.Dispose(); //mxd
cagebuffer = null; //mxd cagebuffer = null; //mxd
updategeo = true; updategeo = true;
@ -256,132 +271,143 @@ namespace CodeImp.DoomBuilder.VisualModes
} }
// This sets the vertices for the thing sprite // This sets the vertices for the thing sprite
protected void SetVertices(ICollection<WorldVertex> verts, Plane floor, Plane ceiling) protected void SetVertices(WorldVertex[][] verts, Plane floor, Plane ceiling)
{ {
// Copy vertices // Copy vertices
vertices = new WorldVertex[verts.Count]; vertices = new WorldVertex[verts.Length][];
verts.CopyTo(vertices, 0); triangles = new int[verts.Length];
triangles = vertices.Length / 3;
//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; updategeo = true;
//mxd. Do some GLOOME shenanigans... //mxd. Do some GLOOME shenanigans...
if(triangles < 2) return; for(int c = 0; c < vertices.Length; c++)
float localcenterz = vertices[1].z * 0.5f;
Matrix m;
switch(info.RenderMode)
{ {
// TODO: Currently broken in GLOOME... if(triangles[c] < 2) continue;
case Thing.SpriteRenderMode.WALL_SPRITE: float localcenterz = vertices[c][1].z * 0.5f;
m = Matrix.Translation(0f, 0f, -localcenterz) * Matrix.RotationY(Thing.RollRad) * Matrix.RotationZ(thing.Angle) * Matrix.Translation(0f, 0f, localcenterz); Matrix m;
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;
case Thing.SpriteRenderMode.FLOOR_SPRITE: switch(info.RenderMode)
Matrix floorrotation = Matrix.RotationZ(info.RollSprite ? Thing.RollRad : 0f) {
* Matrix.RotationY(Thing.Angle) // TODO: Currently broken in GLOOME...
* Matrix.RotationX(Angle2D.PIHALF); case Thing.SpriteRenderMode.WALL_SPRITE:
m = Matrix.Translation(0f, 0f, -localcenterz) * Matrix.RotationY(Thing.RollRad) * Matrix.RotationZ(thing.Angle) * Matrix.Translation(0f, 0f, localcenterz);
m = Matrix.Translation(0f, 0f, -localcenterz) * floorrotation * Matrix.Translation(0f, 0f, localcenterz); for(int i = 0; i < vertices[c].Length; i++)
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))
{ {
float voffset; Vector4 transformed = Vector3.Transform(new Vector3(vertices[c][i].x, vertices[c][i].y, vertices[c][i].z), m);
if(info.Hangs) vertices[c][i].x = transformed.X;
{ vertices[c][i].y = transformed.Y;
float thingz = ceilz - Thing.Position.z + Thing.Height; vertices[c][i].z = transformed.Z;
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;
} }
} break;
break;
case Thing.SpriteRenderMode.CEILING_SPRITE: case Thing.SpriteRenderMode.FLOOR_SPRITE:
Matrix ceilrotation = Matrix.RotationZ(info.RollSprite ? Thing.RollRad : 0f) Matrix floorrotation = Matrix.RotationZ(info.RollSprite ? Thing.RollRad : 0f)
* Matrix.RotationY(Thing.Angle) * Matrix.RotationY(Thing.Angle)
* Matrix.RotationX(Angle2D.PIHALF); * Matrix.RotationX(Angle2D.PIHALF);
m = Matrix.Translation(0f, 0f, -localcenterz) * ceilrotation * Matrix.Translation(0f, 0f, localcenterz); 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 for(int i = 0; i < vertices[c].Length; i++)
// 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; Vector4 transformed = Vector3.Transform(new Vector3(vertices[c][i].x, vertices[c][i].y, vertices[c][i].z), m);
if(info.Hangs) vertices[c][i].x = transformed.X;
{ vertices[c][i].y = transformed.Y;
float thingz = ceilz - Math.Max(0, Thing.Position.z) - Thing.Height; vertices[c][i].z = transformed.Z;
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;
} }
}
break;
default: // TODO: this won't work on things with AbsoluteZ flag
if(info.RollSprite) // TODO: +ROLLSPRITE implies +STICKTOPLANE?
{ if(info.StickToPlane || 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++)
{ {
Vector4 transformed = Vector3.Transform(new Vector3(vertices[i].x, vertices[i].y, vertices[i].z), m); // Calculate vertical offset
vertices[i].x = transformed.X; float floorz = floor.GetZ(Thing.Position);
vertices[i].y = transformed.Y; float ceilz = ceiling.GetZ(Thing.Position);
vertices[i].z = transformed.Z;
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? // Do we need to update the geometry buffer?
if(updategeo) if(updategeo)
{ {
// Trash geometry buffer //mxd. Trash geometry buffers
if(geobuffer != null) geobuffer.Dispose(); if(geobuffers != null)
geobuffer = null; foreach(VertexBuffer geobuffer in geobuffers) geobuffer.Dispose();
// Any vertics? // Any vertics?
if(vertices.Length > 0) if(vertices.Length > 0)
{ {
// Make a new buffer geobuffers = new VertexBuffer[vertices.Length];
geobuffer = new VertexBuffer(General.Map.Graphics.Device, WorldVertex.Stride * vertices.Length, for(int i = 0; i < vertices.Length; i++)
Usage.WriteOnly | Usage.Dynamic, VertexFormat.None, Pool.Default); {
// 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 // Fill the buffer
DataStream bufferstream = geobuffer.Lock(0, WorldVertex.Stride * vertices.Length, LockFlags.Discard); DataStream bufferstream = geobuffers[i].Lock(0, WorldVertex.Stride * vertices[i].Length, LockFlags.Discard);
bufferstream.WriteRange(vertices); bufferstream.WriteRange(vertices[i]);
geobuffer.Unlock(); geobuffers[i].Unlock();
bufferstream.Dispose(); bufferstream.Dispose();
}
} }
//mxd. Check if thing is light //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[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); 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
}
/// <summary> /// <summary>
/// This is called when the thing must be tested for line intersection. This should reject /// This is called when the thing must be tested for line intersection. This should reject

View file

@ -42,7 +42,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
private bool isloaded; private bool isloaded;
private bool nointeraction; //mxd private bool nointeraction; //mxd
private ImageData sprite; private ImageData[] sprites;
private float cageradius2; private float cageradius2;
private Vector2D pos2d; private Vector2D pos2d;
private Vector3D boxp1; private Vector3D boxp1;
@ -76,11 +76,12 @@ namespace CodeImp.DoomBuilder.BuilderModes
//mxd. When true, the thing can be moved below floor/above ceiling //mxd. When true, the thing can be moved below floor/above ceiling
nointeraction = (info.Actor != null && info.Actor.GetFlagValue("nointeraction", false)); nointeraction = (info.Actor != null && info.Actor.GetFlagValue("nointeraction", false));
// Find sprite texture //mxd. Find sprite textures
if(info.Sprite.Length > 0) sprites = new ImageData[info.SpriteFrame.Length];
for(int i = 0; i < info.SpriteFrame.Length; i++)
{ {
sprite = General.Map.Data.GetSpriteImage(info.Sprite); sprites[i] = General.Map.Data.GetSpriteImage(info.SpriteFrame[i].Sprite);
if(sprite != null) sprite.AddReference(); if(sprites[i] != null) sprites[i].AddReference();
} }
//mxd //mxd
@ -191,98 +192,103 @@ namespace CodeImp.DoomBuilder.BuilderModes
sizeless = false; sizeless = false;
} }
if(sprite != null) Plane floor = new Plane(); //mxd
Plane ceiling = new Plane(); //mxd
if(Thing.Sector != null)
{ {
Plane floor = new Plane(); //mxd SectorData sd = mode.GetSectorData(Thing.Sector);
Plane ceiling = new Plane(); //mxd floor = sd.Floor.plane; //mxd
if(Thing.Sector != null) ceiling = sd.Ceiling.plane; //mxd
if(!info.Bright)
{ {
SectorData sd = mode.GetSectorData(Thing.Sector); Vector3D thingpos = new Vector3D(Thing.Position.x, Thing.Position.y, Thing.Position.z + sd.Floor.plane.GetZ(Thing.Position));
floor = sd.Floor.plane; //mxd SectorLevel level = sd.GetLevelAboveOrAt(thingpos);
ceiling = sd.Ceiling.plane; //mxd
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)); // TECH: In GZDoom, ceiling glow doesn't affect thing brightness
SectorLevel level = sd.GetLevelAboveOrAt(thingpos); // Use sector brightness for color shading
int brightness = level.brightnessbelow;
//mxd. Let's use point on floor plane instead of Thing.Sector.FloorHeight; // Level is glowing
if(nointeraction && level == null && sd.LightLevels.Count > 0) level = sd.LightLevels[sd.LightLevels.Count - 1]; if(level.affectedbyglow && level.type == SectorLevelType.Floor)
//mxd. Use the light level of the highest surface when a thing is above highest sector level.
if(level != null)
{ {
// TECH: In GZDoom, ceiling glow doesn't affect thing brightness // Extrafloor glow doesn't affect thing brightness
// Use sector brightness for color shading if(level.sector == Thing.Sector)
int brightness = level.brightnessbelow;
// Level is glowing
if(level.affectedbyglow && level.type == SectorLevelType.Floor)
{ {
// Extrafloor glow doesn't affect thing brightness float planez = level.plane.GetZ(thingpos);
if(level.sector == Thing.Sector)
{
float planez = level.plane.GetZ(thingpos);
// Get glow brightness // Get glow brightness
int glowbrightness = sd.FloorGlow.Brightness / 2; int glowbrightness = sd.FloorGlow.Brightness / 2;
SectorLevel nexthigher = sd.GetLevelAbove(new Vector3D(thingpos, planez)); 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 // Interpolate thing brightness between glow and regular ones
if(sd.Floor != null && sd.FloorGlow != null) if(nexthigher != null)
{ {
// Get glow brightness float higherz = nexthigher.plane.GetZ(thingpos);
float glowz = level.plane.GetZ(thingpos); float delta = General.Clamp(1.0f - (thingpos.z - planez) / (higherz - planez), 0f, 1f);
float floorz = floor.GetZ(thingpos); brightness = (int)((glowbrightness + level.sector.Brightness / 2) * delta + nexthigher.sector.Brightness * (1.0f - delta));
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);
} }
} // Level below this one is glowing. Only possible for floor glow(?)
//TECH: even Bright Thing frames are affected by custom fade... else if(level.type == SectorLevelType.Glow)
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 // Interpolate thing brightness between glow and regular ones
fogfactor = VisualGeometry.CalculateFogFactor(level.sector.FogMode, level.brightnessbelow); 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 // Check if the texture is loaded
ImageData sprite = sprites[i];
sprite.LoadImage(); sprite.LoadImage();
isloaded = sprite.IsImageLoaded; isloaded = sprite.IsImageLoaded;
if(isloaded) if(isloaded)
{ {
float offsetx = 0.0f; float offsetx = 0.0f;
float offsety = 0.0f; float offsety = 0.0f;
base.Texture = sprite; base.textures[i] = sprite;
// Determine sprite size and offset // Determine sprite size and offset
float radius = sprite.ScaledWidth * 0.5f; float radius = sprite.ScaledWidth * 0.5f;
@ -304,30 +310,34 @@ namespace CodeImp.DoomBuilder.BuilderModes
// Make vertices // Make vertices
WorldVertex[] verts = new WorldVertex[6]; 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 if(sizeless) //mxd
{ {
float hh = height / 2; float hh = height / 2;
verts[0] = new WorldVertex(-radius + offsetx, 0.0f, offsety - hh, sectorcolor, 0.0f, 1.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, 0.0f, 0.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, 1.0f, 0.0f); verts[2] = new WorldVertex(+radius + offsetx, 0.0f, hh + offsety, sectorcolor, ur, 0.0f);
verts[3] = verts[0]; verts[3] = verts[0];
verts[4] = verts[2]; 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 else
{ {
verts[0] = new WorldVertex(-radius + offsetx, 0.0f, offsety, sectorcolor, 0.0f, 1.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, 0.0f, 0.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, 1.0f, 0.0f); verts[2] = new WorldVertex(+radius + offsetx, 0.0f, height + offsety, sectorcolor, ur, 0.0f);
verts[3] = verts[0]; verts[3] = verts[0];
verts[4] = verts[2]; 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 else
{ {
base.Texture = General.Map.Data.Hourglass3D; base.textures[i] = General.Map.Data.Hourglass3D;
// Determine sprite size // Determine sprite size
float radius = Math.Min(thingradius, thingheight / 2f); float radius = Math.Min(thingradius, thingheight / 2f);
@ -341,9 +351,12 @@ namespace CodeImp.DoomBuilder.BuilderModes
verts[3] = verts[0]; verts[3] = verts[0];
verts[4] = verts[2]; verts[4] = verts[2];
verts[5] = new WorldVertex(+radius, 0.0f, 0.0f, sectorcolor, 1.0f, 1.0f); 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 // Determine position
Vector3D pos = Thing.Position; Vector3D pos = Thing.Position;
@ -439,10 +452,10 @@ namespace CodeImp.DoomBuilder.BuilderModes
{ {
if(!IsDisposed) if(!IsDisposed)
{ {
if(sprite != null) if(sprites != null) //mxd
{ {
sprite.RemoveReference(); foreach(ImageData sprite in sprites) sprite.RemoveReference();
sprite = null; sprites = null;
} }
base.Dispose(); base.Dispose();
@ -462,11 +475,12 @@ namespace CodeImp.DoomBuilder.BuilderModes
//mxd. When true, the thing can be moved below floor/above ceiling //mxd. When true, the thing can be moved below floor/above ceiling
nointeraction = (info.Actor != null && info.Actor.GetFlagValue("nointeraction", false)); nointeraction = (info.Actor != null && info.Actor.GetFlagValue("nointeraction", false));
// Find sprite texture //mxd. Find sprite textures
if(info.Sprite.Length > 0) sprites = new ImageData[info.SpriteFrame.Length];
for(int i = 0; i < info.SpriteFrame.Length; i++)
{ {
sprite = General.Map.Data.GetSpriteImage(info.Sprite); sprites[i] = General.Map.Data.GetSpriteImage(info.SpriteFrame[i].Sprite);
if(sprite != null) sprite.AddReference(); if(sprites[i] != null) sprites[i].AddReference();
} }
// Setup visual thing // Setup visual thing
@ -478,11 +492,18 @@ namespace CodeImp.DoomBuilder.BuilderModes
{ {
if(!isloaded) if(!isloaded)
{ {
// Rebuild sprite geometry when sprite is loaded //mxd. Rebuild sprite geometry when all sprites are loaded
if(sprite.IsImageLoaded) bool allloaded = true;
foreach(ImageData sprite in sprites)
{ {
Setup(); if(!sprite.IsImageLoaded)
{
allloaded = false;
break;
}
} }
if(allloaded) Setup();
} }
// Let the base update // Let the base update
@ -757,13 +778,14 @@ namespace CodeImp.DoomBuilder.BuilderModes
//mxd //mxd
public void OnChangeScale(int incrementX, int incrementY) 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)) if((General.Map.UndoRedo.NextUndo == null) || (General.Map.UndoRedo.NextUndo.TicketID != undoticket))
undoticket = mode.CreateUndo("Change thing scale"); undoticket = mode.CreateUndo("Change thing scale");
float scaleX = Thing.ScaleX; float scaleX = Thing.ScaleX;
float scaleY = Thing.ScaleY; float scaleY = Thing.ScaleY;
ImageData sprite = sprites[0];
if(incrementX != 0) if(incrementX != 0)
{ {