Classic modes: rewritten and optimized some parts of text label rendering logic.

Internal, API: TextLabels can now display multi-line text, their font can be changed, they can have a background.
This commit is contained in:
MaxED 2016-03-30 23:25:03 +00:00 committed by spherallic
parent d09000dc71
commit 1e88de5eba
15 changed files with 344 additions and 873 deletions

View file

@ -1368,9 +1368,7 @@
<SubType>Designer</SubType>
<DependentUpon>ThingsFiltersForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Resources\Font.png" />
<EmbeddedResource Include="Resources\White.png" />
<EmbeddedResource Include="Resources\Font.cfg" />
<EmbeddedResource Include="Windows\UpdateForm.resx">
<DependentUpon>UpdateForm.cs</DependentUpon>
</EmbeddedResource>

View file

@ -2533,12 +2533,6 @@ namespace CodeImp.DoomBuilder
return io.GetType() == t;
}
//mxd
public SizeF GetTextSize(string text, float scale)
{
return graphics.Font.GetTextSize(text, scale);
}
//mxd
[BeginAction("snapvertstogrid")]
private void SnapSelectedMapElementsToGrid()

View file

@ -57,8 +57,6 @@ namespace CodeImp.DoomBuilder.Rendering
private ShaderManager shaders;
private Surface backbuffer;
private Surface depthbuffer;
private TextFont font;
private ResourceImage fonttexture;
// Disposing
private bool isdisposed;
@ -75,8 +73,6 @@ namespace CodeImp.DoomBuilder.Rendering
internal ShaderManager Shaders { get { return shaders; } }
internal Surface BackBuffer { get { return backbuffer; } }
internal Surface DepthBuffer { get { return depthbuffer; } }
internal TextFont Font { get { return font; } }
internal Texture FontTexture { get { return fonttexture.Texture; } }
internal Filter PostFilter { get { return postfilter; } }
internal Filter MipGenerateFilter { get { return mipgeneratefilter; } }
@ -100,18 +96,16 @@ namespace CodeImp.DoomBuilder.Rendering
// Disposer
public void Dispose()
{
// Not already disposed?
if (!isdisposed)
{
// Clean up
foreach (ID3DResource res in resources) res.UnloadResource();
if (shaders != null) shaders.Dispose();
rendertarget = null;
if (backbuffer != null) backbuffer.Dispose();
if (depthbuffer != null) depthbuffer.Dispose();
if (font != null) font.Dispose();
if (fonttexture != null) fonttexture.Dispose();
if (device != null) device.Dispose();
// Not already disposed?
if(!isdisposed)
{
// Clean up
foreach(ID3DResource res in resources) res.UnloadResource();
if(shaders != null) shaders.Dispose();
rendertarget = null;
if(backbuffer != null) backbuffer.Dispose();
if(depthbuffer != null) depthbuffer.Dispose();
if(device != null) device.Dispose();
if (ObjectTable.Objects.Count > 1) //mxd. Direct3D itself is not disposed while the editor is running
{
@ -290,14 +284,6 @@ namespace CodeImp.DoomBuilder.Rendering
// Create shader manager
shaders = new ShaderManager(this);
// Font
postfilter = Filter.Box; // Only for the font. This will be reset in SetupSettings (see below)
font = new TextFont();
fonttexture = new ResourceImage("CodeImp.DoomBuilder.Resources.Font.png");
fonttexture.LoadImage();
fonttexture.MipMapLevels = 2;
fonttexture.CreateTexture();
// Initialize settings
SetupSettings();

View file

@ -76,6 +76,7 @@ namespace CodeImp.DoomBuilder.Rendering
void RenderArrows(ICollection<Line3D> line); //mxd
void RenderArrows(ICollection<Line3D> line, bool transformcoords); //mxd
void RenderText(TextLabel text);
void RenderText(List<TextLabel> labels); //mxd
void RenderGeometry(FlatVertex[] vertices, ImageData texture, bool transformcoords);
void RenderHighlight(FlatVertex[] vertices, int color); //mxd
void RedrawSurface();

View file

@ -208,6 +208,12 @@ namespace CodeImp.DoomBuilder.Rendering
{
return "[A=" + a + ", R=" + r + ", G=" + g + ", B=" + b + "]";
}
//mxd
public bool Equals(PixelColor other)
{
return (r == other.r && g == other.g && b == other.b && a == other.a);
}
#endregion
}

View file

@ -1678,34 +1678,90 @@ namespace CodeImp.DoomBuilder.Rendering
}
// This renders text
public void RenderText(TextLabel text)
public void RenderText(TextLabel label)
{
// Update the text if needed
text.Update(translatex, translatey, scale, -scale);
// Text is created?
if(text.VertexBuffer != null)
{
// Set renderstates for rendering
graphics.Device.SetRenderState(RenderState.CullMode, Cull.None);
graphics.Device.SetRenderState(RenderState.ZEnable, false);
graphics.Device.SetRenderState(RenderState.AlphaBlendEnable, true);
graphics.Device.SetRenderState(RenderState.AlphaTestEnable, false);
graphics.Device.SetRenderState(RenderState.TextureFactor, -1);
graphics.Device.SetRenderState(RenderState.FogEnable, false);
graphics.Shaders.Display2D.Texture1 = graphics.FontTexture;
SetWorldTransformation(false);
graphics.Shaders.Display2D.SetSettings(1f, 1f, 0f, 1f, true);
graphics.Device.SetStreamSource(0, text.VertexBuffer, 0, FlatVertex.Stride);
//mxd. Update the text if needed
RectangleF bbox = label.Update(translatex, translatey, scale, -scale);
// Draw
graphics.Shaders.Display2D.Begin();
graphics.Shaders.Display2D.BeginPass(1); //mxd
//graphics.Device.DrawPrimitives(PrimitiveType.TriangleList, 0, text.NumFaces >> 1); //mxd. Seems to be working fine without this line, soooo...
graphics.Device.DrawPrimitives(PrimitiveType.TriangleList, 0, text.NumFaces);
graphics.Shaders.Display2D.EndPass();
graphics.Shaders.Display2D.End();
//mxd. Have graphics / on screen?
if(label.VertexBuffer == null || (bbox.Right < 0.1f) || (bbox.Left > windowsize.Width) || (bbox.Bottom < 0.1f) || (bbox.Top > windowsize.Height))
return;
// Set renderstates for rendering
graphics.Device.SetRenderState(RenderState.CullMode, Cull.None);
graphics.Device.SetRenderState(RenderState.ZEnable, false);
graphics.Device.SetRenderState(RenderState.AlphaBlendEnable, true);
graphics.Device.SetRenderState(RenderState.AlphaTestEnable, false);
graphics.Device.SetRenderState(RenderState.TextureFactor, -1);
graphics.Device.SetRenderState(RenderState.FogEnable, false);
graphics.Shaders.Display2D.Texture1 = label.Texture;
SetWorldTransformation(false);
graphics.Shaders.Display2D.SetSettings(1f, 1f, 0f, 1f, true);
graphics.Device.SetStreamSource(0, label.VertexBuffer, 0, FlatVertex.Stride);
// Draw
graphics.Shaders.Display2D.Begin();
graphics.Shaders.Display2D.BeginPass(1); //mxd
graphics.Device.DrawPrimitives(PrimitiveType.TriangleStrip, 0, 2);
graphics.Shaders.Display2D.EndPass();
graphics.Shaders.Display2D.End();
}
//mxd. This renders text
public void RenderText(List<TextLabel> labels)
{
// Update labels
int skipped = 0;
foreach(TextLabel label in labels)
{
// Update the text if needed
RectangleF bbox = label.Update(translatex, translatey, scale, -scale);
// Have graphics / on screen?
if(label.VertexBuffer == null || (bbox.Right < 0.1f) || (bbox.Left > windowsize.Width) || (bbox.Bottom < 0.1f) || (bbox.Top > windowsize.Height))
{
label.SkipRendering = true;
skipped++;
}
else
{
label.SkipRendering = false;
}
}
if(labels.Count == skipped) return;
// Set renderstates for rendering
graphics.Device.SetRenderState(RenderState.CullMode, Cull.None);
graphics.Device.SetRenderState(RenderState.ZEnable, false);
graphics.Device.SetRenderState(RenderState.AlphaBlendEnable, true);
graphics.Device.SetRenderState(RenderState.AlphaTestEnable, false);
graphics.Device.SetRenderState(RenderState.TextureFactor, -1);
graphics.Device.SetRenderState(RenderState.FogEnable, false);
SetWorldTransformation(false);
graphics.Shaders.Display2D.SetSettings(1f, 1f, 0f, 1f, true);
// Begin drawing
graphics.Shaders.Display2D.Begin();
graphics.Shaders.Display2D.BeginPass(1);
foreach(TextLabel label in labels)
{
// Text is created?
if(!label.SkipRendering)
{
graphics.Shaders.Display2D.Texture1 = label.Texture;
graphics.Shaders.Display2D.ApplySettings();
graphics.Device.SetStreamSource(0, label.VertexBuffer, 0, FlatVertex.Stride);
// Draw
graphics.Device.DrawPrimitives(PrimitiveType.TriangleStrip, 0, 2);
}
}
// Finish drawing
graphics.Shaders.Display2D.EndPass();
graphics.Shaders.Display2D.End();
}
// This renders a rectangle with given border size and color

View file

@ -13,7 +13,7 @@
*/
#endregion
/*
#region ================== Namespaces
using System;
@ -245,3 +245,4 @@ namespace CodeImp.DoomBuilder.Rendering
#endregion
}
}
*/

View file

@ -17,11 +17,15 @@
#region ================== Namespaces
using System;
using System.Text;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Drawing.Text;
using System.IO;
using System.Drawing;
using SlimDX.Direct3D9;
using SlimDX;
using CodeImp.DoomBuilder.Geometry;
using Font = System.Drawing.Font;
#endregion
@ -37,22 +41,24 @@ namespace CodeImp.DoomBuilder.Rendering
// The text is stored as a polygon in a vertex buffer
private VertexBuffer textbuffer;
private int numfaces;
private int capacity;
private Texture texture;
private Font font; //mxd
// Text settings
private string text;
private RectangleF rect;
private RectangleF absview; //mxd
private bool transformcoords;
private PixelColor color;
private PixelColor backcolor;
private float scale;
private TextAlignmentX alignx;
private TextAlignmentY aligny;
private SizeF size;
private SizeF textsize;
private bool drawbg; //mxd
// This keeps track if changes were made
private bool updateneeded;
private bool textureupdateneeded; //mxd
private float lasttranslatex = float.MinValue;
private float lasttranslatey;
private float lastscalex;
@ -73,16 +79,18 @@ namespace CodeImp.DoomBuilder.Rendering
public float Height { get { return rect.Height; } set { rect.Height = value; updateneeded = true; } }
public float Right { get { return rect.Right; } set { rect.Width = value - rect.X + 1f; updateneeded = true; } }
public float Bottom { get { return rect.Bottom; } set { rect.Height = value - rect.Y + 1f; updateneeded = true; } }
public string Text { get { return text; } set { if(text != value.ToUpperInvariant()) { text = value.ToUpperInvariant(); updateneeded = true; } } }
public string Text { get { return text; } set { if(text != value) { text = value; textureupdateneeded = true; } } }
public Font Font { get { return font; } set { font = value; textureupdateneeded = true; } } //mxd
public bool TransformCoords { get { return transformcoords; } set { transformcoords = value; updateneeded = true; } }
public SizeF TextSize { get { return size; } }
public float Scale { get { return scale; } set { scale = value; updateneeded = true; } }
public SizeF TextSize { get { return textsize; } }
public TextAlignmentX AlignX { get { return alignx; } set { alignx = value; updateneeded = true; } }
public TextAlignmentY AlignY { get { return aligny; } set { aligny = value; updateneeded = true; } }
public PixelColor Color { get { return color; } set { color = value; updateneeded = true; } }
public PixelColor Backcolor { get { return backcolor; } set { backcolor = value; updateneeded = true; } }
public PixelColor Color { get { return color; } set { if(!color.Equals(value)) { color = value; textureupdateneeded = true; } } }
public PixelColor Backcolor { get { return backcolor; } set { if(!backcolor.Equals(value)) { backcolor = value; textureupdateneeded = true; } } }
public bool DrawBackground { get { return drawbg; } set { if(drawbg != value) { drawbg = value; textureupdateneeded = true; } } } //mxd
internal Texture Texture { get { return texture; } } //mxd
internal VertexBuffer VertexBuffer { get { return textbuffer; } }
internal int NumFaces { get { return numfaces; } }
internal bool SkipRendering; //mxd
// Disposing
public bool IsDisposed { get { return isdisposed; } }
@ -92,20 +100,19 @@ namespace CodeImp.DoomBuilder.Rendering
#region ================== Constructor / Disposer
// Constructor
public TextLabel(int capacity)
public TextLabel()
{
// Initialize
this.text = "";
this.font = new Font(General.MainWindow.Font.FontFamily, (float)Math.Round(General.MainWindow.Font.SizeInPoints * 1.25f), FontStyle.Regular); //mxd
this.rect = new RectangleF(0f, 0f, 1f, 1f);
this.color = new PixelColor(255, 255, 255, 255);
this.backcolor = new PixelColor(0, 0, 0, 0);
this.scale = 10f;
this.backcolor = new PixelColor(255, 0, 0, 0);
this.alignx = TextAlignmentX.Center;
this.aligny = TextAlignmentY.Top;
this.size = new SizeF(0f, 0f);
this.textsize = new SizeF();
this.updateneeded = true;
this.numfaces = 0;
this.capacity = capacity;
this.textureupdateneeded = true; //mxd
// Register as resource
General.Map.Graphics.RegisterResource(this);
@ -136,46 +143,50 @@ namespace CodeImp.DoomBuilder.Rendering
#region ================== Methods
// This updates the text if needed
internal void Update(float translatex, float translatey, float scalex, float scaley)
internal RectangleF Update(float translatex, float translatey, float scalex, float scaley)
{
// Check if transformation changed and needs to be updated
if(transformcoords)
if(transformcoords && (translatex != lasttranslatex || translatey != lasttranslatey ||
scalex != lastscalex || scaley != lastscaley))
{
if(translatex != lasttranslatex || translatey != lasttranslatey ||
scalex != lastscalex || scaley != lastscaley)
lasttranslatex = translatex; //mxd
lasttranslatey = translatey; //mxd
lastscalex = scalex; //mxd
lastscaley = scaley; //mxd
updateneeded = true;
}
//mxd. Update texture if needed
if(textureupdateneeded)
{
// Get rid of old texture
if(texture != null)
{
lasttranslatex = translatex; //mxd
lasttranslatey = translatey; //mxd
lastscalex = scalex; //mxd
lastscaley = scaley; //mxd
updateneeded = true;
texture.Dispose();
texture = null;
}
// Create label image
Bitmap img = CreateLabelImage(text, font, color, backcolor, drawbg);
textsize = img.Size;
// Create texture
MemoryStream memstream = new MemoryStream((img.Size.Width * img.Size.Height * 4) + 4096);
img.Save(memstream, ImageFormat.Bmp);
memstream.Seek(0, SeekOrigin.Begin);
texture = Texture.FromStream(General.Map.Graphics.Device, memstream, (int)memstream.Length,
img.Size.Width, img.Size.Height, 1, Usage.None, Format.Unknown,
Pool.Managed, General.Map.Graphics.PostFilter, General.Map.Graphics.MipGenerateFilter, 0);
}
// Update if needed
if(updateneeded)
if(updateneeded || textureupdateneeded)
{
// Only build when there are any vertices
if(text.Length > 0)
{
// Do we have to make a new buffer?
if((textbuffer == null) || (text.Length > capacity))
{
// Dispose previous
if(textbuffer != null) textbuffer.Dispose();
// Determine new capacity
if(capacity < text.Length) capacity = text.Length;
// Create the buffer
textbuffer = new VertexBuffer(General.Map.Graphics.Device,
capacity * 12 * FlatVertex.Stride,
Usage.Dynamic | Usage.WriteOnly,
VertexFormat.None, Pool.Default);
}
// Transform?
RectangleF absview;
if(transformcoords)
{
// Calculate absolute coordinates
@ -183,24 +194,21 @@ namespace CodeImp.DoomBuilder.Rendering
Vector2D rb = new Vector2D(rect.Right, rect.Bottom);
lt = lt.GetTransformed(translatex, translatey, scalex, scaley);
rb = rb.GetTransformed(translatex, translatey, scalex, scaley);
absview = new RectangleF(lt.x, lt.y, rb.x - lt.x, rb.y - lt.y);
absview = new RectangleF((float)Math.Round(lt.x), (float)Math.Round(lt.y), rb.x - lt.x, rb.y - lt.y);
}
else
{
// Fixed coordinates
absview = rect;
}
// Calculate text dimensions
size = General.Map.Graphics.Font.GetTextSize(text, scale);
// Align the text horizontally
float beginx = 0;
switch(alignx)
{
case TextAlignmentX.Left: beginx = absview.X; break;
case TextAlignmentX.Center: beginx = absview.X + (absview.Width - size.Width) * 0.5f; break;
case TextAlignmentX.Right: beginx = absview.X + absview.Width - size.Width; break;
case TextAlignmentX.Center: beginx = absview.X + (absview.Width - textsize.Width) * 0.5f; break;
case TextAlignmentX.Right: beginx = absview.X + absview.Width - textsize.Width; break;
}
// Align the text vertically
@ -208,63 +216,149 @@ namespace CodeImp.DoomBuilder.Rendering
switch(aligny)
{
case TextAlignmentY.Top: beginy = absview.Y; break;
case TextAlignmentY.Middle: beginy = absview.Y + (absview.Height - size.Height) * 0.5f; break;
case TextAlignmentY.Bottom: beginy = absview.Y + absview.Height - size.Height; break;
case TextAlignmentY.Middle: beginy = absview.Y + (absview.Height - textsize.Height) * 0.5f; break;
case TextAlignmentY.Bottom: beginy = absview.Y + absview.Height - textsize.Height; break;
}
// Get the ASCII bytes for the text
byte[] textbytes = Encoding.ASCII.GetBytes(text);
// Do we have to make a new buffer?
if(textbuffer == null)
{
// Create the buffer
textbuffer = new VertexBuffer(General.Map.Graphics.Device, 4 * FlatVertex.Stride,
Usage.Dynamic | Usage.WriteOnly, VertexFormat.None, Pool.Default);
}
// Lock the buffer
DataStream stream = textbuffer.Lock(0, capacity * 12 * FlatVertex.Stride,
LockFlags.Discard | LockFlags.NoSystemLock);
// Go for all chars in text to create the backgrounds
float textx = beginx;
foreach(byte b in textbytes)
General.Map.Graphics.Font.SetupVertices(stream, b, scale, backcolor.ToInt(),
ref textx, beginy, size.Height, 0.5f);
// Go for all chars in text to create the text
textx = beginx;
foreach(byte b in textbytes)
General.Map.Graphics.Font.SetupVertices(stream, b, scale, color.ToInt(),
ref textx, beginy, size.Height, 0.0f);
//mxd. Lock the buffer
using(DataStream stream = textbuffer.Lock(0, 4 * FlatVertex.Stride, LockFlags.Discard | LockFlags.NoSystemLock))
{
FlatQuad quad = new FlatQuad(PrimitiveType.TriangleStrip, beginx, beginy, beginx + textsize.Width, beginy + textsize.Height);
stream.WriteRange(quad.Vertices);
}
// Done filling the vertex buffer
textbuffer.Unlock();
stream.Dispose();
// Calculate number of triangles
numfaces = text.Length * 4;
}
else
{
// No faces in polygon
numfaces = 0;
size = new SizeF(0f, 0f);
if(textbuffer != null) textbuffer.Dispose(); //mxd
textsize = new SizeF();
}
// Text updated
updateneeded = false;
textureupdateneeded = false; //mxd
}
return absview; //mxd
}
//mxd
private static Bitmap CreateLabelImage(string text, Font font, PixelColor color, PixelColor backcolor, bool drawbg)
{
PointF textorigin = new PointF(4, 3);
RectangleF textrect = new RectangleF(textorigin, General.Interface.MeasureString(text, font));
textrect.Width = (float)Math.Round(textrect.Width);
textrect.Height = (float)Math.Round(textrect.Height);
RectangleF bgrect = new RectangleF(0, 0, textrect.Width + textorigin.X * 2, textrect.Height + textorigin.Y * 2);
Bitmap result = new Bitmap((int)bgrect.Width, (int)bgrect.Height);
using(Graphics g = Graphics.FromImage(result))
{
g.SmoothingMode = SmoothingMode.HighQuality;
g.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
g.CompositingQuality = CompositingQuality.HighQuality;
// Draw text
using(StringFormat sf = new StringFormat())
{
sf.FormatFlags = StringFormatFlags.NoWrap;
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Center;
// Draw text with BG
if(drawbg)
{
GraphicsPath p = new GraphicsPath();
float radius = textorigin.X;
const float outlinewidth = 1;
RectangleF pathrect = bgrect;
pathrect.Width -= 1;
pathrect.Height -= 1;
// Left line
p.AddLine(pathrect.Left, pathrect.Bottom - radius + outlinewidth, pathrect.Left, pathrect.Top + radius);
p.AddArc(pathrect.Left, pathrect.Top, radius, radius, 180, 90);
// Top line
p.AddLine(pathrect.Left + radius, pathrect.Top, pathrect.Right - radius, pathrect.Top);
p.AddArc(pathrect.Right - radius, pathrect.Top, radius, radius, 270, 90);
// Right line
p.AddLine(pathrect.Right, pathrect.Top + radius, pathrect.Right, pathrect.Bottom - radius);
p.AddArc(pathrect.Right - radius, pathrect.Bottom - radius, radius, radius, 0, 90);
// Bottom line
p.AddLine(pathrect.Left + radius, pathrect.Bottom, pathrect.Left + radius, pathrect.Bottom);
p.AddArc(pathrect.Left, pathrect.Bottom - radius, radius, radius, 90, 90);
// Fill'n'draw bg
using(SolidBrush brush = new SolidBrush(color.ToColor()))
g.FillPath(brush, p);
using(Pen pen = new Pen(backcolor.ToColor(), outlinewidth))
g.DrawPath(pen, p);
// Draw text
using(SolidBrush brush = new SolidBrush(backcolor.ToColor()))
g.DrawString(text, font, brush, textrect, sf);
}
// Draw text with outline
else
{
RectangleF pathrect = textrect;
pathrect.Inflate(1, 3);
GraphicsPath p = new GraphicsPath();
p.AddString(text, font.FontFamily, (int)font.Style, g.DpiY * font.Size / 72f, pathrect, sf);
// Draw'n'fill text
using(Pen pen = new Pen(backcolor.ToColor(), 3))
g.DrawPath(pen, p);
using(SolidBrush brush = new SolidBrush(color.ToColor()))
g.FillPath(brush, p);
}
}
}
return result;
}
// This unloads the resources
public void UnloadResource()
{
// Clean up
if(textbuffer != null) textbuffer.Dispose();
textbuffer = null;
if(textbuffer != null)
{
textbuffer.Dispose();
textbuffer = null;
}
if(texture != null) //mxd
{
texture.Dispose();
texture = null;
}
// Need to update before we can render
updateneeded = true;
textureupdateneeded = true; //mxd
}
// This (re)loads the resources
public void ReloadResource()
{
}
public void ReloadResource() { }
#endregion
}

View file

@ -1,710 +0,0 @@
count = 64;
chars
{
65
{
width = 26;
height = 42;
u1 = 0.011719f;
v1 = -0.003906f;
u2 = 0.078125f;
v2 = 0.195313f;
}
66
{
width = 26;
height = 42;
u1 = 0.082031f;
v1 = -0.003906f;
u2 = 0.148438f;
v2 = 0.195313f;
}
67
{
width = 26;
height = 42;
u1 = 0.152344f;
v1 = -0.003906f;
u2 = 0.21875f;
v2 = 0.195313f;
}
68
{
width = 26;
height = 42;
u1 = 0.222656f;
v1 = -0.003906f;
u2 = 0.289063f;
v2 = 0.195313f;
}
69
{
width = 24;
height = 42;
u1 = 0.292969f;
v1 = -0.003906f;
u2 = 0.355469f;
v2 = 0.195313f;
}
70
{
width = 22;
height = 42;
u1 = 0.359375f;
v1 = -0.003906f;
u2 = 0.417969f;
v2 = 0.195313f;
}
71
{
width = 28;
height = 42;
u1 = 0.421875f;
v1 = -0.003906f;
u2 = 0.492188f;
v2 = 0.195313f;
}
72
{
width = 28;
height = 42;
u1 = 0.496094f;
v1 = -0.003906f;
u2 = 0.566406f;
v2 = 0.195313f;
}
73
{
width = 13;
height = 42;
u1 = 0.570313f;
v1 = -0.003906f;
u2 = 0.611328f;
v2 = 0.195313f;
}
74
{
width = 22;
height = 42;
u1 = 0.615234f;
v1 = -0.003906f;
u2 = 0.673828f;
v2 = 0.195313f;
}
75
{
width = 28;
height = 42;
u1 = 0.677734f;
v1 = -0.003906f;
u2 = 0.748047f;
v2 = 0.195313f;
}
76
{
width = 22;
height = 42;
u1 = 0.751953f;
v1 = -0.003906f;
u2 = 0.810547f;
v2 = 0.195313f;
}
77
{
width = 31;
height = 42;
u1 = 0.814453f;
v1 = -0.003906f;
u2 = 0.890625f;
v2 = 0.195313f;
}
78
{
width = 28;
height = 42;
u1 = 0.894531f;
v1 = -0.003906f;
u2 = 0.964844f;
v2 = 0.195313f;
}
79
{
width = 28;
height = 42;
u1 = 0.011719f;
v1 = 0.183594f;
u2 = 0.082031f;
v2 = 0.382813f;
}
80
{
width = 24;
height = 42;
u1 = 0.085938f;
v1 = 0.183594f;
u2 = 0.148438f;
v2 = 0.382813f;
}
81
{
width = 28;
height = 42;
u1 = 0.152344f;
v1 = 0.183594f;
u2 = 0.222656f;
v2 = 0.382813f;
}
82
{
width = 26;
height = 42;
u1 = 0.226563f;
v1 = 0.183594f;
u2 = 0.292969f;
v2 = 0.382813f;
}
83
{
width = 24;
height = 42;
u1 = 0.296875f;
v1 = 0.183594f;
u2 = 0.359375f;
v2 = 0.382813f;
}
84
{
width = 24;
height = 42;
u1 = 0.363281f;
v1 = 0.183594f;
u2 = 0.425781f;
v2 = 0.382813f;
}
85
{
width = 28;
height = 42;
u1 = 0.429688f;
v1 = 0.183594f;
u2 = 0.5f;
v2 = 0.382813f;
}
86
{
width = 26;
height = 42;
u1 = 0.503906f;
v1 = 0.183594f;
u2 = 0.570313f;
v2 = 0.382813f;
}
87
{
width = 33;
height = 42;
u1 = 0.574219f;
v1 = 0.183594f;
u2 = 0.654297f;
v2 = 0.382813f;
}
88
{
width = 26;
height = 42;
u1 = 0.658203f;
v1 = 0.183594f;
u2 = 0.724609f;
v2 = 0.382813f;
}
89
{
width = 26;
height = 42;
u1 = 0.728516f;
v1 = 0.183594f;
u2 = 0.794922f;
v2 = 0.382813f;
}
90
{
width = 24;
height = 42;
u1 = 0.798828f;
v1 = 0.183594f;
u2 = 0.861328f;
v2 = 0.382813f;
}
48
{
width = 22;
height = 42;
u1 = 0.865234f;
v1 = 0.183594f;
u2 = 0.923828f;
v2 = 0.382813f;
}
49
{
width = 22;
height = 42;
u1 = 0.927734f;
v1 = 0.183594f;
u2 = 0.986328f;
v2 = 0.382813f;
}
50
{
width = 22;
height = 42;
u1 = 0.011719f;
v1 = 0.371094f;
u2 = 0.070313f;
v2 = 0.570313f;
}
51
{
width = 22;
height = 42;
u1 = 0.074219f;
v1 = 0.371094f;
u2 = 0.132813f;
v2 = 0.570313f;
}
52
{
width = 22;
height = 42;
u1 = 0.136719f;
v1 = 0.371094f;
u2 = 0.195313f;
v2 = 0.570313f;
}
53
{
width = 22;
height = 42;
u1 = 0.199219f;
v1 = 0.371094f;
u2 = 0.257813f;
v2 = 0.570313f;
}
54
{
width = 22;
height = 42;
u1 = 0.261719f;
v1 = 0.371094f;
u2 = 0.320313f;
v2 = 0.570313f;
}
55
{
width = 22;
height = 42;
u1 = 0.324219f;
v1 = 0.371094f;
u2 = 0.382813f;
v2 = 0.570313f;
}
56
{
width = 22;
height = 42;
u1 = 0.386719f;
v1 = 0.371094f;
u2 = 0.445313f;
v2 = 0.570313f;
}
57
{
width = 22;
height = 42;
u1 = 0.449219f;
v1 = 0.371094f;
u2 = 0.507813f;
v2 = 0.570313f;
}
32
{
width = 12;
height = 42;
u1 = 0.511719f;
v1 = 0.371094f;
u2 = 0.550781f;
v2 = 0.570313f;
}
33
{
width = 12;
height = 42;
u1 = 0.554688f;
v1 = 0.371094f;
u2 = 0.59375f;
v2 = 0.570313f;
}
64
{
width = 25;
height = 42;
u1 = 0.597656f;
v1 = 0.371094f;
u2 = 0.662109f;
v2 = 0.570313f;
}
35
{
width = 22;
height = 42;
u1 = 0.666016f;
v1 = 0.371094f;
u2 = 0.724609f;
v2 = 0.570313f;
}
36
{
width = 22;
height = 42;
u1 = 0.728516f;
v1 = 0.371094f;
u2 = 0.787109f;
v2 = 0.570313f;
}
37
{
width = 33;
height = 42;
u1 = 0.791016f;
v1 = 0.371094f;
u2 = 0.871094f;
v2 = 0.570313f;
}
94
{
width = 22;
height = 42;
u1 = 0.875f;
v1 = 0.371094f;
u2 = 0.933594f;
v2 = 0.570313f;
}
38
{
width = 29;
height = 42;
u1 = 0.011719f;
v1 = 0.558594f;
u2 = 0.083984f;
v2 = 0.757813f;
}
42
{
width = 19;
height = 42;
u1 = 0.087891f;
v1 = 0.558594f;
u2 = 0.140625f;
v2 = 0.757813f;
}
40
{
width = 13;
height = 42;
u1 = 0.144531f;
v1 = 0.558594f;
u2 = 0.185547f;
v2 = 0.757813f;
}
41
{
width = 13;
height = 42;
u1 = 0.189453f;
v1 = 0.558594f;
u2 = 0.230469f;
v2 = 0.757813f;
}
95
{
width = 17;
height = 42;
u1 = 0.234375f;
v1 = 0.558594f;
u2 = 0.283203f;
v2 = 0.757813f;
}
43
{
width = 22;
height = 42;
u1 = 0.287109f;
v1 = 0.558594f;
u2 = 0.345703f;
v2 = 0.757813f;
}
61
{
width = 22;
height = 42;
u1 = 0.349609f;
v1 = 0.558594f;
u2 = 0.408203f;
v2 = 0.757813f;
}
45
{
width = 12;
height = 42;
u1 = 0.412109f;
v1 = 0.558594f;
u2 = 0.451172f;
v2 = 0.757813f;
}
91
{
width = 13;
height = 42;
u1 = 0.455078f;
v1 = 0.558594f;
u2 = 0.496094f;
v2 = 0.757813f;
}
93
{
width = 13;
height = 42;
u1 = 0.5f;
v1 = 0.558594f;
u2 = 0.541016f;
v2 = 0.757813f;
}
58
{
width = 12;
height = 42;
u1 = 0.544922f;
v1 = 0.558594f;
u2 = 0.583984f;
v2 = 0.757813f;
}
59
{
width = 12;
height = 42;
u1 = 0.587891f;
v1 = 0.558594f;
u2 = 0.626953f;
v2 = 0.757813f;
}
39
{
width = 10;
height = 42;
u1 = 0.630859f;
v1 = 0.558594f;
u2 = 0.666016f;
v2 = 0.757813f;
}
34
{
width = 17;
height = 42;
u1 = 0.669922f;
v1 = 0.558594f;
u2 = 0.71875f;
v2 = 0.757813f;
}
44
{
width = 12;
height = 42;
u1 = 0.722656f;
v1 = 0.558594f;
u2 = 0.761719f;
v2 = 0.757813f;
}
46
{
width = 12;
height = 42;
u1 = 0.765625f;
v1 = 0.558594f;
u2 = 0.804688f;
v2 = 0.757813f;
}
60
{
width = 22;
height = 42;
u1 = 0.808594f;
v1 = 0.558594f;
u2 = 0.867188f;
v2 = 0.757813f;
}
62
{
width = 22;
height = 42;
u1 = 0.871094f;
v1 = 0.558594f;
u2 = 0.929688f;
v2 = 0.757813f;
}
47
{
width = 10;
height = 42;
u1 = 0.933594f;
v1 = 0.558594f;
u2 = 0.96875f;
v2 = 0.757813f;
}
63
{
width = 21;
height = 42;
u1 = 0.011719f;
v1 = 0.746094f;
u2 = 0.068359f;
v2 = 0.945313f;
}
92
{
width = 10;
height = 42;
u1 = 0.072266f;
v1 = 0.746094f;
u2 = 0.107422f;
v2 = 0.945313f;
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

View file

@ -18,6 +18,7 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using CodeImp.DoomBuilder.Map;
using CodeImp.DoomBuilder.Geometry;
@ -76,6 +77,7 @@ namespace CodeImp.DoomBuilder.Windows
void ResumeExclusiveMouseInput();
void SetCursor(Cursor cursor);
void MessageBeep(MessageBeepType type);
SizeF MeasureString(string text, Font font); //mxd
/// <summary>
/// This moves the focus to the editing display.

View file

@ -173,6 +173,9 @@ namespace CodeImp.DoomBuilder.Windows
//mxd
private System.Timers.Timer blinkTimer;
private bool editformopen;
//mxd. Misc drawing
private Graphics graphics;
#endregion
@ -288,6 +291,9 @@ namespace CodeImp.DoomBuilder.Windows
//mxd. Hints
hintsPanel = new HintsPanel();
hintsDocker = new Docker("hints", "Help", hintsPanel);
//mxd. Graphics
graphics = Graphics.FromHwndInternal(windowptr);
}
#endregion
@ -4231,5 +4237,14 @@ namespace CodeImp.DoomBuilder.Windows
}
#endregion
#region ================== Graphics (mxd)
public SizeF MeasureString(string text, Font font)
{
return graphics.MeasureString(text, font);
}
#endregion
}
}

View file

@ -367,7 +367,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
//mxd
[BeginAction("togglehighlight")]
public void ToggleHighlight()
public virtual void ToggleHighlight()
{
BuilderPlug.Me.UseHighlight = !BuilderPlug.Me.UseHighlight;
General.Interface.DisplayStatus(StatusType.Action, "Highlight is now " + (BuilderPlug.Me.UseHighlight ? "ON" : "OFF") + ".");

View file

@ -138,11 +138,12 @@ namespace CodeImp.DoomBuilder.BuilderModes
if(labels != null)
{
// Dispose old labels
foreach(KeyValuePair<Sector, TextLabel[]> lbl in labels)
foreach(TextLabel l in lbl.Value) l.Dispose();
foreach(TextLabel[] lbl in labels.Values)
foreach(TextLabel l in lbl) l.Dispose();
}
// Make text labels for sectors
PixelColor c = (BuilderPlug.Me.UseHighlight ? General.Colors.Highlight : General.Colors.Selection); //mxd
labels = new Dictionary<Sector, TextLabel[]>(General.Map.Map.Sectors.Count);
foreach(Sector s in General.Map.Map.Sectors)
{
@ -151,13 +152,12 @@ namespace CodeImp.DoomBuilder.BuilderModes
for(int i = 0; i < s.Labels.Count; i++)
{
Vector2D v = s.Labels[i].position;
labelarray[i] = new TextLabel(20);
labelarray[i] = new TextLabel();
labelarray[i].TransformCoords = true;
labelarray[i].Rectangle = new RectangleF(v.x, v.y, 0.0f, 0.0f);
labelarray[i].AlignX = TextAlignmentX.Center;
labelarray[i].AlignY = TextAlignmentY.Middle;
labelarray[i].Scale = 14f;
labelarray[i].Color = General.Colors.Highlight.WithAlpha(255);
labelarray[i].Color = c;
labelarray[i].Backcolor = General.Colors.Background.WithAlpha(255);
}
labels.Add(s, labelarray);
@ -192,6 +192,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
if(BuilderPlug.Me.ViewSelectionNumbers)
{
List<TextLabel> torender = new List<TextLabel>(orderedselection.Count);
foreach(Sector s in orderedselection)
{
// Render labels
@ -202,9 +203,10 @@ namespace CodeImp.DoomBuilder.BuilderModes
// 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) torender.Add(l);
}
}
renderer.RenderText(torender);
}
//mxd. Render effect labels
@ -221,9 +223,10 @@ namespace CodeImp.DoomBuilder.BuilderModes
//mxd
private void RenderEffectLabels(Dictionary<Sector, string[]> labelsGroup)
{
List<TextLabel> torender = new List<TextLabel>(labelsGroup.Count);
foreach(KeyValuePair<Sector, string[]> group in labelsGroup)
{
// Render labels
// Pick which text variant to use
TextLabel[] labelarray = labels[group.Key];
for(int i = 0; i < group.Key.Labels.Count; i++)
{
@ -231,10 +234,10 @@ namespace CodeImp.DoomBuilder.BuilderModes
l.Color = General.Colors.InfoLine;
// Render only when enough space for the label to see
float requiredsize = (General.Map.GetTextSize(group.Value[0], l.Scale).Width) / renderer.Scale;
float requiredsize = (General.Interface.MeasureString(group.Value[0], l.Font).Width / 2) / renderer.Scale;
if(requiredsize > group.Key.Labels[i].radius)
{
requiredsize = (General.Map.GetTextSize(group.Value[1], l.Scale).Width) / renderer.Scale;
requiredsize = (General.Interface.MeasureString(group.Value[1], l.Font).Width / 2) / renderer.Scale;
l.Text = (requiredsize > group.Key.Labels[i].radius ? "+" : group.Value[1]);
}
else
@ -242,9 +245,12 @@ namespace CodeImp.DoomBuilder.BuilderModes
l.Text = group.Value[0];
}
renderer.RenderText(l);
torender.Add(l);
}
}
// Render labels
renderer.RenderText(torender);
}
//mxd
@ -286,8 +292,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
string[] result = new[] { string.Empty, string.Empty };
if(s.Effect != 0 && s.Tag != 0)
{
result[0] = tagstr + "; " + effectstr;
result[1] = tagstrshort + " " + effectstrshort;
result[0] = tagstr + Environment.NewLine + effectstr;
result[1] = tagstrshort + Environment.NewLine + effectstrshort;
}
else if(s.Effect != 0)
{
@ -413,14 +419,16 @@ namespace CodeImp.DoomBuilder.BuilderModes
if((highlighted != null) && !highlighted.IsDisposed)
{
TextLabel[] labelarray = labels[highlighted];
foreach(TextLabel l in labelarray) l.Color = General.Colors.Selection;
PixelColor c = (BuilderPlug.Me.UseHighlight ? General.Colors.Highlight : General.Colors.Selection);
foreach(TextLabel l in labelarray) l.Color = c;
}
// Change label color
if((s != null) && !s.IsDisposed)
{
TextLabel[] labelarray = labels[s];
foreach(TextLabel l in labelarray) l.Color = General.Colors.Highlight;
PixelColor c = (BuilderPlug.Me.UseHighlight ? General.Colors.Selection : General.Colors.Highlight);
foreach(TextLabel l in labelarray) l.Color = c;
}
// If we're changing associations, then we
@ -485,11 +493,12 @@ namespace CodeImp.DoomBuilder.BuilderModes
{
//mxd
string selectedCount = General.Map.Map.SelectedSectorsCount.ToString();
PixelColor c = (BuilderPlug.Me.UseHighlight ? General.Colors.Highlight : General.Colors.Selection);
TextLabel[] labelarray = labels[s];
foreach(TextLabel l in labelarray)
{
l.Text = selectedCount;
l.Color = General.Colors.Selection;
l.Color = c;
}
UpdateEffectLabels();
@ -545,6 +554,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
{
// Go for all labels in all selected sectors
ICollection<Sector> orderedselection = General.Map.Map.GetSelectedSectors(true);
PixelColor c = (BuilderPlug.Me.UseHighlight ? General.Colors.Highlight : General.Colors.Selection); //mxd
int index = 0;
foreach(Sector s in orderedselection)
{
@ -554,7 +564,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
// Make sure the text and color are right
int labelnum = index + 1;
l.Text = labelnum.ToString();
l.Color = General.Colors.Selection;
l.Color = c;
}
index++;
}
@ -826,7 +836,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
// Update overlay
TextLabel[] labelarray = labels[highlighted];
foreach(TextLabel l in labelarray) l.Color = General.Colors.Highlight;
PixelColor c = (BuilderPlug.Me.UseHighlight ? General.Colors.Selection : General.Colors.Highlight);
foreach(TextLabel l in labelarray) l.Color = c;
UpdateOverlaySurfaces(); //mxd
UpdateOverlay();
renderer.Present();
@ -1333,6 +1344,26 @@ namespace CodeImp.DoomBuilder.BuilderModes
base.OnRedoEnd(); //mxd
}
//mxd
public override void ToggleHighlight()
{
// Update label colors
PixelColor c = (BuilderPlug.Me.UseHighlight ? General.Colors.Selection : General.Colors.Highlight);
foreach(TextLabel[] labelarray in labels.Values)
foreach(TextLabel l in labelarray) l.Color = c;
// Update highlighted label color
if((highlighted != null) && !highlighted.IsDisposed)
{
TextLabel[] labelarray = labels[highlighted];
c = (BuilderPlug.Me.UseHighlight ? General.Colors.Highlight : General.Colors.Selection);
foreach(TextLabel l in labelarray) l.Color = c;
}
// Pass to base
base.ToggleHighlight();
}
//mxd
private void RenderComment(Sector s)
{

View file

@ -29,8 +29,6 @@ namespace CodeImp.DoomBuilder.BuilderModes
{
#region ================== Constants
private const int TEXT_CAPACITY = 15;
private const float TEXT_SCALE = 14f;
private const string VALUE_FORMAT = "0";
#endregion
@ -105,12 +103,11 @@ namespace CodeImp.DoomBuilder.BuilderModes
// Initialization
private void Initialize()
{
label = new TextLabel(TEXT_CAPACITY);
label = new TextLabel();
label.AlignX = TextAlignmentX.Center;
label.AlignY = TextAlignmentY.Middle;
label.Color = General.Colors.Highlight;
label.Backcolor = General.Colors.Background;
label.Scale = TEXT_SCALE;
label.TransformCoords = true;
}
@ -133,8 +130,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
float length = delta.GetLength();
if(showangle)
{
int displayangle = General.ClampAngle((int)Math.Round(Angle2D.RadToDeg(delta.GetAngle())) - 90);
label.Text = "l:" + length.ToString(VALUE_FORMAT) + "; a:" + displayangle;
int displayangle = General.ClampAngle((int)Math.Round(Angle2D.RadToDeg(delta.GetAngle())));
label.Text = "L:" + length.ToString(VALUE_FORMAT) + "; A:" + displayangle;
}
else
{
@ -194,7 +191,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
{
Vector2D perpendicular = (end - start).GetPerpendicular();
float angle = perpendicular.GetAngle();
SizeF textsize = General.Map.GetTextSize(label.Text, label.Scale);
SizeF textsize = General.Interface.MeasureString(label.Text, label.Font);
float offset = textsize.Width * Math.Abs((float)Math.Sin(angle)) + textsize.Height * Math.Abs((float)Math.Cos(angle));
perpendicular = perpendicular.GetNormal().GetScaled(offset / 2.0f / General.Map.Renderer2D.Scale);
start += perpendicular;