Compare commits

...

2 Commits

Author SHA1 Message Date
ccb0c6ffe7 Add new font search criterea. 2024-04-28 13:45:46 +03:00
bc3dcff3ea Remove the old Quik texture API. 2024-04-28 13:44:40 +03:00
12 changed files with 356 additions and 174 deletions

@ -1,69 +0,0 @@
using System;
using Quik.Media;
namespace Quik
{
/// <summary>
/// Interface for texture instances.
/// </summary>
public abstract class QuikTexture : IEquatable<QuikTexture>, IDisposable
{
/// <summary>
/// Width of the texture.
/// </summary>
public abstract int Width { get; }
/// <summary>
/// Height of the texture.
/// </summary>
public abstract int Height { get; }
/// <summary>
/// True if the texture can have mipmaps.
/// </summary>
public abstract bool Mipmaps { get; }
/// <summary>
/// Indicates whether this texture contains a signed distance field.
/// </summary>
public bool SignedDistanceField { get; set; }
/// <summary>
/// Indicates whether this texture has premultiplied alpha.
/// </summary>
public bool PreMultipled { get; set; }
/// <summary>
/// Upload texture data.
/// </summary>
/// <param name="data">Pointer to data.</param>
/// <param name="format">Color format of the data.</param>
/// <param name="size">Size of the texture data.</param>
/// <param name="level">Mip level.</param>
/// <param name="alignment">Pixel alignment. Expected to be 1, 2, 4, or 8.</param>
public abstract void Image(IntPtr data, QImageFormat format, QVec2 size, int level, int alignment = 4);
/// <summary>
/// Upload texture data.
/// </summary>
/// <param name="data">Pointer to data.</param>
/// <param name="format">Color format for the data.</param>
/// <param name="location">Location of the data in the texture.</param>
/// <param name="level">Mip level.</param>
/// <param name="alignment">Pixel alignment. Expected to be 1, 2, 4, or 8.</param>
public abstract void SubImage(IntPtr data, QImageFormat format, QRectangle location, int level, int alignment = 4);
/// <summary>
/// Generate the mip maps for the texture.
/// </summary>
public abstract void GenerateMipMaps();
public virtual bool Equals(QuikTexture other)
{
return base.Equals(other);
}
public void Dispose() => Dispose(true);
protected virtual void Dispose(bool isDisposing) { }
}
}

@ -1,32 +0,0 @@
using Quik.Media;
namespace Quik
{
/// <summary>
/// Interface for QUIK texture managers.
/// </summary>
public interface IQuikTextureManager
{
/// <summary>
/// The context that owns the texture manager.
/// </summary>
// QuikContext Context { get; set; }
/// <summary>
/// Create a texture.
/// </summary>
/// <param name="size">Size of the texture.</param>
/// <param name="mipmaps">True in order to allow mipmaps.</param>
/// <param name="format">The color format of the internal texture.</param>
/// <returns>Handle to a texture object.</returns>
/// <remarks>
/// All parameters are hints. If there is a situation where the texture does not
/// have mip levels, or format cannot be specified, ignore these parameters.
/// </remarks>
QuikTexture CreateTexture(QVec2 size, bool mipmaps, QImageFormat format);
/// <summary>
/// A function called on context clear. (useful for discarding old textures)
/// </summary>
void Clear();
}
}

240
Quik/Media/Font/FontFace.cs Normal file

