Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/NoelFB/Foster
Browse files Browse the repository at this point in the history
  • Loading branch information
MaddyThorson committed Sep 9, 2023
2 parents 26a0c25 + 59de634 commit 5221700
Show file tree
Hide file tree
Showing 15 changed files with 6,004 additions and 62 deletions.
49 changes: 49 additions & 0 deletions Framework/Graphics/Batch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1439,6 +1439,55 @@ public void ImageFit(in Subtexture subtex, in Rect rect, in Vector2 justify, Col

#endregion

#region SpriteFont

public void Text(SpriteFont font, ReadOnlySpan<char> text, Vector2 position, Color color)
{
Text(font, text, position, Vector2.Zero, color);
}

public void Text(SpriteFont font, ReadOnlySpan<char> text, Vector2 position, Vector2 justify, Color color)
{
// TODO:
// I feel like the vertical alignment is slightly off, but not sure how.

var at = position + new Vector2(0, font.Ascent);
var last = 0;

if (justify.X != 0)
at.X -= justify.X * font.WidthOfLine(text);

if (justify.Y != 0)
at.Y -= justify.Y * font.HeightOf(text);

for (int i = 0; i < text.Length; i ++)
{
if (text[i] == '\n')
{
at.X = position.X;
if (justify.X != 0 && i < text.Length - 1)
at.X -= justify.X * font.WidthOfLine(text[(i + 1)..]);
at.Y += font.LineHeight;
last = 0;
continue;
}

if (font.TryGetCharacter(text, i, out var ch, out var step))
{
if (last != 0)
at.X += font.GetKerning(last, ch.Codepoint);

Image(ch.Subtexture, at + ch.Offset, color);

last = ch.Codepoint;
at.X += ch.Advance;
i += step - 1;
}
}
}

#endregion

#region Copy Arrays

/// <summary>
Expand Down
168 changes: 149 additions & 19 deletions Framework/Graphics/Mesh.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,29 @@ public class Mesh : IResource
{
public string Name { get; set; } = string.Empty;
public bool IsDisposed => isDisposed;

/// <summary>
/// Number of Vertices in the Mesh
/// </summary>
public int VertexCount { get; private set; } = 0;

/// <summary>
/// Number of Indices in the Mesh
/// </summary>
public int IndexCount { get; private set; } = 0;

/// <summary>
/// Current Index Format
/// </summary>
public IndexFormat? IndexFormat { get; private set; }

/// <summary>
/// Current Vertex Format
/// </summary>
public VertexFormat? VertexFormat { get; private set; }

internal IntPtr resource;
internal bool isDisposed = false;
private VertexFormat currentFormat;

public Mesh()
{
Expand All @@ -26,49 +43,116 @@ public Mesh()
Dispose();
}

public unsafe void SetIndices<T>(ReadOnlySpan<T> indices) where T : struct
{
var format = true switch
private static IndexFormat GetIndexFormat<T>()
=> true switch
{
true when typeof(T) == typeof(short) => IndexFormat.Sixteen,
true when typeof(T) == typeof(ushort) => IndexFormat.Sixteen,
true when typeof(T) == typeof(int) => IndexFormat.ThirtyTwo,
true when typeof(T) == typeof(uint) => IndexFormat.ThirtyTwo,
true when typeof(T) == typeof(short) => Framework.IndexFormat.Sixteen,
true when typeof(T) == typeof(ushort) => Framework.IndexFormat.Sixteen,
true when typeof(T) == typeof(int) => Framework.IndexFormat.ThirtyTwo,
true when typeof(T) == typeof(uint) => Framework.IndexFormat.ThirtyTwo,
_ => throw new NotImplementedException(),
};

private static int GetIndexFormatSize(Framework.IndexFormat format)
=> format switch
{
Framework.IndexFormat.Sixteen => 2,
Framework.IndexFormat.ThirtyTwo => 4,
_ => throw new NotImplementedException(),
};

/// <summary>
/// Uploads the Index Data to the Mesh
/// </summary>
public unsafe void SetIndices<T>(ReadOnlySpan<T> indices) where T : struct
{
fixed (byte* ptr = MemoryMarshal.AsBytes(indices))
{
SetIndices(new IntPtr(ptr), indices.Length, format);
SetIndices(new IntPtr(ptr), indices.Length, GetIndexFormat<T>());
}
}

/// <summary>
/// Recreates the Index Data to a given size in the Mesh
/// </summary>
public unsafe void SetIndices<T>(int count, IndexFormat format) where T : struct
{
SetIndices(IntPtr.Zero, count, format);
}

/// <summary>
/// Uploads the Index data to the Mesh.
/// </summary>
public unsafe void SetIndices(IntPtr data, int count, IndexFormat format)
{
Debug.Assert(!IsDisposed, "Mesh is Disposed");

IndexCount = count;

int size = format switch
if (!IndexFormat.HasValue || IndexFormat.Value != format)
{
IndexFormat.Sixteen => 2,
IndexFormat.ThirtyTwo => 4,
_ => throw new Exception()
};
IndexFormat = format;
Platform.FosterMeshSetIndexFormat(resource, format);
}

Platform.FosterMeshSetIndexData(
resource,
data,
GetIndexFormatSize(format) * count,
0
);
}

/// <summary>
/// Uploads a sub area of index data to the Mesh.
/// The Mesh must already be able to fit this with a previous call to SetIndices.
/// This also cannot modify the existing Index Format.
/// </summary>
public unsafe void SetSubIndices<T>(int offset, ReadOnlySpan<T> indices) where T : struct
{
Debug.Assert(IndexFormat.HasValue && IndexFormat.Value == GetIndexFormat<T>(),
"Index Format mismatch; SetSubIndices must use the existing Format set in SetIndices");

fixed (byte* ptr = MemoryMarshal.AsBytes(indices))
{
SetSubIndices(offset, new IntPtr(ptr), indices.Length);
}
}

/// <summary>
/// Uploads the Index data to the Mesh.
/// The Mesh must already be able to fit this with a previous call to SetIndices.
/// This also cannot modify the existing Index Format.
/// </summary>
public unsafe void SetSubIndices(int offset, IntPtr data, int count)
{
Debug.Assert(!IsDisposed, "Mesh is Disposed");
Debug.Assert(IndexFormat.HasValue, "Must call SetIndices before SetSubIndices");

if (offset + count > IndexCount)
throw new Exception("SetSubIndices is out of range of the existing Index Buffer");

var size = GetIndexFormatSize(IndexFormat.Value);

Platform.FosterMeshSetIndexFormat(resource, format);
Platform.FosterMeshSetIndexData(
resource,
data,
size * count
size * count,
size * offset
);
}

/// <summary>
/// Uploads the Vertex data to the Mesh.
/// </summary>
public unsafe void SetVertices<T>(ReadOnlySpan<T> vertices) where T : struct, IVertex
{
SetVertices(vertices, default(T).Format);
}

/// <summary>
/// Uploads the Vertex data to the Mesh.
/// </summary>
public unsafe void SetVertices<T>(ReadOnlySpan<T> vertices, VertexFormat format) where T : struct
{
fixed (byte* ptr = MemoryMarshal.AsBytes(vertices))
Expand All @@ -77,16 +161,27 @@ public unsafe void SetVertices<T>(ReadOnlySpan<T> vertices, VertexFormat format)
}
}

/// <summary>
/// Recreates the Vertex Data to a given size in the Mesh
/// </summary>
public unsafe void SetVertices(int count, VertexFormat format)
{
SetVertices(IntPtr.Zero, count, format);
}

/// <summary>
/// Uploads the Vertex data to the Mesh.
/// </summary>
public unsafe void SetVertices(IntPtr data, int count, VertexFormat format)
{
Debug.Assert(!IsDisposed, "Mesh is Disposed");

VertexCount = count;

// update vertex format
if (currentFormat != format)
if (!VertexFormat.HasValue || VertexFormat.Value != format)
{
currentFormat = format;
VertexFormat = format;

var elements = stackalloc Platform.FosterVertexElement[format.Elements.Length];
for (int i = 0; i < format.Elements.Length; i ++)
Expand All @@ -109,7 +204,42 @@ public unsafe void SetVertices(IntPtr data, int count, VertexFormat format)
Platform.FosterMeshSetVertexData(
resource,
data,
format.Stride * count
format.Stride * count,
0
);
}

/// <summary>
/// Uploads the Vertex data to the Mesh.
/// The Mesh must already be able to fit this with a previous call to SetVertices.
/// This also cannot modify the existing Vertex Format.
/// </summary>
public unsafe void SetSubVertices<T>(int offset, ReadOnlySpan<T> vertices) where T : struct
{
fixed (byte* ptr = MemoryMarshal.AsBytes(vertices))
{
SetSubVertices(offset, new IntPtr(ptr), vertices.Length);
}
}

/// <summary>
/// Uploads the Vertex data to the Mesh.
/// The Mesh must already be able to fit this with a previous call to SetVertices.
/// This also cannot modify the existing Vertex Format.
/// </summary>
public unsafe void SetSubVertices(int offset, IntPtr data, int count)
{
Debug.Assert(!IsDisposed, "Mesh is Disposed");
Debug.Assert(VertexFormat.HasValue, "Must call SetVertices before SetSubVertices");

if (offset + count > VertexCount)
throw new Exception("SetSubVertices is out of range of the existing Vertex Buffer");

Platform.FosterMeshSetVertexData(
resource,
data,
VertexFormat.Value.Stride * count,
VertexFormat.Value.Stride * offset
);
}

Expand Down
Loading

0 comments on commit 5221700

Please sign in to comment.