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.
This commit is contained in:
MaxED 2016-07-13 21:53:48 +00:00
parent ec9c3a71f9
commit 13068b1137
6 changed files with 145 additions and 107 deletions

View file

@ -747,6 +747,12 @@ properties
constants
{
//rendering
FLATSPRITE;
ROLLSPRITE;
WALLSPRITE;
DONTFLIP;
ROLLCENTER;
//pointers
AAPTR_DEFAULT;
AAPTR_NULL;

View file

@ -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))
{

View file

@ -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)
foreach(Sector s in changedsectors)
{
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)
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();
foreach(Vertex v in tocheck)
{
Vertex[] tocheck = { l.Start, l.End };
l.Dispose();
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;
}
}
}

View file

@ -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

View file

@ -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"))
//mxd. Try to get a suitable sprite from our hardcoded states list
foreach(string state in SPRITE_CHECK_STATES)
{
StateStructure s = GetState("idle");
if(!HasState(state)) continue;
StateStructure s = GetState(state);
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"))
{
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");
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

View file

@ -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;