1.0.14
NUGET-Changes: + Materials now have a method to draw. That should allow more freedom on how materials can have a effect on the resulting shader. ~ PostProcessEffect.Draw now needs a source ColorAttachment. ~ Added some missing summaries GIT-/SOLUTION-Changes: Remade the folder structure, to something more senseable.
This commit is contained in:
parent
db7f01dca1
commit
89de4258e1
181 changed files with 584 additions and 698 deletions
118
src/renderer/SM.Base/Drawing/DrawingBasis.cs
Normal file
118
src/renderer/SM.Base/Drawing/DrawingBasis.cs
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
#region usings
|
||||
|
||||
using System.Collections.Generic;
|
||||
using OpenTK.Graphics.OpenGL4;
|
||||
using SM.Base.Scene;
|
||||
using SM.Base.Window;
|
||||
using SM.OGL.Mesh;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace SM.Base.Drawing
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains general basis systems for drawing objects.
|
||||
/// </summary>
|
||||
public abstract class DrawingBasis : IShowItem, IModelItem
|
||||
{
|
||||
/// <summary>
|
||||
/// The camera, that was used last time the object was rendered.
|
||||
/// </summary>
|
||||
public GenericCamera LastDrawingCamera { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The material it should use.
|
||||
/// </summary>
|
||||
public Material Material { get; set; } = new Material();
|
||||
|
||||
/// <summary>
|
||||
/// Transformation for the textures.
|
||||
/// </summary>
|
||||
public TextureTransformation TextureTransform { get; set; } = new TextureTransformation();
|
||||
|
||||
/// <summary>
|
||||
/// This allows custom shaders to add own arguments.
|
||||
/// </summary>
|
||||
public ShaderArguments ShaderArguments => Material.ShaderArguments;
|
||||
|
||||
/// <summary>
|
||||
/// This can force a shader to render the object with the specified mesh type.
|
||||
/// </summary>
|
||||
public PrimitiveType? ForcedMeshType { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The mesh it should use.
|
||||
/// </summary>
|
||||
public GenericMesh Mesh { get; set; } = SMRenderer.DefaultMesh;
|
||||
|
||||
/// <inheritdoc />
|
||||
public object Parent { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name { get; set; } = "Unnamed draw object";
|
||||
|
||||
/// <inheritdoc />
|
||||
public ICollection<string> Flags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This value determents if the object should draw something.
|
||||
/// </summary>
|
||||
public bool Active { get; set; } = true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool RenderActive { get; set; } = true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Draw(DrawContext context)
|
||||
{
|
||||
context.Material = Material;
|
||||
context.Mesh = Mesh;
|
||||
|
||||
DrawContext(ref context);
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public virtual void OnAdded(object sender)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual void OnRemoved(object sender)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws the context, that was given to them.
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
protected virtual void DrawContext(ref DrawContext context)
|
||||
{
|
||||
context.ForcedType = ForcedMeshType;
|
||||
context.TextureMatrix *= TextureTransform.GetMatrix();
|
||||
context.LastObject = this;
|
||||
|
||||
LastDrawingCamera = context.UseCamera;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Contains general basis systems for drawing objects.
|
||||
/// </summary>
|
||||
/// <typeparam name="TTransformation">The transformation type</typeparam>
|
||||
public abstract class DrawingBasis<TTransformation> : DrawingBasis, IShowTransformItem<TTransformation>
|
||||
where TTransformation : GenericTransformation, new()
|
||||
{
|
||||
/// <summary>
|
||||
/// The current transformation.
|
||||
/// </summary>
|
||||
public TTransformation Transform { get; set; } = new TTransformation();
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void DrawContext(ref DrawContext context)
|
||||
{
|
||||
base.DrawContext(ref context);
|
||||
Transform.LastMaster = context.ModelMatrix;
|
||||
context.ModelMatrix = Transform.InWorldSpace;
|
||||
}
|
||||
}
|
||||
}
|
||||
72
src/renderer/SM.Base/Drawing/GenericTransformation.cs
Normal file
72
src/renderer/SM.Base/Drawing/GenericTransformation.cs
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
#region usings
|
||||
|
||||
using OpenTK;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace SM.Base.Drawing
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains methods for using transformations right.
|
||||
/// </summary>
|
||||
public abstract class GenericTransformation
|
||||
{
|
||||
/// <summary>
|
||||
/// If true, ignores the transformation and sends <see cref="Matrix4.Identity" />, when requested.
|
||||
/// </summary>
|
||||
public bool Ignore = false;
|
||||
|
||||
/// <summary>
|
||||
/// The last matrix that was used to calculate the real world matrix.
|
||||
/// </summary>
|
||||
public Matrix4 LastMaster { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The transformation in world space.
|
||||
/// </summary>
|
||||
public Matrix4 InWorldSpace => MergeMatrix(LastMaster);
|
||||
|
||||
/// <summary>
|
||||
/// Contains the current model matrix.
|
||||
/// </summary>
|
||||
protected Matrix4 _modelMatrix { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Contains the last frame the matrix was calculated.
|
||||
/// </summary>
|
||||
protected ulong _lastFrame { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current model matrix.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Matrix4 GetMatrix()
|
||||
{
|
||||
if (Ignore) return Matrix4.Identity;
|
||||
|
||||
if (_lastFrame != SMRenderer.CurrentFrame)
|
||||
{
|
||||
_lastFrame = SMRenderer.CurrentFrame;
|
||||
_modelMatrix = RequestMatrix();
|
||||
}
|
||||
|
||||
return _modelMatrix;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This combines the current matrix with the provided one.
|
||||
/// </summary>
|
||||
/// <param name="matrix"></param>
|
||||
/// <returns></returns>
|
||||
public Matrix4 MergeMatrix(Matrix4 matrix)
|
||||
{
|
||||
return GetMatrix() * matrix;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the current matrix.
|
||||
/// </summary>
|
||||
/// <returns>The current matrix.</returns>
|
||||
protected abstract Matrix4 RequestMatrix();
|
||||
}
|
||||
}
|
||||
24
src/renderer/SM.Base/Drawing/Instance.cs
Normal file
24
src/renderer/SM.Base/Drawing/Instance.cs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
#region usings
|
||||
|
||||
using OpenTK;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace SM.Base.Drawing
|
||||
{
|
||||
/// <summary>
|
||||
/// This represens a drawing instance.
|
||||
/// </summary>
|
||||
public class Instance
|
||||
{
|
||||
/// <summary>
|
||||
/// The model matrix.
|
||||
/// </summary>
|
||||
public Matrix4 ModelMatrix = Matrix4.Identity;
|
||||
|
||||
/// <summary>
|
||||
/// The Texture matrix
|
||||
/// </summary>
|
||||
public Matrix3 TextureMatrix = Matrix3.Identity;
|
||||
}
|
||||
}
|
||||
47
src/renderer/SM.Base/Drawing/Material.cs
Normal file
47
src/renderer/SM.Base/Drawing/Material.cs
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
#region usings
|
||||
|
||||
using OpenTK.Graphics;
|
||||
using SM.Base.Shaders;
|
||||
using SM.Base.Window;
|
||||
using SM.OGL.Texture;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace SM.Base.Drawing
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a material.
|
||||
/// </summary>
|
||||
public class Material
|
||||
{
|
||||
/// <summary>
|
||||
/// A setting to enable Blending.
|
||||
/// </summary>
|
||||
public virtual bool Blending { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// A custom shader, that is used to draw this material.
|
||||
/// </summary>
|
||||
public virtual MaterialShader CustomShader { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The base texture. (aka. Diffuse Texture)
|
||||
/// </summary>
|
||||
public virtual TextureBase Texture { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The tint or color.
|
||||
/// </summary>
|
||||
public virtual Color4 Tint { get; set; } = Color4.White;
|
||||
|
||||
/// <summary>
|
||||
/// This allows custom shaders to use own shader arguments.
|
||||
/// </summary>
|
||||
public ShaderArguments ShaderArguments { get; internal set; } = new ShaderArguments();
|
||||
|
||||
public virtual void Draw(DrawContext context)
|
||||
{
|
||||
context.Shader.Draw(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
212
src/renderer/SM.Base/Drawing/Particles/ParticleDrawingBasis.cs
Normal file
212
src/renderer/SM.Base/Drawing/Particles/ParticleDrawingBasis.cs
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
#region usings
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using OpenTK;
|
||||
using SM.Base.Scene;
|
||||
using SM.Base.Time;
|
||||
using SM.Base.Window;
|
||||
using Stopwatch = System.Diagnostics.Stopwatch;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace SM.Base.Drawing.Particles
|
||||
{
|
||||
/// <summary>
|
||||
/// The (drawing) basis for particles
|
||||
/// </summary>
|
||||
public abstract class ParticleDrawingBasis<TTransform, TDirection> : DrawingBasis<TTransform>, IScriptable
|
||||
where TTransform : GenericTransformation, new()
|
||||
where TDirection : struct
|
||||
{
|
||||
private float? _continuesIntervalSeconds = null;
|
||||
private Interval _continuesInterval;
|
||||
|
||||
/// <summary>
|
||||
/// The stopwatch of the particles.
|
||||
/// </summary>
|
||||
protected Timer timer;
|
||||
|
||||
/// <summary>
|
||||
/// This contains the different instances for the particles.
|
||||
/// </summary>
|
||||
protected List<ParticleInstance<TDirection>> instances;
|
||||
|
||||
/// <summary>
|
||||
/// The amount of particles
|
||||
/// </summary>
|
||||
public int Amount = 32;
|
||||
|
||||
/// <summary>
|
||||
/// The base lifetime for particles in seconds.
|
||||
/// </summary>
|
||||
public float Lifetime;
|
||||
/// <summary>
|
||||
/// Randomizes the lifetime for particles.
|
||||
/// </summary>
|
||||
public float LifetimeRandomize = 0;
|
||||
|
||||
/// <summary>
|
||||
/// If set to any value (except null), it will create the particles continuously.
|
||||
/// </summary>
|
||||
public float? ContinuousInterval
|
||||
{
|
||||
get => _continuesIntervalSeconds;
|
||||
set
|
||||
{
|
||||
if (value.HasValue)
|
||||
{
|
||||
_continuesInterval.Target = value.Value;
|
||||
}
|
||||
|
||||
_continuesIntervalSeconds = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If true, the particles will spawn in Worldspace and can't be moved by the transformation.
|
||||
/// </summary>
|
||||
public bool DetachedParticles;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum speed of the particles
|
||||
/// <para>Default: 25</para>
|
||||
/// </summary>
|
||||
public float MaxSpeed = 25;
|
||||
|
||||
/// <summary>
|
||||
/// Sets up the timer.
|
||||
/// </summary>
|
||||
/// <param name="duration">Duration how long the particles should live</param>
|
||||
protected ParticleDrawingBasis(TimeSpan duration)
|
||||
{
|
||||
timer = new Timer(duration);
|
||||
_continuesInterval = new Interval(0);
|
||||
_continuesInterval.End += CreateContinuesParticles;
|
||||
|
||||
Lifetime = (float) duration.TotalSeconds;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get/Sets the state of pausing.
|
||||
/// </summary>
|
||||
public bool Paused
|
||||
{
|
||||
get => timer.Paused;
|
||||
set => timer.Paused = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Controls the movement of each particles.
|
||||
/// </summary>
|
||||
public abstract Func<ParticleInstance<TDirection>, TDirection> MovementCalculation { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool UpdateActive {
|
||||
get => timer.Active || _continuesInterval.Active;
|
||||
set { return; }
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Update(UpdateContext context)
|
||||
{
|
||||
Stopwatch stp = new Stopwatch();
|
||||
stp.Start();
|
||||
for (int i = 0; i < instances.Count; i++)
|
||||
{
|
||||
instances[i].Lifetime -= context.Deltatime;
|
||||
if (instances[i].Lifetime <= 0)
|
||||
{
|
||||
instances.Remove(instances[i]);
|
||||
break;
|
||||
}
|
||||
|
||||
instances[i].ModelMatrix = CreateMatrix(instances[i], MovementCalculation(instances[i]));
|
||||
}
|
||||
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Triggers the particles.
|
||||
/// </summary>
|
||||
public void Trigger()
|
||||
{
|
||||
instances = new List<ParticleInstance<TDirection>>();
|
||||
if (_continuesIntervalSeconds.HasValue)
|
||||
{
|
||||
_continuesInterval.Target = _continuesIntervalSeconds.Value;
|
||||
_continuesInterval.Start();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
timer.Start();
|
||||
|
||||
CreateParticles();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stops the particles.
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
if (_continuesInterval.Active)
|
||||
{
|
||||
_continuesInterval.Stop();
|
||||
}
|
||||
|
||||
timer.Stop();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnRemoved(object sender)
|
||||
{
|
||||
base.OnRemoved(sender);
|
||||
|
||||
Stop();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void DrawContext(ref DrawContext context)
|
||||
{
|
||||
if (!timer.Active && _continuesInterval != null && !_continuesInterval.Active) return;
|
||||
|
||||
base.DrawContext(ref context);
|
||||
|
||||
if (DetachedParticles) context.ModelMatrix = Matrix4.Identity;
|
||||
|
||||
context.Instances = instances.ConvertAll(a => (Instance)a);
|
||||
|
||||
Material.Draw(context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the particles.
|
||||
/// </summary>
|
||||
protected virtual void CreateParticles()
|
||||
{
|
||||
|
||||
|
||||
for (int i = 0; i < Amount; i++)
|
||||
{
|
||||
instances.Add(CreateObject(i));
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateContinuesParticles(Timer arg1, UpdateContext arg2)
|
||||
{
|
||||
instances.Add(CreateObject(0));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a particle.
|
||||
/// </summary>
|
||||
protected abstract ParticleInstance<TDirection> CreateObject(int index);
|
||||
|
||||
/// <summary>
|
||||
/// Generates the desired matrix for drawing.
|
||||
/// </summary>
|
||||
protected abstract Matrix4 CreateMatrix(ParticleInstance<TDirection> Struct, TDirection relativePosition);
|
||||
}
|
||||
}
|
||||
40
src/renderer/SM.Base/Drawing/Particles/ParticleInstance.cs
Normal file
40
src/renderer/SM.Base/Drawing/Particles/ParticleInstance.cs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
using OpenTK;
|
||||
|
||||
namespace SM.Base.Drawing.Particles
|
||||
{
|
||||
/// <summary>
|
||||
/// This describes a instance of a particle
|
||||
/// </summary>
|
||||
public class ParticleInstance : Instance
|
||||
{
|
||||
/// <summary>
|
||||
/// The lifetime the particle started with.
|
||||
/// </summary>
|
||||
public float StartLifetime = 0;
|
||||
|
||||
/// <summary>
|
||||
/// The lifetime this particular particle still has.
|
||||
/// </summary>
|
||||
public float Lifetime = 0;
|
||||
|
||||
/// <summary>
|
||||
/// A additional matrix to store rotation and scale.
|
||||
/// </summary>
|
||||
public Matrix4 Matrix;
|
||||
|
||||
/// <summary>
|
||||
/// Speeeeeeeeeed
|
||||
/// </summary>
|
||||
public float Speed;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public class ParticleInstance<TValue> : ParticleInstance
|
||||
where TValue : struct
|
||||
{
|
||||
/// <summary>
|
||||
/// A direction, that the particle should travel.
|
||||
/// </summary>
|
||||
public TValue Direction;
|
||||
}
|
||||
}
|
||||
30
src/renderer/SM.Base/Drawing/Particles/ParticleMovement.cs
Normal file
30
src/renderer/SM.Base/Drawing/Particles/ParticleMovement.cs
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#region usings
|
||||
|
||||
using OpenTK;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace SM.Base.Drawing.Particles
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains methods for particle movements.
|
||||
/// </summary>
|
||||
public class ParticleMovement
|
||||
{
|
||||
/// <summary>
|
||||
/// Default movement for 2D.
|
||||
/// </summary>
|
||||
public static Vector2 Default2D(ParticleInstance<Vector2> particle)
|
||||
{
|
||||
return particle.Direction * ((particle.StartLifetime - particle.Lifetime) * particle.Speed);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default movement for 3D.
|
||||
/// </summary>
|
||||
public static Vector3 Default3D(ParticleInstance<Vector3> particle)
|
||||
{
|
||||
return particle.Direction * ((particle.StartLifetime - particle.Lifetime) * particle.Speed);
|
||||
}
|
||||
}
|
||||
}
|
||||
26
src/renderer/SM.Base/Drawing/ShaderArguments.cs
Normal file
26
src/renderer/SM.Base/Drawing/ShaderArguments.cs
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#region usings
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace SM.Base.Drawing
|
||||
{
|
||||
/// <summary>
|
||||
/// A custom dictionary, with a few useful methods.
|
||||
/// </summary>
|
||||
public class ShaderArguments : Dictionary<string, object>
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the stored value or the default value if the name doesn't exist.
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="defaultValue"></param>
|
||||
/// <typeparam name="TType"></typeparam>
|
||||
/// <returns></returns>
|
||||
public TType Get<TType>(string name, TType defaultValue = default)
|
||||
{
|
||||
return ContainsKey(name) ? (TType) this[name] : defaultValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
37
src/renderer/SM.Base/Drawing/Text/CharParameter.cs
Normal file
37
src/renderer/SM.Base/Drawing/Text/CharParameter.cs
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
#region usings
|
||||
|
||||
using System;
|
||||
using OpenTK;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace SM.Base.Drawing.Text
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains information for a font character.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public struct CharParameter
|
||||
{
|
||||
/// <summary>
|
||||
/// The advance on the X-axis.
|
||||
/// </summary>
|
||||
public int Advance;
|
||||
|
||||
/// <summary>
|
||||
/// The bearing for this char.
|
||||
/// </summary>
|
||||
public float BearingX;
|
||||
|
||||
/// <summary>
|
||||
/// The width of the character.
|
||||
/// </summary>
|
||||
public float Width;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Matrix for the texture.
|
||||
/// </summary>
|
||||
public Matrix3 TextureMatrix;
|
||||
}
|
||||
}
|
||||
125
src/renderer/SM.Base/Drawing/Text/Font.cs
Normal file
125
src/renderer/SM.Base/Drawing/Text/Font.cs
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Windows.Forms;
|
||||
using OpenTK;
|
||||
using SharpFont;
|
||||
using SM.Base.Textures;
|
||||
|
||||
namespace SM.Base.Drawing.Text
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a font to be used in DrawText-classes.
|
||||
/// </summary>
|
||||
public class Font : Texture
|
||||
{
|
||||
private static Library _lib;
|
||||
|
||||
private Face _fontFace;
|
||||
|
||||
/// <summary>
|
||||
/// The amount the cursor should move forward when a space was found.
|
||||
/// </summary>
|
||||
public float SpaceWidth { get; private set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// The char set the font should contain.
|
||||
/// <para>See <see cref="FontCharStorage"/> for some default values.</para>
|
||||
/// <para>Default: <see cref="FontCharStorage.SimpleUTF8"/></para>
|
||||
/// </summary>
|
||||
public ICollection<char> CharSet { get; set; } = FontCharStorage.SimpleUTF8;
|
||||
|
||||
/// <summary>
|
||||
/// The font-size defines how large the result texture should be.
|
||||
/// <para>Lower equals less quality, but also less memory usage.</para>
|
||||
/// <para>Higher equals high quality, but also high memory usage.</para>
|
||||
/// <para>Default: 12</para>
|
||||
/// </summary>
|
||||
public float FontSize { get; set; } = 12;
|
||||
|
||||
/// <summary>
|
||||
/// The character positions.
|
||||
/// </summary>
|
||||
public Dictionary<char, CharParameter> Positions = new Dictionary<char, CharParameter>();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates a font, by using a path
|
||||
/// </summary>
|
||||
/// <param name="path">Path to the font-file.</param>
|
||||
public Font(string path)
|
||||
{
|
||||
_lib ??= new Library();
|
||||
|
||||
_fontFace = new Face(_lib, path);
|
||||
UnpackAlignment = 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// (Re-)Generates the texture.
|
||||
/// </summary>
|
||||
public void RegenerateTexture()
|
||||
{
|
||||
Width = Height = 0;
|
||||
Positions = new Dictionary<char, CharParameter>();
|
||||
|
||||
_fontFace.SetCharSize(0, FontSize, 0, 96);
|
||||
|
||||
var pos = new Dictionary<char, float[]>();
|
||||
foreach (char c in CharSet)
|
||||
{
|
||||
_fontFace.LoadChar(c, LoadFlags.Render, LoadTarget.Normal);
|
||||
|
||||
pos.Add(c, new []{(float)_fontFace.Glyph.Bitmap.Width, Width});
|
||||
Width += (int)_fontFace.Glyph.Advance.X + 2;
|
||||
Height = Math.Max(_fontFace.Glyph.Bitmap.Rows, Height);
|
||||
}
|
||||
|
||||
_fontFace.LoadChar('_', LoadFlags.Render, LoadTarget.Normal);
|
||||
SpaceWidth = _fontFace.Glyph.Advance.X.ToSingle();
|
||||
|
||||
float bBoxHeight = (Math.Abs(_fontFace.BBox.Bottom) + _fontFace.BBox.Top);
|
||||
float bBoxTopScale = _fontFace.BBox.Top / bBoxHeight;
|
||||
float baseline = Height * bBoxTopScale + 1;
|
||||
|
||||
Map = new Bitmap(Width, Height);
|
||||
using (Graphics g = Graphics.FromImage(Map))
|
||||
{
|
||||
g.Clear(Color.Transparent);
|
||||
|
||||
|
||||
foreach (var keyvalue in pos)
|
||||
{
|
||||
_fontFace.LoadChar(keyvalue.Key, LoadFlags.Render, LoadTarget.Normal);
|
||||
|
||||
int y = ((int)baseline - (int)_fontFace.Glyph.Metrics.HorizontalBearingY);
|
||||
|
||||
g.DrawImageUnscaled(_fontFace.Glyph.Bitmap.ToGdipBitmap(Color.White), (int)keyvalue.Value[1], y);
|
||||
|
||||
Vector2 offset = new Vector2(keyvalue.Value[1] / Width, 0);
|
||||
Vector2 scale = new Vector2(keyvalue.Value[0] / Width, 1);
|
||||
Positions.Add(keyvalue.Key, new CharParameter()
|
||||
{
|
||||
Advance = (int)_fontFace.Glyph.LinearHorizontalAdvance,
|
||||
BearingX = _fontFace.Glyph.BitmapLeft,
|
||||
|
||||
Width = keyvalue.Value[0],
|
||||
|
||||
TextureMatrix = TextureTransformation.CalculateMatrix(offset,
|
||||
scale, 0),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Compile()
|
||||
{
|
||||
RegenerateTexture();
|
||||
base.Compile();
|
||||
}
|
||||
}
|
||||
}
|
||||
29
src/renderer/SM.Base/Drawing/Text/FontCharStorage.cs
Normal file
29
src/renderer/SM.Base/Drawing/Text/FontCharStorage.cs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
namespace SM.Base.Drawing.Text
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains default char sets.
|
||||
/// </summary>
|
||||
public class FontCharStorage
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains the english alphabet and the common special character.
|
||||
/// </summary>
|
||||
public static readonly char[] SimpleUTF8 =
|
||||
{
|
||||
'!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5',
|
||||
'6',
|
||||
'7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
|
||||
'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', '`',
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u',
|
||||
'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~'
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Contains only numbers.
|
||||
/// </summary>
|
||||
public static readonly char[] Numbers =
|
||||
{
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
|
||||
};
|
||||
}
|
||||
}
|
||||
202
src/renderer/SM.Base/Drawing/Text/TextDrawingBasis.cs
Normal file
202
src/renderer/SM.Base/Drawing/Text/TextDrawingBasis.cs
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
#region usings
|
||||
|
||||
using System;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using SM.Base.Objects.Static;
|
||||
using SM.Base.Window;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace SM.Base.Drawing.Text
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the options for <see cref="TextDrawingBasis{TTransform}.Origin"/>
|
||||
/// </summary>
|
||||
public enum TextOrigin
|
||||
{
|
||||
/// <summary>
|
||||
/// The position equals (0,0) in the left side of the text.
|
||||
/// </summary>
|
||||
Left,
|
||||
/// <summary>
|
||||
/// The position equals (0,0) in the center of the text.
|
||||
/// </summary>
|
||||
Center,
|
||||
/// <summary>
|
||||
/// The position equals (0,0) in the right side of the text.
|
||||
/// </summary>
|
||||
Right
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines a basis for text drawing.
|
||||
/// </summary>
|
||||
/// <typeparam name="TTransform">Transformation type</typeparam>
|
||||
public abstract class TextDrawingBasis<TTransform> : DrawingBasis<TTransform>
|
||||
where TTransform : GenericTransformation, new()
|
||||
{
|
||||
/// <summary>
|
||||
/// The different instances for drawing.
|
||||
/// </summary>
|
||||
protected Instance[] _instances;
|
||||
|
||||
/// <summary>
|
||||
/// The text, that is drawn.
|
||||
/// </summary>
|
||||
protected string _text;
|
||||
|
||||
/// <summary>
|
||||
/// The width of the text object.
|
||||
/// </summary>
|
||||
public float Width;
|
||||
|
||||
/// <summary>
|
||||
/// The height of the text object.
|
||||
/// </summary>
|
||||
public float Height;
|
||||
|
||||
/// <summary>
|
||||
/// Allow to change the origin of the text.
|
||||
/// <para>Default: <see cref="TextOrigin.Left"/></para>
|
||||
/// </summary>
|
||||
public TextOrigin Origin = TextOrigin.Left;
|
||||
|
||||
/// <summary>
|
||||
/// The spacing between numbers.
|
||||
/// <para>Default: 1</para>
|
||||
/// </summary>
|
||||
public float Spacing = 1f;
|
||||
|
||||
/// <summary>
|
||||
/// The font.
|
||||
/// </summary>
|
||||
public Font Font
|
||||
{
|
||||
get => (Font)Material.Texture;
|
||||
set
|
||||
{
|
||||
Material.Texture = value;
|
||||
GenerateMatrixes();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The text, that is drawn.
|
||||
/// </summary>
|
||||
public string Text
|
||||
{
|
||||
get => _text;
|
||||
set
|
||||
{
|
||||
_text = value;
|
||||
GenerateMatrixes();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The font color.
|
||||
/// </summary>
|
||||
public Color4 Color
|
||||
{
|
||||
get => Material.Tint;
|
||||
set => Material.Tint = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a text object with a font.
|
||||
/// </summary>
|
||||
/// <param name="font">The font.</param>
|
||||
protected TextDrawingBasis(Font font)
|
||||
{
|
||||
Material.Texture = font;
|
||||
Material.Blending = true;
|
||||
Mesh = Plate.Object;
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void DrawContext(ref DrawContext context)
|
||||
{
|
||||
base.DrawContext(ref context);
|
||||
if (_instances == null) GenerateMatrixes();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This generates the instances.
|
||||
/// </summary>
|
||||
/// <exception cref="Exception">The font doesn't contain a character that is needed for the text.</exception>
|
||||
public void GenerateMatrixes()
|
||||
{
|
||||
if (!Font.WasCompiled) Font.RegenerateTexture();
|
||||
|
||||
_text = _text.Replace("\r\n", "\n").Replace("\t", " ");
|
||||
|
||||
_instances = new Instance[_text.Length];
|
||||
|
||||
float x = 0;
|
||||
float y = 0;
|
||||
for (var i = 0; i < _text.Length; i++)
|
||||
{
|
||||
if (_text[i] == ' ')
|
||||
{
|
||||
x += Font.SpaceWidth * Spacing;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_text[i] == '\n')
|
||||
{
|
||||
y += Font.Height;
|
||||
Width = Math.Max(Width, x);
|
||||
x = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
CharParameter parameter;
|
||||
try
|
||||
{
|
||||
parameter = Font.Positions[_text[i]];
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw new Exception("Font doesn't contain '" + _text[i] + "'");
|
||||
}
|
||||
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
x += parameter.Width / 2;
|
||||
}
|
||||
|
||||
var matrix = Matrix4.CreateScale(parameter.Width, Font.Height, 1) *
|
||||
Matrix4.CreateTranslation(x + parameter.Width / 2, -y, 0);
|
||||
_instances[i] = new Instance
|
||||
{
|
||||
ModelMatrix = matrix,
|
||||
TextureMatrix = parameter.TextureMatrix
|
||||
};
|
||||
|
||||
x += parameter.Advance;
|
||||
}
|
||||
Height = y + Font.Height;
|
||||
Width = x;
|
||||
|
||||
if (Origin != TextOrigin.Left)
|
||||
{
|
||||
foreach (Instance i in _instances)
|
||||
{
|
||||
if (i == null) continue;
|
||||
switch (Origin)
|
||||
{
|
||||
case TextOrigin.Center:
|
||||
i.ModelMatrix *= Matrix4.CreateTranslation(-Width / 2, 0, 0);
|
||||
break;
|
||||
case TextOrigin.Right:
|
||||
i.ModelMatrix *= Matrix4.CreateTranslation(-Width, 0, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
89
src/renderer/SM.Base/Drawing/TextureTransformation.cs
Normal file
89
src/renderer/SM.Base/Drawing/TextureTransformation.cs
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
#region usings
|
||||
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics.ES10;
|
||||
using SM.Base.Textures;
|
||||
using SM.Base.Types;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace SM.Base.Drawing
|
||||
{
|
||||
/// <summary>
|
||||
/// Stores transformations for the textures.
|
||||
/// </summary>
|
||||
public class TextureTransformation
|
||||
{
|
||||
/// <summary>
|
||||
/// The offset from the origin.
|
||||
/// </summary>
|
||||
public CVector2 Offset = new CVector2(0);
|
||||
/// <summary>
|
||||
/// The rotation of the texture.
|
||||
/// </summary>
|
||||
public CVector1 Rotation = new CVector1(0);
|
||||
/// <summary>
|
||||
/// The scale of the texture.
|
||||
/// </summary>
|
||||
public CVector2 Scale = new CVector2(1);
|
||||
|
||||
/// <summary>
|
||||
/// Get the texture matrix.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Matrix3 GetMatrix()
|
||||
{
|
||||
return CalculateMatrix(Offset, Scale, Rotation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the offset relative to the pixels of the texture.
|
||||
/// </summary>
|
||||
/// <param name="texture">The texture it should use.</param>
|
||||
/// <param name="pixelLocation">The offset in pixel.</param>
|
||||
public void SetOffsetRelative(Texture texture, Vector2 pixelLocation)
|
||||
{
|
||||
Vector2 textureSize = new Vector2(texture.Width, texture.Height);
|
||||
Offset.Set( Vector2.Divide(pixelLocation, textureSize) );
|
||||
}
|
||||
/// <summary>
|
||||
/// Sets the scale relative to the pixels of the texture.
|
||||
/// </summary>
|
||||
/// <param name="texture">The texture.</param>
|
||||
/// <param name="rectangleSize">The scale in pixel.</param>
|
||||
public void SetScaleRelative(Texture texture, Vector2 rectangleSize)
|
||||
{
|
||||
Vector2 textureSize = new Vector2(texture.Width, texture.Height);
|
||||
Scale.Set( Vector2.Divide(rectangleSize, textureSize) );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the offset and scale relative to the pixels of the texture.
|
||||
/// </summary>
|
||||
/// <param name="texture">The texture.</param>
|
||||
/// <param name="location">Offset in pixel</param>
|
||||
/// <param name="rectangleSize">Scale in pixel.</param>
|
||||
public void SetRectangleRelative(Texture texture, Vector2 location, Vector2 rectangleSize)
|
||||
{
|
||||
Vector2 textureSize = new Vector2(texture.Width, texture.Height);
|
||||
|
||||
Offset.Set(Vector2.Divide(location, textureSize));
|
||||
Scale.Set(Vector2.Divide(rectangleSize, textureSize));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates a texture matrix.
|
||||
/// </summary>
|
||||
/// <param name="offset"></param>
|
||||
/// <param name="scale"></param>
|
||||
/// <param name="rotation"></param>
|
||||
/// <returns></returns>
|
||||
public static Matrix3 CalculateMatrix(Vector2 offset, Vector2 scale, float rotation)
|
||||
{
|
||||
float radians = MathHelper.DegreesToRadians(rotation);
|
||||
Matrix3 result = Matrix3.CreateScale(scale.X, scale.Y, 1) * Matrix3.CreateRotationZ(radians);
|
||||
result.Row2 = new Vector3(offset.X, offset.Y, 1);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue