Fixed, DB2 bug: side panel's tabs were drawn incorrectly when panel's height was lower than cumulative tabs height.

Visual mode, GLOOME: wall/floor/ceiling sprites are now rendered closer to the way it's done in GLOOME.
Sectors mode, UDMF: some cosmetic tweaks to comment icons rendering.
Classic modes: linedef rendering is now skipped when it's visible length is very short.
General interface: fixed a possible crash when clicking on the warnings count label when it was updated from the background thread.
This commit is contained in:
MaxED 2015-08-31 22:06:44 +00:00
parent ee719bd943
commit c407c8c351
7 changed files with 193 additions and 205 deletions

View file

@ -429,10 +429,9 @@ namespace CodeImp.DoomBuilder.Config
//mxd. GLOOME rendering flags. ORDER: WALLSPRITE -> FLOORSPRITE || CEILSPRITE
rollsprite = actor.GetFlagValue("rollsprite", false);
//TODO: in GLOOME +WALLSPRITE works only when +ROLLSPRITE is set?
if(rollsprite && actor.GetFlagValue("wallsprite", false)) rendermode = Thing.SpriteRenderMode.WALL_SPRITE;
else if(actor.GetFlagValue("floorsprite", false)) rendermode = Thing.SpriteRenderMode.FLOOR_SPRITE;
else if(actor.GetFlagValue("ceilsprite", false)) rendermode = Thing.SpriteRenderMode.CEILING_SPRITE;
if(actor.GetFlagValue("wallsprite", false)) rendermode = Thing.SpriteRenderMode.WALL_SPRITE;
else if(actor.GetFlagValue("floorsprite", false)) rendermode = Thing.SpriteRenderMode.FLOOR_SPRITE;
else if(actor.GetFlagValue("ceilsprite", false)) rendermode = Thing.SpriteRenderMode.CEILING_SPRITE;
if(rendermode == Thing.SpriteRenderMode.FLOOR_SPRITE || rendermode == Thing.SpriteRenderMode.CEILING_SPRITE)
sticktoplane = actor.GetFlagValue("sticktoplane", false); // Works only for Floor/Ceil sprites

View file