@ -0,0 +1,240 @@
using System;
using System.Net.WebSockets;
using System.Text;
using Quik.Media.Font;
namespace Quik.Media.Font
{
public readonly struct FontFace : IEquatable<FontFace>
{
public string Family { get; }
public FontSlant Slant { get; }
public FontWeight Weight { get; }
public FontStretch Stretch { get; }
public FontFace(string family, FontSlant slant, FontWeight weight, FontStretch stretch)
{
Family = family;
Slant = slant;
Weight = weight;
Stretch = stretch;
}
public override string ToString()
{
StringBuilder builder = new StringBuilder(Family);
if (Slant != FontSlant.Normal)
{
builder.Append(' ');
builder.Append(Slant);
}
if (Stretch != FontStretch.Normal)
{
builder.Append(' ');
builder.Append(Stretch);
}
if (Weight != FontWeight.Normal)
{
builder.Append(' ');
builder.Append(Weight);
}
if (Slant == FontSlant.Normal &&
Stretch == FontStretch.Normal &&
Weight == FontWeight.Normal)
{
builder.Append(" Regular");
}
return builder.ToString();
}
public override int GetHashCode()
{
return HashCode.Combine(Family, Slant, Weight, Stretch);
}
public static bool operator==(FontFace a, FontFace b)
{
return (a.Slant == b.Slant) &&
(a.Weight == b.Weight) &&
(a.Stretch == b.Stretch) &&
(a.Family == a.Family);
}
public static bool operator!=(FontFace a, FontFace b)
{
return (a.Slant != b.Slant) ||
(a.Weight != b.Weight) ||
(a.Stretch != b.Stretch) ||
(a.Family != b.Family);
}
public bool Equals(FontFace other)
{
return this == other;
}
public override bool Equals(object obj)
{
return (obj.GetType() == typeof(FontFace)) &&
this == (FontFace)obj;
}
public static FontFace Parse(string family, string style)
{
FontSlant slant = FontSlant.Normal;
FontWeight weight = FontWeight.Normal;
FontStretch stretch = FontStretch.Normal;
string[] tokens = style.Split(' ');
foreach (string token in tokens)
{
/**/ if (TryParseSlant(token, out FontSlant xslant)) slant = xslant;
else if (TryParseWeight(token, out FontWeight xweight)) weight = xweight;
else if (TryParseStretch(token, out FontStretch xstretch)) stretch = xstretch;
}
return new FontFace(family, slant, weight, stretch);
}
public static FontFace Parse(string face)
{
StringBuilder family = new StringBuilder();
FontSlant slant = FontSlant.Normal;
FontWeight weight = FontWeight.Normal;
FontStretch stretch = FontStretch.Normal;
string[] tokens = face.Split(' ');
foreach (string token in tokens)
{
string xtoken = token.ToLower();
if (xtoken == "regular" || xtoken == "normal")
{
continue;
}
else if (TryParseSlant(xtoken, out FontSlant xslant)) slant = xslant;
else if (TryParseWeight(xtoken, out FontWeight xweight)) weight = xweight;
else if (TryParseStretch(xtoken, out FontStretch xstretch)) stretch = xstretch;
else
{
family.Append(token);
}
}
return new FontFace(family.ToString(), slant, weight, stretch);
}
/// <summary>
/// Try to convert a token that represents a font slant into its enum.
/// </summary>
/// <param name="token">The token to interpret.</param>
/// <param name="slant">The resulting slant.</param>
/// <returns>True if it matched any.</returns>
public static bool TryParseSlant(string token, out FontSlant slant)
{
switch (token.ToLower())
{
case "italic":
slant = FontSlant.Italic;
return true;
case "oblique":
slant = FontSlant.Oblique;
return true;
default:
slant = FontSlant.Normal;
return false;
}
}
/// <summary>
/// Try to convert a token that represents a font weight into its enum.
/// </summary>
/// <param name="token">The token to interpret.</param>
/// <param name="weight">The resulting weight.</param>
/// <returns>True if it matched any.</returns>
public static bool TryParseWeight(string token, out FontWeight weight)
{
switch (token.ToLower())
{
case "thin":
weight = FontWeight.Thin;
return true;
case "extralight":
case "ultralight":
weight = FontWeight._200;
return true;
case "light":
case "demilight":
case "semilight":
weight = FontWeight._300;
return true;
case "demibold":
case "semibold":
weight = FontWeight._600;
return true;
case "bold":
weight = FontWeight._700;
return true;
case "extrabold":
case "ultrabold":
weight = FontWeight._800;
return true;
case "heavy":
case "extrablack":
case "black":
case "ultrablack":
weight = FontWeight._900;
return true;
default:
weight = FontWeight.Normal;
return false;
}
}
/// <summary>
/// Try to convert a token that represents a font stretch into its enum.
/// </summary>
/// <param name="token">The token to interpret.</param>
/// <param name="stretch">The resulting stretch.</param>
/// <returns>True if it matched any.</returns>
public static bool TryParseStretch(string token, out FontStretch stretch)
{
switch (token.ToLower())
{
case "ultracondensed":
stretch = FontStretch.UltraCondensed;
return true;
case "extracondensed":
stretch = FontStretch.ExtraCondensed;
return true;
case "condensed":
stretch = FontStretch.Condensed;
return true;
case "semicondensed":
case "demicondensed":
stretch = FontStretch.SemiCondensed;
return true;
case "semiexpanded":
case "demiexpanded":
stretch = FontStretch.SemiExpanded;
return true;
case "expanded":
stretch = FontStretch.Expanded;
return true;
case "extraexpanded":
stretch = FontStretch.ExtraExpanded;
return true;
case "ultraexpanded":
stretch = FontStretch.UltraExpanded;
return true;
default:
stretch = FontStretch.Normal;
return false;
}
}
}
}

@ -0,0 +1,9 @@
namespace Quik.Media.Font
{
public enum FontSlant
{
Normal = 0,
Italic = 1,
Oblique = 2,
}
}

@ -0,0 +1,18 @@
namespace Quik.Media.Font
{
/// <summary>
/// Enumeration of font stretch values.
/// </summary>
public enum FontStretch
{
UltraCondensed = 500,
ExtraCondensed = 625,
Condensed = 750,
SemiCondensed = 875,
Normal = 1000,
SemiExpanded = 1125,
Expanded = 1250,
ExtraExpanded = 1500,
UltraExpanded = 2000,
}
}

