This repository has been archived on 2023-07-11. You can view files and clone it, but cannot push or open issues or pull requests.
gwen-dotnet/Gwen/Renderer/Base.cs

440 lines
14 KiB
C#

using System;
//using System.Drawing;
using System.IO;
namespace Gwen.Renderer
{
/// <summary>
/// Base renderer.
/// </summary>
public class Base : IDisposable
{
//public Random rnd;
private Point m_RenderOffset;
private Rectangle m_ClipRegion;
//protected ICacheToTexture m_RTT;
public float Scale { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="Base"/> class.
/// </summary>
protected Base()
{
//rnd = new Random();
m_RenderOffset = Point.Empty;
Scale = 1.0f;
if (CTT != null)
CTT.Initialize();
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
/// <filterpriority>2</filterpriority>
public virtual void Dispose()
{
if (CTT != null)
CTT.ShutDown();
GC.SuppressFinalize(this);
}
#if DEBUG
~Base()
{
throw new InvalidOperationException(String.Format("IDisposable object finalized: {0}", GetType()));
//Debug.Print(String.Format("IDisposable object finalized: {0}", GetType()));
}
#endif
/// <summary>
/// Starts rendering.
/// </summary>
public virtual void Begin()
{}
/// <summary>
/// Stops rendering.
/// </summary>
public virtual void End()
{}
/// <summary>
/// Gets or sets the current drawing color.
/// </summary>
public virtual Color DrawColor { get; set; }
/// <summary>
/// Rendering offset. No need to touch it usually.
/// </summary>
public Point RenderOffset { get { return m_RenderOffset; } set { m_RenderOffset = value; } }
/// <summary>
/// Clipping rectangle.
/// </summary>
public Rectangle ClipRegion { get { return m_ClipRegion; } set { m_ClipRegion = value; } }
/// <summary>
/// Indicates whether the clip region is visible.
/// </summary>
public bool ClipRegionVisible
{
get
{
if (m_ClipRegion.Width <= 0 || m_ClipRegion.Height <= 0)
return false;
return true;
}
}
/// <summary>
/// Draws a line.
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <param name="a"></param>
/// <param name="b"></param>
public virtual void DrawLine(int x, int y, int a, int b)
{}
/// <summary>
/// Draws a solid filled rectangle.
/// </summary>
/// <param name="rect"></param>
public virtual void DrawFilledRect(Rectangle rect)
{}
/// <summary>
/// Starts clipping to the current clipping rectangle.
/// </summary>
public virtual void StartClip()
{}
/// <summary>
/// Stops clipping.
/// </summary>
public virtual void EndClip()
{}
/// <summary>
/// Loads the specified texture.
/// </summary>
/// <param name="t"></param>
public virtual void LoadTexture(Texture t)
{}
/// <summary>
/// Initializes texture from raw pixel data.
/// </summary>
/// <param name="t">Texture to initialize. Dimensions need to be set.</param>
/// <param name="pixelData">Pixel data in RGBA format.</param>
public virtual void LoadTextureRaw(Texture t, byte[] pixelData)
{}
/// <summary>
/// Initializes texture from image file data.
/// </summary>
/// <param name="t">Texture to initialize.</param>
/// <param name="data">Image file as stream.</param>
public virtual void LoadTextureStream(Texture t, Stream data)
{}
/// <summary>
/// Frees the specified texture.
/// </summary>
/// <param name="t">Texture to free.</param>
public virtual void FreeTexture(Texture t)
{}
/// <summary>
/// Draws textured rectangle.
/// </summary>
/// <param name="t">Texture to use.</param>
/// <param name="targetRect">Rectangle bounds.</param>
/// <param name="u1">Texture coordinate u1.</param>
/// <param name="v1">Texture coordinate v1.</param>
/// <param name="u2">Texture coordinate u2.</param>
/// <param name="v2">Texture coordinate v2.</param>
public virtual void DrawTexturedRect(Texture t, Rectangle targetRect, float u1=0, float v1=0, float u2=1, float v2=1)
{}
/// <summary>
/// Draws "missing image" default texture.
/// </summary>
/// <param name="rect">Target rectangle.</param>
public virtual void DrawMissingImage(Rectangle rect)
{
//DrawColor = Color.FromArgb(255, rnd.Next(0,255), rnd.Next(0,255), rnd.Next(0, 255));
DrawColor = Color.Red;
DrawFilledRect(rect);
}
/// <summary>
/// Cache to texture provider.
/// </summary>
public virtual ICacheToTexture CTT { get { return null; } }
/// <summary>
/// Loads the specified font.
/// </summary>
/// <param name="font">Font to load.</param>
/// <returns>True if succeeded.</returns>
public virtual bool LoadFont(Font font)
{
return false;
}
/// <summary>
/// Frees the specified font.
/// </summary>
/// <param name="font">Font to free.</param>
public virtual void FreeFont(Font font)
{}
/// <summary>
/// Returns dimensions of the text using specified font.
/// </summary>
/// <param name="font">Font to use.</param>
/// <param name="text">Text to measure.</param>
/// <returns>Width and height of the rendered text.</returns>
public virtual Point MeasureText(Font font, String text)
{
Point p = new Point((int)(font.Size * Scale * text.Length * 0.4f), (int)(font.Size * Scale));
return p;
}
/// <summary>
/// Renders text using specified font.
/// </summary>
/// <param name="font">Font to use.</param>
/// <param name="position">Top-left corner of the text.</param>
/// <param name="text">Text to render.</param>
public virtual void RenderText(Font font, Point position, String text)
{
float size = font.Size * Scale;
for ( int i=0; i<text.Length; i++ )
{
char chr = text[i];
if ( chr == ' ' )
continue;
Rectangle r = Util.FloatRect(position.X + i * size * 0.4f, position.Y, size * 0.4f - 1, size);
/*
This isn't important, it's just me messing around changing the
shape of the rect based on the letter.. just for fun.
*/
if ( chr == 'l' || chr == 'i' || chr == '!' || chr == 't' )
{
r.Width = 1;
}
else if ( chr >= 'a' && chr <= 'z' )
{
r.Y = (int)(r.Y + size * 0.5f);
r.Height = (int)(r.Height - size * 0.4f);
}
else if ( chr == '.' || chr == ',' )
{
r.X += 2;
r.Y += r.Height - 2;
r.Width = 2;
r.Height = 2;
}
else if ( chr == '\'' || chr == '`' || chr == '"' )
{
r.X += 3;
r.Width = 2;
r.Height = 2;
}
if ( chr == 'o' || chr == 'O' || chr == '0' )
DrawLinedRect( r );
else
DrawFilledRect( r );
}
}
//
// No need to implement these functions in your derived class, but if
// you can do them faster than the default implementation it's a good idea to.
//
/// <summary>
/// Draws a lined rectangle. Used for keyboard focus overlay.
/// </summary>
/// <param name="rect">Target rectangle.</param>
public virtual void DrawLinedRect(Rectangle rect)
{
DrawFilledRect(new Rectangle(rect.X, rect.Y, rect.Width, 1));
DrawFilledRect(new Rectangle(rect.X, rect.Y + rect.Height - 1, rect.Width, 1));
DrawFilledRect(new Rectangle(rect.X, rect.Y, 1, rect.Height));
DrawFilledRect(new Rectangle(rect.X + rect.Width - 1, rect.Y, 1, rect.Height));
}
/// <summary>
/// Draws a single pixel. Very slow, do not use. :P
/// </summary>
/// <param name="x">X.</param>
/// <param name="y">Y.</param>
public virtual void DrawPixel(int x, int y)
{
// [omeg] amazing ;)
DrawFilledRect(new Rectangle(x, y, 1, 1));
}
/// <summary>
/// Gets pixel color of a specified texture. Slow.
/// </summary>
/// <param name="texture">Texture.</param>
/// <param name="x">X.</param>
/// <param name="y">Y.</param>
/// <returns>Pixel color.</returns>
public virtual Color PixelColor(Texture texture, uint x, uint y)
{
return PixelColor(texture, x, y, Color.White);
}
/// <summary>
/// Gets pixel color of a specified texture, returning default if otherwise failed. Slow.
/// </summary>
/// <param name="texture">Texture.</param>
/// <param name="x">X.</param>
/// <param name="y">Y.</param>
/// <param name="defaultColor">Color to return on failure.</param>
/// <returns>Pixel color.</returns>
public virtual Color PixelColor(Texture texture, uint x, uint y, Color defaultColor)
{
return defaultColor;
}
/// <summary>
/// Draws a round-corner rectangle.
/// </summary>
/// <param name="rect">Target rectangle.</param>
/// <param name="slight"></param>
public virtual void DrawShavedCornerRect(Rectangle rect, bool slight = false)
{
// Draw INSIDE the w/h.
rect.Width -= 1;
rect.Height -= 1;
if (slight)
{
DrawFilledRect(new Rectangle(rect.X + 1, rect.Y, rect.Width - 1, 1));
DrawFilledRect(new Rectangle(rect.X + 1, rect.Y + rect.Height, rect.Width - 1, 1));
DrawFilledRect(new Rectangle(rect.X, rect.Y + 1, 1, rect.Height - 1));
DrawFilledRect(new Rectangle(rect.X + rect.Width, rect.Y + 1, 1, rect.Height - 1));
return;
}
DrawPixel(rect.X + 1, rect.Y + 1);
DrawPixel(rect.X + rect.Width - 1, rect.Y + 1);
DrawPixel(rect.X + 1, rect.Y + rect.Height - 1);
DrawPixel(rect.X + rect.Width - 1, rect.Y + rect.Height - 1);
DrawFilledRect(new Rectangle(rect.X + 2, rect.Y, rect.Width - 3, 1));
DrawFilledRect(new Rectangle(rect.X + 2, rect.Y + rect.Height, rect.Width - 3, 1));
DrawFilledRect(new Rectangle(rect.X, rect.Y + 2, 1, rect.Height - 3));
DrawFilledRect(new Rectangle(rect.X + rect.Width, rect.Y + 2, 1, rect.Height - 3));
}
private int TranslateX(int x)
{
int x1 = x + m_RenderOffset.X;
return Util.Ceil(x1 * Scale);
}
private int TranslateY(int y)
{
int y1 = y + m_RenderOffset.Y;
return Util.Ceil(y1 * Scale);
}
/// <summary>
/// Translates a panel's local drawing coordinate into view space, taking offsets into account.
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
public void Translate(ref int x, ref int y)
{
x += m_RenderOffset.X;
y += m_RenderOffset.Y;
x = Util.Ceil(x * Scale);
y = Util.Ceil(y * Scale);
}
/// <summary>
/// Translates a panel's local drawing coordinate into view space, taking offsets into account.
/// </summary>
public Point Translate(Point p)
{
int x = p.X;
int y = p.Y;
Translate(ref x, ref y);
return new Point(x, y);
}
/// <summary>
/// Translates a panel's local drawing coordinate into view space, taking offsets into account.
/// </summary>
public Rectangle Translate(Rectangle rect)
{
return new Rectangle(TranslateX(rect.X), TranslateY(rect.Y), Util.Ceil(rect.Width * Scale), Util.Ceil(rect.Height * Scale));
}
/// <summary>
/// Adds a point to the render offset.
/// </summary>
/// <param name="offset">Point to add.</param>
public void AddRenderOffset(Rectangle offset)
{
m_RenderOffset = new Point(m_RenderOffset.X + offset.X, m_RenderOffset.Y + offset.Y);
}
/// <summary>
/// Adds a rectangle to the clipping region.
/// </summary>
/// <param name="rect">Rectangle to add.</param>
public void AddClipRegion(Rectangle rect)
{
rect.X = m_RenderOffset.X;
rect.Y = m_RenderOffset.Y;
Rectangle r = rect;
if (rect.X < m_ClipRegion.X)
{
r.Width -= (m_ClipRegion.X - r.X);
r.X = m_ClipRegion.X;
}
if (rect.Y < m_ClipRegion.Y)
{
r.Height -= (m_ClipRegion.Y - r.Y);
r.Y = m_ClipRegion.Y;
}
if (rect.Right > m_ClipRegion.Right)
{
r.Width = m_ClipRegion.Right - r.X;
}
if (rect.Bottom > m_ClipRegion.Bottom)
{
r.Height = m_ClipRegion.Bottom - r.Y;
}
m_ClipRegion = r;
}
}
}