@ -18,10 +18,10 @@
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
using System.Drawing.Imaging;
using System.Drawing.Text;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
#endregion
@ -35,8 +35,8 @@ namespace CodeImp.DoomBuilder.Controls
#region ================== Variables
private Bitmap tabsimage;
private int highlighttab;
private readonly StringFormat stringformat;
#endregion
@ -48,170 +48,95 @@ namespace CodeImp.DoomBuilder.Controls
if(VisualStyleInformation.IsSupportedByOS && VisualStyleInformation.IsEnabledByUser)
{
// Style settings
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
this.SetStyle(ControlStyles.SupportsTransparentBackColor, false);
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.Opaque, true);
this.UpdateStyles();
this.SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.DoubleBuffer, true);
this.DrawMode = TabDrawMode.OwnerDrawFixed;
}
stringformat = new StringFormat {Alignment = StringAlignment.Center, HotkeyPrefix = HotkeyPrefix.None, LineAlignment = StringAlignment.Center};
highlighttab = -1;
}
// Disposer
protected override void Dispose(bool disposing)
{
if(tabsimage != null)
{
tabsimage.Dispose();
tabsimage = null;
}
base.Dispose(disposing);
}
#endregion
#region ================== Methods
// This redraws the tabs
protected unsafe void RedrawTabs()
{
// Determine length and width in pixels
int tabslength = 0;
for(int i = 0; i < this.TabPages.Count; i++)
{
Rectangle r = this.GetTabRect(i);
tabslength += r.Height;
}
tabslength += 4;
int tabswidth = this.ItemSize.Height + 2;
// Dispose old image
if(tabsimage != null)
{
tabsimage.Dispose();
tabsimage = null;
}
if(VisualStyleInformation.IsSupportedByOS && VisualStyleInformation.IsEnabledByUser)
{
StringFormat drawformat = new StringFormat();
drawformat.Alignment = StringAlignment.Center;
drawformat.HotkeyPrefix = HotkeyPrefix.None;
drawformat.LineAlignment = StringAlignment.Center;
// Create images
tabsimage = new Bitmap(tabswidth, tabslength, PixelFormat.Format32bppArgb);
Bitmap drawimage = new Bitmap(tabslength, tabswidth, PixelFormat.Format32bppArgb);
Graphics g = Graphics.FromImage(drawimage);
// Render the tabs (backwards when right-aligned)
int posoffset = 0;
int selectedposoffset = -1;
int start = (this.Alignment == TabAlignment.Left) ? 0 : (this.TabPages.Count - 1);
int end = (this.Alignment == TabAlignment.Left) ? this.TabPages.Count : -1;
int step = (this.Alignment == TabAlignment.Left) ? 1 : -1;
for(int i = start; i != end; i += step)
{
VisualStyleRenderer renderer;
Rectangle tr = this.GetTabRect(i);
// Tab selected?
if(i == this.SelectedIndex)
{
// We will draw this later
selectedposoffset = posoffset;
}
else
{
if(i == highlighttab)
renderer = new VisualStyleRenderer(VisualStyleElement.Tab.TabItem.Hot);
else
renderer = new VisualStyleRenderer(VisualStyleElement.Tab.TabItem.Normal);
// Draw tab
Rectangle r = new Rectangle(posoffset + 2, 2, tr.Height, tr.Width - 2);
renderer.DrawBackground(g, r);
g.DrawString(this.TabPages[i].Text, this.Font, SystemBrushes.ControlText, new RectangleF(r.Location, r.Size), drawformat);
}
posoffset += tr.Height;
}
// Render the selected tab, because it is slightly larger and overlapping the others
if(selectedposoffset > -1)
{
VisualStyleRenderer renderer = new VisualStyleRenderer(VisualStyleElement.Tab.TabItem.Pressed);
Rectangle tr = this.GetTabRect(this.SelectedIndex);
Rectangle r = new Rectangle(selectedposoffset, 0, tr.Height + 4, tr.Width);
renderer.DrawBackground(g, r);
g.DrawString(this.TabPages[this.SelectedIndex].Text, this.Font, SystemBrushes.ControlText, new RectangleF(r.X, r.Y, r.Width, r.Height - 2), drawformat);
}
// Rotate the image and copy to tabsimage
BitmapData drawndata = drawimage.LockBits(new Rectangle(0, 0, drawimage.Size.Width, drawimage.Size.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
BitmapData targetdata = tabsimage.LockBits(new Rectangle(0, 0, tabsimage.Size.Width, tabsimage.Size.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
int* dd = (int*)drawndata.Scan0.ToPointer();
int* td = (int*)targetdata.Scan0.ToPointer();
if(this.Alignment == TabAlignment.Right)
{
for(int y = 0; y < drawndata.Height; y++)
{
for(int x = 0; x < drawndata.Width; x++)
{
td[(drawndata.Width - 1 - x) * targetdata.Width + y] = *dd;
dd++;
}
}
}
else
{
for(int y = 0; y < drawndata.Height; y++)
{
for(int x = 0; x < drawndata.Width; x++)
{
td[x * targetdata.Width + (drawndata.Height - 1 - y)] = *dd;
dd++;
}
}
}
drawimage.UnlockBits(drawndata);
tabsimage.UnlockBits(targetdata);
// Clean up
g.Dispose();
drawimage.Dispose();
//mxd
private void DrawTab(Graphics graphics, int index)
{
Rectangle bounds = this.GetTabRect(index);
VisualStyleRenderer renderer;
bool selected = (index == this.SelectedIndex);
// Transform bounds?
switch(this.Alignment)
{
case TabAlignment.Right:
bounds = new Rectangle((selected ? bounds.X - 1 : bounds.X + 1), bounds.Y, bounds.Height, bounds.Width);
break;
case TabAlignment.Left:
bounds = new Rectangle(bounds.X, bounds.Y, bounds.Height, bounds.Width);
break;
default:
if(selected) bounds.Y -= 2;
break;
}
if(selected)
{
bounds.Height += 2;
renderer = new VisualStyleRenderer(VisualStyleElement.Tab.TabItem.Pressed);
}
else
{
renderer = new VisualStyleRenderer(index == highlighttab ? VisualStyleElement.Tab.TabItem.Hot : VisualStyleElement.Tab.TabItem.Normal);
}
Bitmap drawimage = new Bitmap(bounds.Width, bounds.Height, PixelFormat.Format32bppArgb);
// Draw tab
using(Graphics g = Graphics.FromImage(drawimage))
{
Rectangle bgbounds = new Rectangle(0, 0, bounds.Width, bounds.Height + 1);
bgbounds.Inflate(-1, 0);
renderer.DrawBackground(g, bgbounds);
g.DrawString(this.TabPages[index].Text, this.Font, SystemBrushes.ControlText, new RectangleF(bgbounds.Location, bounds.Size), stringformat);
}
// Rotate image?
switch(this.Alignment)
{
case TabAlignment.Right:
drawimage.RotateFlip(RotateFlipType.Rotate270FlipNone);
break;
case TabAlignment.Left:
drawimage.RotateFlip(RotateFlipType.Rotate90FlipNone);
break;
}
graphics.DrawImage(drawimage, bounds.X, bounds.Y);
}
#endregion
#region ================== Events
// Redrawing needed
//mxd. Redrawing needed
protected override void OnPaint(PaintEventArgs e)
{
if(VisualStyleInformation.IsSupportedByOS && VisualStyleInformation.IsEnabledByUser)
{
RedrawTabs();
e.Graphics.Clear(SystemColors.Control);
// Draw tabs
for(int i = 0; i < this.TabPages.Count; i++)
{
if(i == this.SelectedIndex) continue;
DrawTab(e.Graphics, i);
}
Point p;
if(this.Alignment == TabAlignment.Left)
{
p = new Point(0, 0);
}
else
{
int left = this.ClientSize.Width - tabsimage.Size.Width;
if(left < 0) left = 0;
p = new Point(left, 0);
}
e.Graphics.DrawImage(tabsimage, p);
// Draw selected tab
if(this.SelectedIndex != -1) DrawTab(e.Graphics, this.SelectedIndex);
}
else
{

View file

@ -113,6 +113,8 @@ namespace CodeImp.DoomBuilder.Rendering
private float translatex;
private float translatey;
private float linenormalsize;
private float minlinelength; //mxd. Linedef should be longer than this to be rendered
private float minlinenormallength; //mxd. Linedef direction indicator should be longer than this to be rendered
private float lastgridscale = -1f;
private int lastgridsize;
private float lastgridx;
@ -513,6 +515,8 @@ namespace CodeImp.DoomBuilder.Rendering
translatex = -offsetx + (windowsize.Width * 0.5f) * scaleinv;
translatey = -offsety - (windowsize.Height * 0.5f) * scaleinv;
linenormalsize = 10f * scaleinv;
minlinelength = linenormalsize * 0.0625f; //mxd
minlinenormallength = linenormalsize * 2f; //mxd
vertexsize = (int)(1.7f * General.Settings.GZVertexScale2D * scale + 0.5f); //mxd. added GZVertexScale2D
if(vertexsize < 0) vertexsize = 0;
@ -1875,6 +1879,9 @@ namespace CodeImp.DoomBuilder.Rendering
// Transform coordinates
Vector2D v1 = start.GetTransformed(translatex, translatey, scale, -scale);
Vector2D v2 = end.GetTransformed(translatex, translatey, scale, -scale);
//mxd. Should we bother?
if((v2 - v1).GetLengthSq() < linenormalsize * 0.0625f) return;
// Draw line
plotter.DrawLineSolid((int)v1.x, (int)v1.y, (int)v2.x, (int)v2.y, ref c);
@ -1886,6 +1893,10 @@ namespace CodeImp.DoomBuilder.Rendering
// Transform vertex coordinates
Vector2D v1 = l.Start.Position.GetTransformed(translatex, translatey, scale, -scale);
Vector2D v2 = l.End.Position.GetTransformed(translatex, translatey, scale, -scale);
//mxd. Should we bother?
float lengthsq = (v2 - v1).GetLengthSq();
if(lengthsq < minlinelength) return; //mxd
// Draw line. mxd: added 3d-floor indication
if(l.ExtraFloorFlag && General.Settings.GZMarkExtraFloors)
@ -1893,6 +1904,9 @@ namespace CodeImp.DoomBuilder.Rendering
else
plotter.DrawLineSolid((int)v1.x, (int)v1.y, (int)v2.x, (int)v2.y, ref c);
//mxd. Should we bother?
if(lengthsq < minlinenormallength) return; //mxd
// Calculate normal indicator
float mx = (v2.x - v1.x) * 0.5f;
float my = (v2.y - v1.y) * 0.5f;
@ -1907,7 +1921,37 @@ namespace CodeImp.DoomBuilder.Rendering
public void PlotLinedefSet(ICollection<Linedef> linedefs)
{
// Go for all linedefs
foreach(Linedef l in linedefs) PlotLinedef(l, DetermineLinedefColor(l));
foreach(Linedef l in linedefs)
{
// Transform vertex coordinates
Vector2D v1 = l.Start.Position.GetTransformed(translatex, translatey, scale, -scale);
Vector2D v2 = l.End.Position.GetTransformed(translatex, translatey, scale, -scale);
//mxd. Should we bother?
float lengthsq = (v2 - v1).GetLengthSq();
if(lengthsq < minlinelength) continue; //mxd
// Determine color
PixelColor c = DetermineLinedefColor(l);
// Draw line. mxd: added 3d-floor indication
if(l.ExtraFloorFlag && General.Settings.GZMarkExtraFloors)
plotter.DrawLine3DFloor(v1, v2, ref c, General.Colors.ThreeDFloor);
else
plotter.DrawLineSolid((int)v1.x, (int)v1.y, (int)v2.x, (int)v2.y, ref c);
//mxd. Should we bother?
if(lengthsq < minlinenormallength) continue; //mxd
// Calculate normal indicator
float mx = (v2.x - v1.x) * 0.5f;
float my = (v2.y - v1.y) * 0.5f;
// Draw normal indicator
plotter.DrawLineSolid((int)(v1.x + mx), (int)(v1.y + my),
(int)((v1.x + mx) - (my * l.LengthInv) * linenormalsize),
(int)((v1.y + my) + (mx * l.LengthInv) * linenormalsize), ref c);
}
}
// This renders a single vertex

View file

@ -274,11 +274,13 @@ namespace CodeImp.DoomBuilder.VisualModes
updategeo = true;
//mxd. Do some GLOOME shenanigans...
int localcenterz = (int)(Thing.Height / 2);
if(triangles < 2) return;
float localcenterz = vertices[1].z * 0.5f;
Matrix m;
switch(info.RenderMode)
{
// Appied only when ROLLSPRITE flag is set (?)
// 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++)
@ -291,9 +293,12 @@ namespace CodeImp.DoomBuilder.VisualModes
break;
case Thing.SpriteRenderMode.FLOOR_SPRITE:
// TODO: thing angle is involved in this... somehow
Matrix floorrotation = (info.RollSprite ? Matrix.RotationY(Thing.RollRad) * Matrix.RotationX(Angle2D.PIHALF) : Matrix.RotationX(Angle2D.PIHALF));
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);
@ -303,7 +308,8 @@ namespace CodeImp.DoomBuilder.VisualModes
}
// TODO: this won't work on things with AbsoluteZ flag
if(info.StickToPlane)
// TODO: +ROLLSPRITE implies +STICKTOPLANE?
if(info.StickToPlane || info.RollSprite)
{
// Calculate vertical offset
float floorz = floor.GetZ(Thing.Position);
@ -330,9 +336,12 @@ namespace CodeImp.DoomBuilder.VisualModes
break;
case Thing.SpriteRenderMode.CEILING_SPRITE:
// TODO: thing angle is involved in this... somehow
Matrix ceilrotation = (info.RollSprite ? Matrix.RotationY(Thing.RollRad) * Matrix.RotationX(-Angle2D.PIHALF) : Matrix.RotationX(-Angle2D.PIHALF));
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.Length; i++)
{
Vector4 transformed = Vector3.Transform(new Vector3(vertices[i].x, vertices[i].y, vertices[i].z), m);
@ -342,7 +351,8 @@ namespace CodeImp.DoomBuilder.VisualModes
}
// TODO: this won't work on things with AbsoluteZ flag
if(info.StickToPlane)
// TODO: +ROLLSPRITE implies +STICKTOPLANE?
if(info.StickToPlane || info.RollSprite)
{
// Calculate vertical offset
float floorz = floor.GetZ(Thing.Position);

View file

@ -3929,11 +3929,31 @@ namespace CodeImp.DoomBuilder.Windows
}
//mxd. Warnings panel
private delegate void SetWarningsCountCallback(int count, bool blink);
internal void SetWarningsCount(int count, bool blink)
{
if(this.InvokeRequired)
{
SetWarningsCountCallback d = SetWarningsCount;
this.Invoke(d, new object[] { count, blink });
return;
}
// Start annoying blinking!
if(blink)
{
if(!blinkTimer.Enabled) blinkTimer.Start();
}
else
{
blinkTimer.Stop();
warnsLabel.BackColor = SystemColors.Control;
}
// Update icon
if(count > 0)
{
if (warnsLabel.Image != Resources.Warning) warnsLabel.Image = Resources.Warning;
warnsLabel.Image = Resources.Warning;
}
else
{
@ -3941,18 +3961,8 @@ namespace CodeImp.DoomBuilder.Windows
warnsLabel.BackColor = SystemColors.Control;
}
// Update errors count
warnsLabel.Text = count.ToString();
//start annoying blinking!
if (blink)
{
if(!blinkTimer.Enabled) blinkTimer.Start();
}
else
{
blinkTimer.Stop();
warnsLabel.BackColor = SystemColors.Control;
}
}
//mxd. Bliks warnings indicator

View file

@ -179,7 +179,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
ICollection<Sector> orderedselection = General.Map.Map.GetSelectedSectors(true);
//mxd. Render selected sectors
if (BuilderPlug.Me.UseHighlight)
if(BuilderPlug.Me.UseHighlight)
{
renderer.RenderHighlight(overlayGeometry, General.Colors.Selection.WithAlpha(64).ToInt());
}
@ -190,32 +190,35 @@ namespace CodeImp.DoomBuilder.BuilderModes
renderer.RenderHighlight(highlighted.FlatVertices, General.Colors.Highlight.WithAlpha(64).ToInt());
}
if (BuilderPlug.Me.ViewSelectionNumbers)
//mxd. Render comments
if(General.Map.UDMF && General.Settings.RenderComments)
{
foreach (Sector s in orderedselection)
foreach(Sector s in General.Map.Map.Sectors) RenderComment(s);
}
if(BuilderPlug.Me.ViewSelectionNumbers)
{
foreach(Sector s in orderedselection)
{
// Render labels
TextLabel[] labelarray = labels[s];
for (int i = 0; i < s.Labels.Count; i++)
for(int i = 0; i < s.Labels.Count; i++)
{
TextLabel l = labelarray[i];
// Render only when enough space for the label to see
float requiredsize = (l.TextSize.Height / 2) / renderer.Scale;
if (requiredsize < s.Labels[i].radius) renderer.RenderText(l);
if(requiredsize < s.Labels[i].radius) renderer.RenderText(l);
}
}
}
//mxd. Render effect labels
if (BuilderPlug.Me.ViewSelectionEffects)
if(BuilderPlug.Me.ViewSelectionEffects)
{
if(!BuilderPlug.Me.ViewSelectionNumbers) RenderEffectLabels(selectedEffectLabels);
RenderEffectLabels(unselectedEffectLabels);
}
//mxd. Render comments
if(General.Map.UDMF && General.Settings.RenderComments) foreach(Sector s in General.Map.Map.Sectors) RenderComment(s);
renderer.Finish();
}
@ -437,7 +440,6 @@ namespace CodeImp.DoomBuilder.BuilderModes
else
{
// Update display
Sector possiblecommentsector = s ?? highlighted; //mxd
if(renderer.StartPlotter(false))
{
// Undraw previous highlight
@ -456,16 +458,6 @@ namespace CodeImp.DoomBuilder.BuilderModes
}
UpdateOverlay();
//mxd. Update comment highlight?
if(General.Map.UDMF && General.Settings.RenderComments
&& possiblecommentsector != null && !possiblecommentsector.IsDisposed
&& renderer.StartOverlay(false))
{
RenderComment(possiblecommentsector);
renderer.Finish();
}
renderer.Present();
}
@ -1348,22 +1340,29 @@ namespace CodeImp.DoomBuilder.BuilderModes
//mxd
private void RenderComment(Sector s)
{
if(s.Fields.ContainsKey("comment"))
{
int iconindex = 0;
string comment = s.Fields.GetValue("comment", string.Empty);
if(comment.Length > 2)
{
string type = comment.Substring(0, 3);
int index = Array.IndexOf(CommentType.Types, type);
if(index != -1) iconindex = index;
}
if(s.Selected || !s.Fields.ContainsKey("comment")) return;
Vector2D center = new Vector2D(s.BBox.Left + s.BBox.Width / 2, s.BBox.Top + s.BBox.Height / 2);
RectangleF rect = new RectangleF(center.x - 8 / renderer.Scale, center.y + 16 * renderer.Scale + 16 / renderer.Scale, 16 / renderer.Scale, -16 / renderer.Scale);
PixelColor c = (s == highlighted ? General.Colors.Highlight : (s.Selected ? General.Colors.Selection : PixelColor.FromColor(Color.White)));
renderer.RenderRectangleFilled(rect, c, true, General.Map.Data.CommentTextures[iconindex]);
int iconindex = 0;
string comment = s.Fields.GetValue("comment", string.Empty);
if(comment.Length > 2)
{
string type = comment.Substring(0, 3);
int index = Array.IndexOf(CommentType.Types, type);
if(index != -1) iconindex = index;
}
if(s.Labels.Count > 0)
foreach(LabelPositionInfo info in s.Labels) RenderComment(s, info.position, iconindex);
else
RenderComment(s, new Vector2D(s.BBox.Left + s.BBox.Width / 2, s.BBox.Top + s.BBox.Height / 2), iconindex);
}
//mxd
private void RenderComment(Sector s, Vector2D center, int iconindex)
{
RectangleF rect = new RectangleF(center.x - 8 / renderer.Scale, center.y + 8 / renderer.Scale, 16 / renderer.Scale, -16 / renderer.Scale);
PixelColor c = (s == highlighted ? General.Colors.Highlight : PixelColor.FromColor(Color.White));
renderer.RenderRectangleFilled(rect, c, true, General.Map.Data.CommentTextures[iconindex]);
}
#endregion

View file

@ -866,6 +866,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
}
}
// ========== mxd. Glowing flats ==========
if(General.Map.Data.GlowingFlats.ContainsKey(s.LongFloorTexture) || General.Map.Data.GlowingFlats.ContainsKey(s.LongCeilTexture))
{
SectorData sd = GetSectorData(s);