@ -0,0 +1,22 @@
using System;
namespace Quik.Media.Font
{
public enum FontWeight
{
_100 = 100,
_200 = 200,
_300 = 300,
_400 = 400,
_500 = 500,
_600 = 600,
_700 = 700,
_800 = 800,
_900 = 900,
Thin = _100,
Normal = _400,
Bold = _700,
Heavy = _900,
}
}

@ -1,44 +0,0 @@
using System;
namespace Quik.Media
{
public struct FontInfo : IEquatable<FontInfo>
{
public string Family { get; }
public FontStyle Style { get; }
public override string ToString()
{
return $"{Family} {Style}";
}
public override int GetHashCode()
{
return Family.GetHashCode() ^
(Style.GetHashCode() * 3976061);
}
public static bool operator==(FontInfo a, FontInfo b)
{
return (a.Style == b.Style) &&
(a.Family == a.Family);
}
public static bool operator!=(FontInfo a, FontInfo b)
{
return (a.Style != b.Style) ||
(a.Family != b.Family);
}
public bool Equals(FontInfo other)
{
return this == other;
}
public override bool Equals(object obj)
{
return (obj.GetType() == typeof(FontInfo)) &&
this == (FontInfo)obj;
}
}
}

@ -1,14 +0,0 @@
using System;
namespace Quik.Media
{
[Flags]
public enum FontStyle
{
Italic = 1 << 0,
Bold = 1 << 1,
Normal = 0,
BoldItalic = Italic | Bold,
}
}

@ -1,4 +1,7 @@
using System;
using System.Collections.Generic;
using Quik.Media;
using Quik.Media.Font;
namespace Quik.Media
{
@ -7,9 +10,11 @@ namespace Quik.Media
/// </summary>
public abstract class QFont : IDisposable
{
public abstract FontInfo Info { get; }
public string Family => Info.Family;
public FontStyle Style => Info.Style;
public abstract FontFace Face { get; }
public string Family => Face.Family;
public FontSlant Slant => Face.Slant;
public FontWeight Weight => Face.Weight;
public FontStretch Stretch => Face.Stretch;
public abstract bool HasRune(int rune);
public abstract QFontPage RasterizePage(int codepage, float size, in FontRasterizerOptions options);

@ -10,11 +10,6 @@ namespace Quik.Media
/// </summary>
public int Rune { get; }
// /// <summary>
// /// Location of the glyph on the atlas.
// /// </summary>
// public QRectangle Location { get; }
/// <summary>
/// Size of the glyph in units.
/// </summary>
@ -37,14 +32,12 @@ namespace Quik.Media
public QGlyphMetrics(
int character,
// QRectangle location,
QVec2 size,
QVec2 horizontalBearing,
QVec2 verticalBearing,
QVec2 advance)
{
Rune = character;
// Location = location;
Size = size;
HorizontalBearing = horizontalBearing;
VerticalBearing = verticalBearing;

54
Quik/PAL/IFontDatabase.cs Normal file

@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.IO;
using Quik.Media.Font;
namespace Quik.PAL
{
/// <summary>
/// Flags that effect font search criterea.
/// </summary>
[Flags]
public enum FontMatchCriteria
{
None = 0,
Family = 1 << 0,
Slant = 1 << 1,
Weight = 1 << 2,
Stretch = 1 << 3,
All = Family | Slant | Weight | Stretch,
}
/// <summary>
/// An abstraction over the system font database.
/// </summary>
public interface IFontDataBase
{
/// <summary>
/// All the fonts installed in the system.
/// </summary>
IEnumerable<FontFace> All { get; }
/// <summary>
/// Search for the given font face.
/// </summary>
/// <param name="prototype">The font face prototype.</param>
/// <param name="criteria">The match criteria</param>
/// <returns>A list of fonts sorted by the closest match first.</returns>
IEnumerable<FontFace> Search(FontFace prototype, FontMatchCriteria criteria = FontMatchCriteria.All);
/// <summary>
/// Get the font face file info if it exists.
/// </summary>
/// <param name="face">The face to look for.</param>
/// <returns>The file info if it exists.</returns>
FileInfo FontFileInfo(FontFace face);
/// <summary>
/// Open a font face.
/// </summary>
/// <param name="face">The font face to open.</param>
/// <returns>The stream to the font face.</returns>
Stream Open(FontFace face);
}
}

@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
using Quik.Media;
using Quik.Typography;
using Quik.Media.Font;
namespace Quik
{
@ -109,9 +109,9 @@ namespace Quik
set => this["list-marker-position"] = value;
}
public QuikTexture ListMarkerImage
public QImage ListMarkerImage
{
get => (QuikTexture)this["list-marker-image"];
get => (QImage)this["list-marker-image"];
set => this["list-marker-image"] = value;
}
@ -127,9 +127,9 @@ namespace Quik
set => this["stroke-color"] = value;
}
public FontInfo Font
public FontFace Font
{
get => (FontInfo)this["font"];
get => (FontFace)this["font"];
set => this["font"] = value;
}