1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-30 13:26:00 +02:00

Merge branch 'master' into bufstream-fixes

This commit is contained in:
EinBurgbauer 2021-12-09 16:13:29 +01:00
commit 92738418eb
243 changed files with 19052 additions and 2933 deletions

View file

@ -7,7 +7,7 @@ StartupObject = "BeefBuild.Program"
[Platform.Windows] [Platform.Windows]
Description = "BeefBuild" Description = "BeefBuild"
FileVersion = "0.43.1" FileVersion = "0.43.2"
[Configs.Debug.Win32] [Configs.Debug.Win32]
TargetName = "" TargetName = ""

View file

@ -15,6 +15,9 @@ CLibType = "Static"
BeefLibType = "Static" BeefLibType = "Static"
PostBuildCmds = ["CopyToDependents(\"$(ProjectDir)/dist/BeefySysLib64_d.dll\")", "CopyToDependents(\"$(ProjectDir)/dist/BeefySysLib64_d.pdb\")"] PostBuildCmds = ["CopyToDependents(\"$(ProjectDir)/dist/BeefySysLib64_d.dll\")", "CopyToDependents(\"$(ProjectDir)/dist/BeefySysLib64_d.pdb\")"]
[Configs.Debug.Linux64]
PostBuildCmds = ["CopyToDependents(\"$(ProjectDir)/dist/libBeefySysLib_d.so\")"]
[Configs.Release.Win32] [Configs.Release.Win32]
OtherLinkFlags = "" OtherLinkFlags = ""
PreprocessorMacros = ["RELEASE", "BF32"] PreprocessorMacros = ["RELEASE", "BF32"]
@ -23,6 +26,9 @@ PreprocessorMacros = ["RELEASE", "BF32"]
OtherLinkFlags = "$(LinkFlags) $(ProjectDir)/dist/BeefySysLib64.lib" OtherLinkFlags = "$(LinkFlags) $(ProjectDir)/dist/BeefySysLib64.lib"
PostBuildCmds = ["CopyToDependents(\"$(ProjectDir)/dist/BeefySysLib64.dll\")", "CopyToDependents(\"$(ProjectDir)/dist/BeefySysLib64.pdb\")"] PostBuildCmds = ["CopyToDependents(\"$(ProjectDir)/dist/BeefySysLib64.dll\")", "CopyToDependents(\"$(ProjectDir)/dist/BeefySysLib64.pdb\")"]
[Configs.Release.Linux64]
PostBuildCmds = ["CopyToDependents(\"$(ProjectDir)/dist/libBeefySysLib.so\")"]
[Configs.Paranoid.Win32] [Configs.Paranoid.Win32]
CLibType = "Static" CLibType = "Static"
BeefLibType = "Static" BeefLibType = "Static"
@ -38,3 +44,15 @@ BeefLibType = "Static"
[Configs.Test.Win64] [Configs.Test.Win64]
CLibType = "Static" CLibType = "Static"
BeefLibType = "Static" BeefLibType = "Static"
[Configs.DebugOpt.Win32]
OtherLinkFlags = "$(LinkFlags) \"$(ProjectDir)/dist/BeefySysLib32_d.lib\""
BeefLibType = "Static"
PostBuildCmds = ["CopyToDependents(\"$(ProjectDir)/dist/BeefySysLib32_d.dll\")", "CopyToDependents(\"$(ProjectDir)/dist/BeefySysLib32_d.pdb\")"]
PreprocessorMacros = ["DEBUG", "BF32"]
[Configs.DebugOpt.Win64]
OtherLinkFlags = "$(LinkFlags) \"$(ProjectDir)/dist/BeefySysLib64.lib\""
CLibType = "Static"
BeefLibType = "Static"
PostBuildCmds = ["CopyToDependents(\"$(ProjectDir)/dist/BeefySysLib64.dll\")", "CopyToDependents(\"$(ProjectDir)/dist/BeefySysLib64.pdb\")"]

View file

@ -727,7 +727,7 @@ namespace Beefy
0.10f, 0.00f, 1.05f, 0, 0.10f, 0.00f, 1.05f, 0,
0, 0, 0, 1);*/ 0, 0, 0, 1);*/
mGraphics.SetShaderConstantData(0, &mColorMatrix.ValueRef, mColorMatrixDataDef); mGraphics.SetVertexShaderConstantData(0, &mColorMatrix.ValueRef, mColorMatrixDataDef);
} }
window.Draw(mGraphics); window.Draw(mGraphics);
window.PostDraw(mGraphics); window.PostDraw(mGraphics);

View file

@ -295,11 +295,13 @@ namespace Beefy
public static Result<void> WriteTextFile(StringView path, StringView text) public static Result<void> WriteTextFile(StringView path, StringView text)
{ {
var stream = scope FileStream(); var stream = scope UnbufferedFileStream();
if (stream.Create(path) case .Err) if (stream.Open(path, .OpenOrCreate, .Write) case .Err)
{
return .Err; return .Err;
}
if (stream.SetLength(text.Length) case .Err)
return .Err;
if (stream.WriteStrUnsized(text) case .Err) if (stream.WriteStrUnsized(text) case .Err)
return .Err; return .Err;

View file

@ -0,0 +1,14 @@
// This file contains portions of code from the FNA project (github.com/FNA-XNA/FNA),
// released under the Microsoft Public License
namespace Beefy.geom
{
class BoundingBox
{
public Vector3 Min;
public Vector3 Max;
public const int CornerCount = 8;
}
}

View file

@ -55,6 +55,19 @@ namespace Beefy.geom
this.m33 = m33; this.m33 = m33;
} }
public static Matrix4 CreateFromColumnMajor(
float m00, float m10, float m20, float m30,
float m01, float m11, float m21, float m31,
float m02, float m12, float m22, float m32,
float m03, float m13, float m23, float m33)
{
return .(
m00, m01, m02, m03,
m10, m11, m12, m13,
m20, m21, m22, m23,
m30, m31, m32, m33);
}
public static Matrix4 CreatePerspective(float width, float height, float nearPlaneDistance, float farPlaneDistance) public static Matrix4 CreatePerspective(float width, float height, float nearPlaneDistance, float farPlaneDistance)
{ {
Matrix4 matrix; Matrix4 matrix;
@ -190,25 +203,23 @@ namespace Beefy.geom
public static Matrix4 Multiply(Matrix4 m1, Matrix4 m2) public static Matrix4 Multiply(Matrix4 m1, Matrix4 m2)
{ {
Matrix4 r; Matrix4 r;
r.m00 = m1.m00 * m2.m00 + m1.m01 * m2.m10 + m1.m02 * m2.m20 + m1.m03 * m2.m30;
r.m01 = m1.m00 * m2.m01 + m1.m01 * m2.m11 + m1.m02 * m2.m21 + m1.m03 * m2.m31;
r.m02 = m1.m00 * m2.m02 + m1.m01 * m2.m12 + m1.m02 * m2.m22 + m1.m03 * m2.m32;
r.m03 = m1.m00 * m2.m03 + m1.m01 * m2.m13 + m1.m02 * m2.m23 + m1.m03 * m2.m33;
r.m10 = m1.m10 * m2.m00 + m1.m11 * m2.m10 + m1.m12 * m2.m20 + m1.m13 * m2.m30; r.m00 = (((m1.m00 * m2.m00) + (m1.m10 * m2.m01)) + (m1.m20 * m2.m02)) + (m1.m30 * m2.m03);
r.m11 = m1.m10 * m2.m01 + m1.m11 * m2.m11 + m1.m12 * m2.m21 + m1.m13 * m2.m31; r.m10 = (((m1.m00 * m2.m10) + (m1.m10 * m2.m11)) + (m1.m20 * m2.m12)) + (m1.m30 * m2.m13);
r.m12 = m1.m10 * m2.m02 + m1.m11 * m2.m12 + m1.m12 * m2.m22 + m1.m13 * m2.m32; r.m20 = (((m1.m00 * m2.m20) + (m1.m10 * m2.m21)) + (m1.m20 * m2.m22)) + (m1.m30 * m2.m23);
r.m13 = m1.m10 * m2.m03 + m1.m11 * m2.m13 + m1.m12 * m2.m23 + m1.m13 * m2.m33; r.m30 = (((m1.m00 * m2.m30) + (m1.m10 * m2.m31)) + (m1.m20 * m2.m32)) + (m1.m30 * m2.m33);
r.m01 = (((m1.m01 * m2.m00) + (m1.m11 * m2.m01)) + (m1.m21 * m2.m02)) + (m1.m31 * m2.m03);
r.m20 = m1.m20 * m2.m00 + m1.m21 * m2.m10 + m1.m22 * m2.m20 + m1.m23 * m2.m30; r.m11 = (((m1.m01 * m2.m10) + (m1.m11 * m2.m11)) + (m1.m21 * m2.m12)) + (m1.m31 * m2.m13);
r.m21 = m1.m20 * m2.m01 + m1.m21 * m2.m11 + m1.m22 * m2.m21 + m1.m23 * m2.m31; r.m21 = (((m1.m01 * m2.m20) + (m1.m11 * m2.m21)) + (m1.m21 * m2.m22)) + (m1.m31 * m2.m23);
r.m22 = m1.m20 * m2.m02 + m1.m21 * m2.m12 + m1.m22 * m2.m22 + m1.m23 * m2.m32; r.m31 = (((m1.m01 * m2.m30) + (m1.m11 * m2.m31)) + (m1.m21 * m2.m32)) + (m1.m31 * m2.m33);
r.m23 = m1.m20 * m2.m03 + m1.m21 * m2.m13 + m1.m22 * m2.m23 + m1.m23 * m2.m33; r.m02 = (((m1.m02 * m2.m00) + (m1.m12 * m2.m01)) + (m1.m22 * m2.m02)) + (m1.m32 * m2.m03);
r.m12 = (((m1.m02 * m2.m10) + (m1.m12 * m2.m11)) + (m1.m22 * m2.m12)) + (m1.m32 * m2.m13);
r.m30 = m1.m30 * m2.m00 + m1.m31 * m2.m10 + m1.m32 * m2.m20 + m1.m33 * m2.m30; r.m22 = (((m1.m02 * m2.m20) + (m1.m12 * m2.m21)) + (m1.m22 * m2.m22)) + (m1.m32 * m2.m23);
r.m31 = m1.m30 * m2.m01 + m1.m31 * m2.m11 + m1.m32 * m2.m21 + m1.m33 * m2.m31; r.m32 = (((m1.m02 * m2.m30) + (m1.m12 * m2.m31)) + (m1.m22 * m2.m32)) + (m1.m32 * m2.m33);
r.m32 = m1.m30 * m2.m02 + m1.m31 * m2.m12 + m1.m32 * m2.m22 + m1.m33 * m2.m32; r.m03 = (((m1.m03 * m2.m00) + (m1.m13 * m2.m01)) + (m1.m23 * m2.m02)) + (m1.m33 * m2.m03);
r.m33 = m1.m30 * m2.m03 + m1.m31 * m2.m13 + m1.m32 * m2.m23 + m1.m33 * m2.m33; r.m13 = (((m1.m03 * m2.m10) + (m1.m13 * m2.m11)) + (m1.m23 * m2.m12)) + (m1.m33 * m2.m13);
r.m23 = (((m1.m03 * m2.m20) + (m1.m13 * m2.m21)) + (m1.m23 * m2.m22)) + (m1.m33 * m2.m23);
r.m33 = (((m1.m03 * m2.m30) + (m1.m13 * m2.m31)) + (m1.m23 * m2.m32)) + (m1.m33 * m2.m33);
return r; return r;
} }
@ -489,5 +500,730 @@ namespace Beefy.geom
r20, r21, r22, r23, r20, r21, r22, r23,
0, 0, 0, 1); 0, 0, 0, 1);
} }
public static void Invert(Matrix4 matrix, out Matrix4 result)
{
float num1 = matrix.m00;
float num2 = matrix.m10;
float num3 = matrix.m20;
float num4 = matrix.m30;
float num5 = matrix.m01;
float num6 = matrix.m11;
float num7 = matrix.m21;
float num8 = matrix.m31;
float num9 = matrix.m02;
float num10 = matrix.m12;
float num11 = matrix.m22;
float num12 = matrix.m32;
float num13 = matrix.m03;
float num14 = matrix.m13;
float num15 = matrix.m23;
float num16 = matrix.m33;
float num17 = (float) ((double) num11 * (double) num16 - (double) num12 * (double) num15);
float num18 = (float) ((double) num10 * (double) num16 - (double) num12 * (double) num14);
float num19 = (float) ((double) num10 * (double) num15 - (double) num11 * (double) num14);
float num20 = (float) ((double) num9 * (double) num16 - (double) num12 * (double) num13);
float num21 = (float) ((double) num9 * (double) num15 - (double) num11 * (double) num13);
float num22 = (float) ((double) num9 * (double) num14 - (double) num10 * (double) num13);
float num23 = (float) ((double) num6 * (double) num17 - (double) num7 * (double) num18 + (double) num8 * (double) num19);
float num24 = (float) -((double) num5 * (double) num17 - (double) num7 * (double) num20 + (double) num8 * (double) num21);
float num25 = (float) ((double) num5 * (double) num18 - (double) num6 * (double) num20 + (double) num8 * (double) num22);
float num26 = (float) -((double) num5 * (double) num19 - (double) num6 * (double) num21 + (double) num7 * (double) num22);
float num27 = (float) (1.0 / ((double) num1 * (double) num23 + (double) num2 * (double) num24 + (double) num3 * (double) num25 + (double) num4 * (double) num26));
result.m00 = num23 * num27;
result.m01 = num24 * num27;
result.m02 = num25 * num27;
result.m03 = num26 * num27;
result.m10 = (float)(-((double) num2 * (double) num17 - (double) num3 * (double) num18 + (double) num4 * (double) num19) * num27);
result.m11 = (float) ((double) num1 * (double) num17 - (double) num3 * (double) num20 + (double) num4 * (double) num21) * num27;
result.m12 = (float)(-((double) num1 * (double) num18 - (double) num2 * (double) num20 + (double) num4 * (double) num22) * num27);
result.m13 = (float) ((double) num1 * (double) num19 - (double) num2 * (double) num21 + (double) num3 * (double) num22) * num27;
float num28 = (float) ((double) num7 * (double) num16 - (double) num8 * (double) num15);
float num29 = (float) ((double) num6 * (double) num16 - (double) num8 * (double) num14);
float num30 = (float) ((double) num6 * (double) num15 - (double) num7 * (double) num14);
float num31 = (float) ((double) num5 * (double) num16 - (double) num8 * (double) num13);
float num32 = (float) ((double) num5 * (double) num15 - (double) num7 * (double) num13);
float num33 = (float) ((double) num5 * (double) num14 - (double) num6 * (double) num13);
result.m20 = (float) ((double) num2 * (double) num28 - (double) num3 * (double) num29 + (double) num4 * (double) num30) * num27;
result.m21 = (float)(-((double) num1 * (double) num28 - (double) num3 * (double) num31 + (double) num4 * (double) num32) * num27);
result.m22 = (float) ((double) num1 * (double) num29 - (double) num2 * (double) num31 + (double) num4 * (double) num33) * num27;
result.m23 = (float)(-((double) num1 * (double) num30 - (double) num2 * (double) num32 + (double) num3 * (double) num33) * num27);
float num34 = (float) ((double) num7 * (double) num12 - (double) num8 * (double) num11);
float num35 = (float) ((double) num6 * (double) num12 - (double) num8 * (double) num10);
float num36 = (float) ((double) num6 * (double) num11 - (double) num7 * (double) num10);
float num37 = (float) ((double) num5 * (double) num12 - (double) num8 * (double) num9);
float num38 = (float) ((double) num5 * (double) num11 - (double) num7 * (double) num9);
float num39 = (float) ((double) num5 * (double) num10 - (double) num6 * (double) num9);
result.m30 = (float)(-((double) num2 * (double) num34 - (double) num3 * (double) num35 + (double) num4 * (double) num36) * num27);
result.m31 = (float) ((double) num1 * (double) num34 - (double) num3 * (double) num37 + (double) num4 * (double) num38) * num27;
result.m32 = (float)(-((double) num1 * (double) num35 - (double) num2 * (double) num37 + (double) num4 * (double) num39) * num27);
result.m33 = (float) ((double) num1 * (double) num36 - (double) num2 * (double) num38 + (double) num3 * (double) num39) * num27;
/*
///
// Use Laplace expansion theorem to calculate the inverse of a 4x4 matrix
//
// 1. Calculate the 2x2 determinants needed the 4x4 determinant based on the 2x2 determinants
// 3. Create the adjugate matrix, which satisfies: A * adj(A) = det(A) * I
// 4. Divide adjugate matrix with the determinant to find the inverse
float det1, det2, det3, det4, det5, det6, det7, det8, det9, det10, det11, det12;
float detMatrix;
FindDeterminants(ref matrix, out detMatrix, out det1, out det2, out det3, out det4, out det5, out det6,
out det7, out det8, out det9, out det10, out det11, out det12);
float invDetMatrix = 1f / detMatrix;
Matrix ret; // Allow for matrix and result to point to the same structure
ret.M11 = (matrix.M22*det12 - matrix.M23*det11 + matrix.M24*det10) * invDetMatrix;
ret.M12 = (-matrix.M12*det12 + matrix.M13*det11 - matrix.M14*det10) * invDetMatrix;
ret.M13 = (matrix.M42*det6 - matrix.M43*det5 + matrix.M44*det4) * invDetMatrix;
ret.M14 = (-matrix.M32*det6 + matrix.M33*det5 - matrix.M34*det4) * invDetMatrix;
ret.M21 = (-matrix.M21*det12 + matrix.M23*det9 - matrix.M24*det8) * invDetMatrix;
ret.M22 = (matrix.M11*det12 - matrix.M13*det9 + matrix.M14*det8) * invDetMatrix;
ret.M23 = (-matrix.M41*det6 + matrix.M43*det3 - matrix.M44*det2) * invDetMatrix;
ret.M24 = (matrix.M31*det6 - matrix.M33*det3 + matrix.M34*det2) * invDetMatrix;
ret.M31 = (matrix.M21*det11 - matrix.M22*det9 + matrix.M24*det7) * invDetMatrix;
ret.M32 = (-matrix.M11*det11 + matrix.M12*det9 - matrix.M14*det7) * invDetMatrix;
ret.M33 = (matrix.M41*det5 - matrix.M42*det3 + matrix.M44*det1) * invDetMatrix;
ret.M34 = (-matrix.M31*det5 + matrix.M32*det3 - matrix.M34*det1) * invDetMatrix;
ret.M41 = (-matrix.M21*det10 + matrix.M22*det8 - matrix.M23*det7) * invDetMatrix;
ret.M42 = (matrix.M11*det10 - matrix.M12*det8 + matrix.M13*det7) * invDetMatrix;
ret.M43 = (-matrix.M41*det4 + matrix.M42*det2 - matrix.M43*det1) * invDetMatrix;
ret.M44 = (matrix.M31*det4 - matrix.M32*det2 + matrix.M33*det1) * invDetMatrix;
result = ret;
*/
}
public static Matrix4 Invert(Matrix4 matrix)
{
Invert(matrix, var outMatrix);
return outMatrix;
}
/// <summary>
/// Decomposes this matrix to translation, rotation and scale elements. Returns <c>true</c> if matrix can be decomposed; <c>false</c> otherwise.
/// </summary>
/// <param name="scale">Scale vector as an output parameter.
/// <param name="rotation">Rotation quaternion as an output parameter.
/// <param name="translation">Translation vector as an output parameter.
/// <returns><c>true</c> if matrix can be decomposed; <c>false</c> otherwise.</returns>
public bool Decompose(
out Vector3 scale,
out Quaternion rotation,
out Vector3 translation
) {
translation.mX = m03;
translation.mY = m13;
translation.mZ = m23;
float xs = (Math.Sign(m00 * m10 * m20 * m30) < 0) ? -1 : 1;
float ys = (Math.Sign(m01 * m11 * m21 * m31) < 0) ? -1 : 1;
float zs = (Math.Sign(m02 * m12 * m22 * m32) < 0) ? -1 : 1;
scale.mX = xs * (float) Math.Sqrt(m00 * m00 + m10 * m10 + m20 * m20);
scale.mY = ys * (float) Math.Sqrt(m01 * m01 + m11 * m11 + m21 * m21);
scale.mZ = zs * (float) Math.Sqrt(m02 * m02 + m12 * m12 + m22 * m22);
if (Math.WithinEpsilon(scale.mX, 0.0f) ||
Math.WithinEpsilon(scale.mY, 0.0f) ||
Math.WithinEpsilon(scale.mZ, 0.0f) )
{
rotation = Quaternion.Identity;
return false;
}
Matrix4 m1 = Matrix4.CreateFromColumnMajor(
m00 / scale.mX, m10 / scale.mX, m20 / scale.mX, 0,
m01 / scale.mY, m11 / scale.mY, m21 / scale.mY, 0,
m02 / scale.mZ, m12 / scale.mZ, m22 / scale.mZ, 0,
0, 0, 0, 1
);
rotation = Quaternion.CreateFromRotationMatrix(m1);
return true;
}
/// <summary>
/// Returns a determinant of this matrix.
/// </summary>
/// <returns>Determinant of this matrix</returns>
/// <remarks>See more about determinant here - http://en.wikipedia.org/wiki/Determinant.
/// </remarks>
public float Determinant()
{
float num18 = (m22 * m33) - (m32 * m23);
float num17 = (m12 * m33) - (m32 * m13);
float num16 = (m12 * m23) - (m22 * m13);
float num15 = (m02 * m33) - (m32 * m03);
float num14 = (m02 * m23) - (m22 * m03);
float num13 = (m02 * m13) - (m12 * m03);
return (
(
(
(m00 * (((m11 * num18) - (m21 * num17)) + (m31 * num16))) -
(m10 * (((m01 * num18) - (m21 * num15)) + (m31 * num14)))
) + (m20 * (((m01 * num17) - (m11 * num15)) + (m31 * num13)))
) - (m30 * (((m01 * num16) - (m11 * num14)) + (m21 * num13)))
);
}
/// <summary>
/// Creates a new matrix for spherical billboarding that rotates around specified object position.
/// </summary>
/// <param name="objectPosition">Position of billboard object. It will rotate around that vector.
/// <param name="cameraPosition">The camera position.
/// <param name="cameraUpVector">The camera up vector.
/// <param name="cameraForwardVector">Optional camera forward vector.
/// <returns>The matrix for spherical billboarding.</returns>
public static Matrix4 CreateBillboard(
Vector3 objectPosition,
Vector3 cameraPosition,
Vector3 cameraUpVector,
Nullable<Vector3> cameraForwardVector
) {
Matrix4 result;
// Delegate to the other overload of the function to do the work
CreateBillboard(
objectPosition,
cameraPosition,
cameraUpVector,
cameraForwardVector,
out result
);
return result;
}
/// <summary>
/// Creates a new matrix for spherical billboarding that rotates around specified object position.
/// </summary>
/// <param name="objectPosition">Position of billboard object. It will rotate around that vector.
/// <param name="cameraPosition">The camera position.
/// <param name="cameraUpVector">The camera up vector.
/// <param name="cameraForwardVector">Optional camera forward vector.
/// <param name="result">The matrix for spherical billboarding as an output parameter.
public static void CreateBillboard(
Vector3 objectPosition,
Vector3 cameraPosition,
Vector3 cameraUpVector,
Vector3? cameraForwardVector,
out Matrix4 result
) {
Vector3 vector;
Vector3 vector2;
Vector3 vector3;
vector.mX = objectPosition.mX - cameraPosition.mX;
vector.mY = objectPosition.mY - cameraPosition.mY;
vector.mZ = objectPosition.mZ - cameraPosition.mZ;
float num = vector.LengthSquared;
if (num < 0.0001f)
{
vector = cameraForwardVector.HasValue ?
-cameraForwardVector.Value :
Vector3.Forward;
}
else
{
vector *= (float) (1f / ((float) Math.Sqrt((double) num)));
}
vector3 = Vector3.Cross(cameraUpVector, vector);
vector3.Normalize();
vector2 = Vector3.Cross(vector, vector3);
result.m00 = vector3.mX;
result.m10 = vector3.mY;
result.m20 = vector3.mZ;
result.m30 = 0;
result.m01 = vector2.mX;
result.m11 = vector2.mY;
result.m21 = vector2.mZ;
result.m31 = 0;
result.m02 = vector.mX;
result.m12 = vector.mY;
result.m22 = vector.mZ;
result.m32 = 0;
result.m03 = objectPosition.mX;
result.m13 = objectPosition.mY;
result.m23 = objectPosition.mZ;
result.m33 = 1;
}
/// <summary>
/// Creates a new matrix for cylindrical billboarding that rotates around specified axis.
/// </summary>
/// <param name="objectPosition">Object position the billboard will rotate around.
/// <param name="cameraPosition">Camera position.
/// <param name="rotateAxis">Axis of billboard for rotation.
/// <param name="cameraForwardVector">Optional camera forward vector.
/// <param name="objectForwardVector">Optional object forward vector.
/// <returns>The matrix for cylindrical billboarding.</returns>
public static Matrix4 CreateConstrainedBillboard(
Vector3 objectPosition,
Vector3 cameraPosition,
Vector3 rotateAxis,
Nullable<Vector3> cameraForwardVector,
Nullable<Vector3> objectForwardVector
) {
Matrix4 result;
CreateConstrainedBillboard(
objectPosition,
cameraPosition,
rotateAxis,
cameraForwardVector,
objectForwardVector,
out result
);
return result;
}
/// <summary>
/// Creates a new matrix for cylindrical billboarding that rotates around specified axis.
/// </summary>
/// <param name="objectPosition">Object position the billboard will rotate around.
/// <param name="cameraPosition">Camera position.
/// <param name="rotateAxis">Axis of billboard for rotation.
/// <param name="cameraForwardVector">Optional camera forward vector.
/// <param name="objectForwardVector">Optional object forward vector.
/// <param name="result">The matrix for cylindrical billboarding as an output parameter.
public static void CreateConstrainedBillboard(
Vector3 objectPosition,
Vector3 cameraPosition,
Vector3 rotateAxis,
Vector3? cameraForwardVector,
Vector3? objectForwardVector,
out Matrix4 result
) {
float num;
Vector3 vector;
Vector3 vector2;
Vector3 vector3;
vector2.mX = objectPosition.mX - cameraPosition.mX;
vector2.mY = objectPosition.mY - cameraPosition.mY;
vector2.mZ = objectPosition.mZ - cameraPosition.mZ;
float num2 = vector2.LengthSquared;
if (num2 < 0.0001f)
{
vector2 = cameraForwardVector.HasValue ?
-cameraForwardVector.Value :
Vector3.Forward;
}
else
{
vector2 *= (float) (1f / ((float) Math.Sqrt((double) num2)));
}
Vector3 vector4 = rotateAxis;
num = Vector3.Dot(rotateAxis, vector2);
if (Math.Abs(num) > 0.9982547f)
{
if (objectForwardVector.HasValue)
{
vector = objectForwardVector.Value;
num = Vector3.Dot(rotateAxis, vector);
if (Math.Abs(num) > 0.9982547f)
{
num = (
(rotateAxis.mX * Vector3.Forward.mX) +
(rotateAxis.mY * Vector3.Forward.mY)
) + (rotateAxis.mZ * Vector3.Forward.mZ);
vector = (Math.Abs(num) > 0.9982547f) ?
Vector3.Right :
Vector3.Forward;
}
}
else
{
num = (
(rotateAxis.mX * Vector3.Forward.mX) +
(rotateAxis.mY * Vector3.Forward.mY)
) + (rotateAxis.mZ * Vector3.Forward.mZ);
vector = (Math.Abs(num) > 0.9982547f) ?
Vector3.Right :
Vector3.Forward;
}
vector3 = Vector3.Cross(rotateAxis, vector);
vector3.Normalize();
vector = Vector3.Cross(vector3, rotateAxis);
vector.Normalize();
}
else
{
vector3 = Vector3.Cross(rotateAxis, vector2);
vector3.Normalize();
vector = Vector3.Cross(vector3, vector4);
vector.Normalize();
}
result.m00 = vector3.mX;
result.m10 = vector3.mY;
result.m20 = vector3.mZ;
result.m30 = 0;
result.m01 = vector4.mX;
result.m11 = vector4.mY;
result.m21 = vector4.mZ;
result.m31 = 0;
result.m02 = vector.mX;
result.m12 = vector.mY;
result.m22 = vector.mZ;
result.m32 = 0;
result.m03 = objectPosition.mX;
result.m13 = objectPosition.mY;
result.m23 = objectPosition.mZ;
result.m33 = 1;
}
/// <summary>
/// Creates a new matrix which contains the rotation moment around specified axis.
/// </summary>
/// <param name="axis">The axis of rotation.
/// <param name="angle">The angle of rotation in radians.
/// <returns>The rotation matrix.</returns>
public static Matrix4 CreateFromAxisAngle(Vector3 axis, float angle)
{
Matrix4 result;
CreateFromAxisAngle(axis, angle, out result);
return result;
}
/// <summary>
/// Creates a new matrix which contains the rotation moment around specified axis.
/// </summary>
/// <param name="axis">The axis of rotation.
/// <param name="angle">The angle of rotation in radians.
/// <param name="result">The rotation matrix as an output parameter.
public static void CreateFromAxisAngle(
Vector3 axis,
float angle,
out Matrix4 result
) {
float x = axis.mX;
float y = axis.mY;
float z = axis.mZ;
float num2 = (float) Math.Sin((double) angle);
float num = (float) Math.Cos((double) angle);
float num11 = x * x;
float num10 = y * y;
float num9 = z * z;
float num8 = x * y;
float num7 = x * z;
float num6 = y * z;
result.m00 = num11 + (num * (1f - num11));
result.m10 = (num8 - (num * num8)) + (num2 * z);
result.m20 = (num7 - (num * num7)) - (num2 * y);
result.m30 = 0;
result.m01 = (num8 - (num * num8)) - (num2 * z);
result.m11 = num10 + (num * (1f - num10));
result.m21 = (num6 - (num * num6)) + (num2 * x);
result.m31 = 0;
result.m02 = (num7 - (num * num7)) + (num2 * y);
result.m12 = (num6 - (num * num6)) - (num2 * x);
result.m22 = num9 + (num * (1f - num9));
result.m32 = 0;
result.m03 = 0;
result.m13 = 0;
result.m23 = 0;
result.m33 = 1;
}
/// <summary>
/// Creates a new rotation matrix from a <see cref="Quaternion"/>.
/// </summary>
/// <param name="quaternion"><see cref="Quaternion"/> of rotation moment.
/// <returns>The rotation matrix.</returns>
public static Matrix4 CreateFromQuaternion(Quaternion quaternion)
{
Matrix4 result;
CreateFromQuaternion(quaternion, out result);
return result;
}
/// <summary>
/// Creates a new rotation matrix from a <see cref="Quaternion"/>.
/// </summary>
/// <param name="quaternion"><see cref="Quaternion"/> of rotation moment.
/// <param name="result">The rotation matrix as an output parameter.
public static void CreateFromQuaternion(Quaternion quaternion, out Matrix4 result)
{
float num9 = quaternion.mX * quaternion.mX;
float num8 = quaternion.mY * quaternion.mY;
float num7 = quaternion.mZ * quaternion.mZ;
float num6 = quaternion.mX * quaternion.mY;
float num5 = quaternion.mZ * quaternion.mW;
float num4 = quaternion.mZ * quaternion.mX;
float num3 = quaternion.mY * quaternion.mW;
float num2 = quaternion.mY * quaternion.mZ;
float num = quaternion.mX * quaternion.mW;
result.m00 = 1f - (2f * (num8 + num7));
result.m10 = 2f * (num6 + num5);
result.m20 = 2f * (num4 - num3);
result.m30 = 0f;
result.m01 = 2f * (num6 - num5);
result.m11 = 1f - (2f * (num7 + num9));
result.m21 = 2f * (num2 + num);
result.m31 = 0f;
result.m02 = 2f * (num4 + num3);
result.m12 = 2f * (num2 - num);
result.m22 = 1f - (2f * (num8 + num9));
result.m32 = 0f;
result.m03 = 0f;
result.m13 = 0f;
result.m23 = 0f;
result.m33 = 1f;
}
/// Creates a new rotation matrix from the specified yaw, pitch and roll values.
/// @param yaw The yaw rotation value in radians.
/// @param pitch The pitch rotation value in radians.
/// @param roll The roll rotation value in radians.
/// @returns The rotation matrix
/// @remarks For more information about yaw, pitch and roll visit http://en.wikipedia.org/wiki/Euler_angles.
public static Matrix4 CreateFromYawPitchRoll(float yaw, float pitch, float roll)
{
Matrix4 matrix;
CreateFromYawPitchRoll(yaw, pitch, roll, out matrix);
return matrix;
}
/// Creates a new rotation matrix from the specified yaw, pitch and roll values.
/// @param yaw The yaw rotation value in radians.
/// @param pitch The pitch rotation value in radians.
/// @param roll The roll rotation value in radians.
/// @param result The rotation matrix as an output parameter.
/// @remarks>For more information about yaw, pitch and roll visit http://en.wikipedia.org/wiki/Euler_angles.
public static void CreateFromYawPitchRoll(
float yaw,
float pitch,
float roll,
out Matrix4 result
) {
Quaternion quaternion;
Quaternion.CreateFromYawPitchRoll(yaw, pitch, roll, out quaternion);
CreateFromQuaternion(quaternion, out result);
}
/// Creates a new viewing matrix.
/// @param cameraPosition Position of the camera.
/// @param cameraTarget Lookup vector of the camera.
/// @param cameraUpVector The direction of the upper edge of the camera.
/// @returns The viewing matrix.
public static Matrix4 CreateLookAt(
Vector3 cameraPosition,
Vector3 cameraTarget,
Vector3 cameraUpVector
) {
Matrix4 matrix;
CreateLookAt(cameraPosition, cameraTarget, cameraUpVector, out matrix);
return matrix;
}
/// Creates a new viewing matrix.
/// @param cameraPosition Position of the camera.
/// @param cameraTarget Lookup vector of the camera.
/// @param cameraUpVector The direction of the upper edge of the camera.
/// @param result The viewing matrix as an output parameter.
public static void CreateLookAt(
Vector3 cameraPosition,
Vector3 cameraTarget,
Vector3 cameraUpVector,
out Matrix4 result
) {
Vector3 vectorA = Vector3.Normalize(cameraPosition - cameraTarget);
Vector3 vectorB = Vector3.Normalize(Vector3.Cross(cameraUpVector, vectorA));
Vector3 vectorC = Vector3.Cross(vectorA, vectorB);
result.m00 = vectorB.mX;
result.m10 = vectorC.mX;
result.m20 = vectorA.mX;
result.m30 = 0f;
result.m01 = vectorB.mY;
result.m11 = vectorC.mY;
result.m21 = vectorA.mY;
result.m31 = 0f;
result.m02 = vectorB.mZ;
result.m12 = vectorC.mZ;
result.m22 = vectorA.mZ;
result.m32 = 0f;
result.m03 = -Vector3.Dot(vectorB, cameraPosition);
result.m13 = -Vector3.Dot(vectorC, cameraPosition);
result.m23 = -Vector3.Dot(vectorA, cameraPosition);
result.m33 = 1f;
}
/// Creates a new projection matrix for orthographic view.
/// @param width Width of the viewing volume.
/// @param height Height of the viewing volume.
/// @param zNearPlane Depth of the near plane.
/// @param zFarPlane Depth of the far plane.
/// @returns The new projection matrix for orthographic view.</returns>
public static Matrix4 CreateOrthographic(
float width,
float height,
float zNearPlane,
float zFarPlane
) {
Matrix4 matrix;
CreateOrthographic(width, height, zNearPlane, zFarPlane, out matrix);
return matrix;
}
/// Creates a new projection matrix for orthographic view.
/// @param width Width of the viewing volume.
/// @param height Height of the viewing volume.
/// @param zNearPlane Depth of the near plane.
/// @param zFarPlane Depth of the far plane.
/// @param result The new projection matrix for orthographic view as an output parameter.
public static void CreateOrthographic(
float width,
float height,
float zNearPlane,
float zFarPlane,
out Matrix4 result
) {
result.m00 = 2f / width;
result.m10 = result.m20 = result.m30 = 0f;
result.m11 = 2f / height;
result.m01 = result.m21 = result.m31 = 0f;
result.m22 = 1f / (zNearPlane - zFarPlane);
result.m02 = result.m12 = result.m32 = 0f;
result.m03 = result.m13 = 0f;
result.m23 = zNearPlane / (zNearPlane - zFarPlane);
result.m33 = 1f;
}
/// Creates a new projection matrix for customized orthographic view.
/// @param left Lower x-value at the near plane.
/// @param right Upper x-value at the near plane.
/// @param bottom Lower y-coordinate at the near plane.
/// @param top Upper y-value at the near plane.
/// @param zNearPlane Depth of the near plane.
/// @param zFarPlane Depth of the far plane.
/// @returns The new projection matrix for customized orthographic view.</returns>
public static Matrix4 CreateOrthographicOffCenter(
float left,
float right,
float bottom,
float top,
float zNearPlane,
float zFarPlane
) {
Matrix4 matrix;
CreateOrthographicOffCenter(
left,
right,
bottom,
top,
zNearPlane,
zFarPlane,
out matrix
);
return matrix;
}
/// Creates a new projection matrix for customized orthographic view.
/// @param left Lower x-value at the near plane.
/// @param right Upper x-value at the near plane.
/// @param bottom Lower y-coordinate at the near plane.
/// @param top Upper y-value at the near plane.
/// @param zNearPlane Depth of the near plane.
/// @param zFarPlane Depth of the far plane.
/// @param result The new projection matrix for customized orthographic view as an output parameter.
public static void CreateOrthographicOffCenter(
float left,
float right,
float bottom,
float top,
float zNearPlane,
float zFarPlane,
out Matrix4 result
)
{
result.m00 = (float) (2.0 / ((double) right - (double) left));
result.m10 = 0.0f;
result.m20 = 0.0f;
result.m30 = 0.0f;
result.m01 = 0.0f;
result.m11 = (float) (2.0 / ((double) top - (double) bottom));
result.m21 = 0.0f;
result.m31 = 0.0f;
result.m02 = 0.0f;
result.m12 = 0.0f;
result.m22 = (float) (1.0 / ((double) zNearPlane - (double) zFarPlane));
result.m32 = 0.0f;
result.m03 = (float) (
((double) left + (double) right) /
((double) left - (double) right)
);
result.m13 = (float) (
((double) top + (double) bottom) /
((double) bottom - (double) top)
);
result.m23 = (float) (
(double) zNearPlane /
((double) zNearPlane - (double) zFarPlane)
);
result.m33 = 1.0f;
}
/// Creates a new matrix that flattens geometry into a specified <see cref="Plane"/> as if casting a shadow from a specified light source.
/// @param lightDirection A vector specifying the direction from which the light that will cast the shadow is coming.
/// @param plane The plane onto which the new matrix should flatten geometry so as to cast a shadow.
/// @returns>A matrix that can be used to flatten geometry onto the specified plane from the specified direction.
public static Matrix4 CreateShadow(Vector3 lightDirection, Plane plane)
{
Matrix4 result;
result = CreateShadow(lightDirection, plane);
return result;
}
/// Creates a new matrix that flattens geometry into a specified <see cref="Plane"/> as if casting a shadow from a specified light source.
/// @param lightDirection A vector specifying the direction from which the light that will cast the shadow is coming.
/// @param plane The plane onto which the new matrix should flatten geometry so as to cast a shadow.
/// @param result A matrix that can be used to flatten geometry onto the specified plane from the specified direction as an output parameter.
public static void CreateShadow(
Vector3 lightDirection,
Plane plane,
out Matrix4 result)
{
float dot = (
(plane.Normal.mX * lightDirection.mX) +
(plane.Normal.mY * lightDirection.mY) +
(plane.Normal.mZ * lightDirection.mZ)
);
float x = -plane.Normal.mX;
float y = -plane.Normal.mY;
float z = -plane.Normal.mZ;
float d = -plane.D;
result.m00 = (x * lightDirection.mX) + dot;
result.m10 = x * lightDirection.mY;
result.m20 = x * lightDirection.mZ;
result.m30 = 0;
result.m01 = y * lightDirection.mX;
result.m11 = (y * lightDirection.mY) + dot;
result.m21 = y * lightDirection.mZ;
result.m31 = 0;
result.m02 = z * lightDirection.mX;
result.m12 = z * lightDirection.mY;
result.m22 = (z * lightDirection.mZ) + dot;
result.m32 = 0;
result.m03 = d * lightDirection.mX;
result.m13 = d * lightDirection.mY;
result.m23 = d * lightDirection.mZ;
result.m33 = dot;
}
public override void ToString(System.String strBuffer)
{
for (int row < 4)
for (int col < 4)
{
#unwarn
strBuffer.AppendF($"M{row+1}{col+1}:{((float*)&this)[row+col*4]}\n");
}
}
} }
} }

View file

@ -0,0 +1,291 @@
// This file contains portions of code from the FNA project (github.com/FNA-XNA/FNA),
// released under the Microsoft Public License
using System;
namespace Beefy.geom
{
/// <summary>
/// Defines the intersection between a <see cref="Plane"/> and a bounding volume.
/// </summary>
public enum PlaneIntersectionType
{
/// <summary>
/// There is no intersection, the bounding volume is in the negative half space of the plane.
/// </summary>
Front,
/// <summary>
/// There is no intersection, the bounding volume is in the positive half space of the plane.
/// </summary>
Back,
/// <summary>
/// The plane is intersected.
/// </summary>
Intersecting
}
public struct Plane
{
public Vector3 Normal;
public float D;
public this(Vector4 value)
: this(Vector3(value.mX, value.mY, value.mZ), value.mW)
{
}
public this(Vector3 normal, float d)
{
Normal = normal;
D = d;
}
public this(Vector3 a, Vector3 b, Vector3 c)
{
Vector3 ab = b - a;
Vector3 ac = c - a;
Vector3 cross = Vector3.Cross(ab, ac);
Vector3.Normalize(cross, out Normal);
D = -(Vector3.Dot(Normal, a));
}
public this(float a, float b, float c, float d)
: this(Vector3(a, b, c), d)
{
}
public float Dot(Vector4 value)
{
return (
(this.Normal.mX * value.mX) +
(this.Normal.mY * value.mY) +
(this.Normal.mZ * value.mZ) +
(this.D * value.mW)
);
}
public void Dot(ref Vector4 value, out float result)
{
result = (
(this.Normal.mX * value.mX) +
(this.Normal.mY * value.mY) +
(this.Normal.mZ * value.mZ) +
(this.D * value.mW)
);
}
public float DotCoordinate(Vector3 value)
{
return (
(this.Normal.mX * value.mX) +
(this.Normal.mY * value.mY) +
(this.Normal.mZ * value.mZ) +
this.D
);
}
public void DotCoordinate(ref Vector3 value, out float result)
{
result = (
(this.Normal.mX * value.mX) +
(this.Normal.mY * value.mY) +
(this.Normal.mZ * value.mZ) +
this.D
);
}
public float DotNormal(Vector3 value)
{
return (
(this.Normal.mX * value.mX) +
(this.Normal.mY * value.mY) +
(this.Normal.mZ * value.mZ)
);
}
public void DotNormal(Vector3 value, out float result)
{
result = (
(this.Normal.mX * value.mX) +
(this.Normal.mY * value.mY) +
(this.Normal.mZ * value.mZ)
);
}
public void Normalize() mut
{
float length = Normal.Length;
float factor = 1.0f / length;
Normal = Vector3.Multiply(Normal, factor);
D = D * factor;
}
/*public PlaneIntersectionType Intersects(BoundingBox box)
{
return box.Intersects(this);
}
public void Intersects(ref BoundingBox box, out PlaneIntersectionType result)
{
box.Intersects(ref this, out result);
}
public PlaneIntersectionType Intersects(BoundingSphere sphere)
{
return sphere.Intersects(this);
}
public void Intersects(ref BoundingSphere sphere, out PlaneIntersectionType result)
{
sphere.Intersects(ref this, out result);
}
public PlaneIntersectionType Intersects(BoundingFrustum frustum)
{
return frustum.Intersects(this);
}*/
#endregion
#region Internal Methods
internal PlaneIntersectionType Intersects(ref Vector3 point)
{
float distance;
DotCoordinate(ref point, out distance);
if (distance > 0)
{
return PlaneIntersectionType.Front;
}
if (distance < 0)
{
return PlaneIntersectionType.Back;
}
return PlaneIntersectionType.Intersecting;
}
#endregion
#region Public Static Methods
public static Plane Normalize(Plane value)
{
Plane ret;
Normalize(value, out ret);
return ret;
}
public static void Normalize(Plane value, out Plane result)
{
float length = value.Normal.Length;
float factor = 1.0f / length;
result.Normal = Vector3.Multiply(value.Normal, factor);
result.D = value.D * factor;
}
/// <summary>
/// Transforms a normalized plane by a matrix.
/// </summary>
/// <param name="plane">The normalized plane to transform.</param>
/// <param name="matrix">The transformation matrix.</param>
/// <returns>The transformed plane.</returns>
public static Plane Transform(Plane plane, Matrix4 matrix)
{
Plane result;
Transform(plane, matrix, out result);
return result;
}
/// <summary>
/// Transforms a normalized plane by a matrix.
/// </summary>
/// <param name="plane">The normalized plane to transform.</param>
/// <param name="matrix">The transformation matrix.</param>
/// <param name="result">The transformed plane.</param>
public static void Transform(
Plane plane,
Matrix4 matrix,
out Plane result
) {
/* See "Transforming Normals" in
* http://www.glprogramming.com/red/appendixf.html
* for an explanation of how this works.
*/
Matrix4 transformedMatrix;
transformedMatrix = Matrix4.Invert(matrix);
transformedMatrix = Matrix4.Transpose(transformedMatrix);
Vector4 vector = Vector4(plane.Normal, plane.D);
Vector4 transformedVector;
Vector4.Transform(
vector,
transformedMatrix,
out transformedVector
);
result = Plane(transformedVector);
}
/// <summary>
/// Transforms a normalized plane by a quaternion rotation.
/// </summary>
/// <param name="plane">The normalized plane to transform.</param>
/// <param name="rotation">The quaternion rotation.</param>
/// <returns>The transformed plane.</returns>
public static Plane Transform(Plane plane, Quaternion rotation)
{
Plane result;
Transform(plane, rotation, out result);
return result;
}
/// <summary>
/// Transforms a normalized plane by a quaternion rotation.
/// </summary>
/// <param name="plane">The normalized plane to transform.</param>
/// <param name="rotation">The quaternion rotation.</param>
/// <param name="result">The transformed plane.</param>
public static void Transform(
Plane plane,
Quaternion rotation,
out Plane result
) {
result.Normal = Vector3.Transform(
plane.Normal,
rotation
);
result.D = plane.D;
}
#endregion
#region Public Static Operators and Override Methods
public static bool operator !=(Plane plane1, Plane plane2)
{
return !plane1.Equals(plane2);
}
public static bool operator ==(Plane plane1, Plane plane2)
{
return plane1.Equals(plane2);
}
public bool Equals(Plane other)
{
return (Normal == other.Normal && D == other.D);
}
public int GetHashCode()
{
return Normal.GetHashCode() ^ D.GetHashCode();
}
public override void ToString(String str)
{
str.AppendF($"{Normal:{Normal} D:{D}}");
}
#endregion
}
}

View file

@ -1,3 +1,6 @@
// This file contains portions of code from the FNA project (github.com/FNA-XNA/FNA),
// released under the Microsoft Public License
using System; using System;
using Beefy.gfx; using Beefy.gfx;
@ -189,42 +192,49 @@ namespace Beefy.geom
public static void CreateFromRotationMatrix(ref Matrix4 matrix, out Quaternion result) public static void CreateFromRotationMatrix(ref Matrix4 matrix, out Quaternion result)
{ {
float num8 = (matrix.m11 + matrix.m22) + matrix.m33; float sqrt;
if (num8 > 0f) float half;
float scale = matrix.m00 + matrix.m11 + matrix.m22;
if (scale > 0.0f)
{ {
float num = (float)Math.Sqrt((double)(num8 + 1f)); sqrt = (float) Math.Sqrt(scale + 1.0f);
result.mW = num * 0.5f; result.mW = sqrt * 0.5f;
num = 0.5f / num; sqrt = 0.5f / sqrt;
result.mX = (matrix.m23 - matrix.m32) * num;
result.mY = (matrix.m31 - matrix.m13) * num; result.mX = (matrix.m21 - matrix.m12) * sqrt;
result.mZ = (matrix.m12 - matrix.m21) * num; result.mY = (matrix.m02 - matrix.m20) * sqrt;
result.mZ = (matrix.m10 - matrix.m01) * sqrt;
} }
else if ((matrix.m11 >= matrix.m22) && (matrix.m11 >= matrix.m33)) else if ((matrix.m00 >= matrix.m11) && (matrix.m00 >= matrix.m22))
{ {
float num7 = (float)Math.Sqrt((double)(((1f + matrix.m11) - matrix.m22) - matrix.m33)); sqrt = (float) Math.Sqrt(1.0f + matrix.m00 - matrix.m11 - matrix.m22);
float num4 = 0.5f / num7; half = 0.5f / sqrt;
result.mX = 0.5f * num7;
result.mY = (matrix.m12 + matrix.m21) * num4; result.mX = 0.5f * sqrt;
result.mZ = (matrix.m13 + matrix.m31) * num4; result.mY = (matrix.m10 + matrix.m01) * half;
result.mW = (matrix.m23 - matrix.m32) * num4; result.mZ = (matrix.m20 + matrix.m02) * half;
result.mW = (matrix.m21 - matrix.m12) * half;
} }
else if (matrix.m22 > matrix.m33) else if (matrix.m11 > matrix.m22)
{ {
float num6 = (float)Math.Sqrt((double)(((1f + matrix.m22) - matrix.m11) - matrix.m33)); sqrt = (float) Math.Sqrt(1.0f + matrix.m11 - matrix.m00 - matrix.m22);
float num3 = 0.5f / num6; half = 0.5f/sqrt;
result.mX = (matrix.m21 + matrix.m12) * num3;
result.mY = 0.5f * num6; result.mX = (matrix.m01 + matrix.m10)*half;
result.mZ = (matrix.m32 + matrix.m23) * num3; result.mY = 0.5f*sqrt;
result.mW = (matrix.m31 - matrix.m13) * num3; result.mZ = (matrix.m12 + matrix.m21)*half;
result.mW = (matrix.m02 - matrix.m20)*half;
} }
else else
{ {
float num5 = (float)Math.Sqrt((double)(((1f + matrix.m33) - matrix.m11) - matrix.m22)); sqrt = (float) Math.Sqrt(1.0f + matrix.m22 - matrix.m00 - matrix.m11);
float num2 = 0.5f / num5; half = 0.5f / sqrt;
result.mX = (matrix.m31 + matrix.m13) * num2;
result.mY = (matrix.m32 + matrix.m23) * num2; result.mX = (matrix.m02 + matrix.m20) * half;
result.mZ = 0.5f * num5; result.mY = (matrix.m12 + matrix.m21) * half;
result.mW = (matrix.m12 - matrix.m21) * num2; result.mZ = 0.5f * sqrt;
result.mW = (matrix.m10 - matrix.m01) * half;
} }
} }

View file

@ -1,3 +1,6 @@
// This file contains portions of code from the FNA project (github.com/FNA-XNA/FNA),
// released under the Microsoft Public License
using System; using System;
using System.Collections; using System.Collections;
using System.Text; using System.Text;
@ -131,7 +134,7 @@ namespace Beefy.geom
{ {
Vector3 newVec; Vector3 newVec;
Normalize(vector, out newVec); Normalize(vector, out newVec);
return vector; return newVec;
} }
public static void Normalize(Vector3 value, out Vector3 result) public static void Normalize(Vector3 value, out Vector3 result)
@ -173,7 +176,7 @@ namespace Beefy.geom
return new Vector2D((float)Math.Cos(angle) * length, (float)Math.Sin(angle) * length); return new Vector2D((float)Math.Cos(angle) * length, (float)Math.Sin(angle) * length);
}*/ }*/
public static Vector3 Transform(Vector3 vec, Matrix4 matrix) public static Vector3 TransformW(Vector3 vec, Matrix4 matrix)
{ {
Vector3 result; Vector3 result;
float fInvW = 1.0f / (matrix.m30 * vec.mX + matrix.m31 * vec.mY + matrix.m32 * vec.mZ + matrix.m33); float fInvW = 1.0f / (matrix.m30 * vec.mX + matrix.m31 * vec.mY + matrix.m32 * vec.mZ + matrix.m33);
@ -181,6 +184,16 @@ namespace Beefy.geom
result.mX = (matrix.m00 * vec.mX + matrix.m01 * vec.mY + matrix.m02 * vec.mZ + matrix.m03) * fInvW; result.mX = (matrix.m00 * vec.mX + matrix.m01 * vec.mY + matrix.m02 * vec.mZ + matrix.m03) * fInvW;
result.mY = (matrix.m10 * vec.mX + matrix.m11 * vec.mY + matrix.m12 * vec.mZ + matrix.m13) * fInvW; result.mY = (matrix.m10 * vec.mX + matrix.m11 * vec.mY + matrix.m12 * vec.mZ + matrix.m13) * fInvW;
result.mZ = (matrix.m20 * vec.mX + matrix.m21 * vec.mY + matrix.m22 * vec.mZ + matrix.m23) * fInvW; result.mZ = (matrix.m20 * vec.mX + matrix.m21 * vec.mY + matrix.m22 * vec.mZ + matrix.m23) * fInvW;
return result;
}
public static Vector3 Transform(Vector3 vec, Matrix4 matrix)
{
Vector3 result;
result.mX = (vec.mX * matrix.m00) + (vec.mY * matrix.m01) + (vec.mZ * matrix.m02) + matrix.m03;
result.mY = (vec.mX * matrix.m10) + (vec.mY * matrix.m11) + (vec.mZ * matrix.m12) + matrix.m13;
result.mZ = (vec.mX * matrix.m20) + (vec.mY * matrix.m21) + (vec.mZ * matrix.m22) + matrix.m23;
return result; return result;
} }
@ -199,6 +212,51 @@ namespace Beefy.geom
} }
}*/ }*/
/// <summary>
/// Returns a <see>Vector3</see> pointing in the opposite
/// direction of <paramref name="value"/>.
/// </summary>
/// <param name="value">The vector to negate.</param>
/// <returns>The vector negation of <paramref name="value"/>.</returns>
public static Vector3 Negate(Vector3 value)
{
return .(-value.mX, -value.mY, -value.mZ);
}
/// <summary>
/// Stores a <see>Vector3</see> pointing in the opposite
/// direction of <paramref name="value"/> in <paramref name="result"/>.
/// </summary>
/// <param name="value">The vector to negate.</param>
/// <param name="result">The vector that the negation of <paramref name="value"/> will be stored in.</param>
public static void Negate(Vector3 value, out Vector3 result)
{
result.mX = -value.mX;
result.mY = -value.mY;
result.mZ = -value.mZ;
}
/// <summary>
/// Creates a new <see cref="Vector3"/> that contains a multiplication of two vectors.
/// </summary>
/// <param name="value1">Source <see cref="Vector3"/>.</param>
/// <param name="value2">Source <see cref="Vector3"/>.</param>
/// <returns>The result of the vector multiplication.</returns>
public static Vector3 Multiply(Vector3 value1, Vector3 value2)
{
return .(value1.mX * value2.mX, value1.mY * value2.mY, value1.mZ * value2.mZ);
}
public static Vector3 Multiply(Vector3 value1, float value2)
{
return .(value1.mX * value2, value1.mY * value2, value1.mZ * value2);
}
public void Normalize() mut
{
Normalize(this, out this);
}
public static Vector3 Transform(Vector3 vec, Quaternion quat) public static Vector3 Transform(Vector3 vec, Quaternion quat)
{ {
Matrix4 matrix = quat.ToMatrix(); Matrix4 matrix = quat.ToMatrix();
@ -234,6 +292,11 @@ namespace Beefy.geom
return Vector3(vec1.mX - vec2.mX, vec1.mY - vec2.mY, vec1.mZ - vec2.mZ); return Vector3(vec1.mX - vec2.mX, vec1.mY - vec2.mY, vec1.mZ - vec2.mZ);
} }
public static Vector3 operator -(Vector3 vec1)
{
return Vector3(-vec1.mX, -vec1.mY, -vec1.mZ);
}
public static Vector3 operator *(Vector3 vec, float scale) public static Vector3 operator *(Vector3 vec, float scale)
{ {
return Vector3(vec.mX * scale, vec.mY * scale, vec.mZ * scale); return Vector3(vec.mX * scale, vec.mY * scale, vec.mZ * scale);

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,59 @@
// This file contains portions of code from the FNA project (github.com/FNA-XNA/FNA),
// released under the Microsoft Public License
using Beefy.geom;
using System.Diagnostics;
namespace Beefy.geom
{
struct Viewport
{
private int mX;
private int mY;
private int mWidth;
private int mHeight;
private float mMinDepth;
private float mMaxDepth;
public this(int x, int y, int width, int height,float minDepth,float maxDepth)
{
this.mX = x;
this.mY = y;
this.mWidth = width;
this.mHeight = height;
this.mMinDepth = minDepth;
this.mMaxDepth = maxDepth;
}
/// Unprojects a Vector3 from screen space into world space.
/// @param source The Vector3 to unproject.
/// @param projection The projection
/// @param view The view
/// @param world The world
public Vector3 Unproject(Vector3 source, Matrix4 projection, Matrix4 view, Matrix4 world)
{
var source;
Matrix4 matrix = Matrix4.Invert(Matrix4.Multiply(Matrix4.Multiply(world, view), projection));
source.mX = (((source.mX - this.mX) / ((float) this.mWidth)) * 2f) - 1f;
source.mY = -((((source.mY - this.mY) / ((float) this.mHeight)) * 2f) - 1f);
source.mZ = (source.mZ - this.mMinDepth) / (this.mMaxDepth - this.mMinDepth);
Vector3 vector = Vector3.Transform(source, matrix);
float a = (((source.mX * matrix.m30) + (source.mY * matrix.m31)) + (source.mZ * matrix.m32)) + matrix.m33;
if (!WithinEpsilon(a, 1f))
{
vector.mX = vector.mX / a;
vector.mY = vector.mY / a;
vector.mZ = vector.mZ / a;
}
return vector;
}
private static bool WithinEpsilon(float a, float b)
{
float num = a - b;
return ((-1.401298E-45f <= num) && (num <= float.Epsilon));
}
}
}

View file

@ -112,13 +112,13 @@ namespace Beefy.gfx
enum MarkPosition enum MarkPosition
{ {
AboveC, // Center AboveC, // Center
AboveR, // Left edge of mark aligned on center of char8 AboveR, // Left edge of mark aligned on center of char
AboveE, // Center of mark aligned on right edge of char8 AboveE, // Center of mark aligned on right edge of char
BelowC, BelowC,
BelowR, BelowR,
OverC, OverC,
OverE, OverE,
TopR, // Center of edge aligned to top of char8 TopR, // Center of edge aligned to top of char
} }
const int32 LOW_CHAR_COUNT = 128; const int32 LOW_CHAR_COUNT = 128;
@ -171,16 +171,33 @@ namespace Beefy.gfx
{ {
if (valType == 1) if (valType == 1)
{ {
String fontName = new String(&fontNameArr); String fontName = scope String(&fontNameArr);
int parenPos = fontName.IndexOf(" ("); int parenPos = fontName.IndexOf(" (");
if (parenPos != -1) if (parenPos != -1)
fontName.RemoveToEnd(parenPos); fontName.RemoveToEnd(parenPos);
fontName.ToUpper(); fontName.ToUpper();
String fontPath = new String(&data); String fontPath = scope String(&data);
if ((!fontPath.EndsWith(".TTF", .OrdinalIgnoreCase)) || (!sFontNameMap.TryAdd(fontName, fontPath))) if ((!fontPath.EndsWith(".TTF", .OrdinalIgnoreCase)) && (!fontPath.EndsWith(".TTC", .OrdinalIgnoreCase)))
continue;
if (fontName.Contains('&'))
{ {
delete fontName; int collectionIdx = 0;
delete fontPath; for (var namePart in fontName.Split('&', .RemoveEmptyEntries))
{
namePart.Trim();
if (sFontNameMap.TryAddAlt(namePart, var keyPtr, var valuePtr))
{
*keyPtr = new String(namePart);
*valuePtr = new $"{fontPath}@{collectionIdx}";
collectionIdx++;
}
}
}
else if (sFontNameMap.TryAdd(fontName, var keyPtr, var valuePtr))
{
*keyPtr = new String(fontName);
*valuePtr = new String(fontPath);
} }
} }
} }
@ -781,7 +798,7 @@ namespace Beefy.gfx
else if (newMatrix.tx > clipRect.mX + clipRect.mWidth) else if (newMatrix.tx > clipRect.mX + clipRect.mWidth)
{ {
isFullyClipped = true; isFullyClipped = true;
if ((newMatrix.a > 0) && (fontMetrics == null)) // Forward? If so, all future char8s will clip if ((newMatrix.a > 0) && (fontMetrics == null)) // Forward? If so, all future chars will clip
break; break;
} }
} }

View file

@ -79,6 +79,10 @@ namespace Beefy.gfx
const int32 CLIP_STACK_SIZE = 256; const int32 CLIP_STACK_SIZE = 256;
public Rect?[] mClipStack = new Rect?[CLIP_STACK_SIZE] ~ delete _; public Rect?[] mClipStack = new Rect?[CLIP_STACK_SIZE] ~ delete _;
public bool mTexWrap;
protected DisposeProxy mTexWrapDisableProxy ~ delete _;
protected DisposeProxy mTexWrapEnableProxy ~ delete _;
public int32 mClipStackIdx = 0; public int32 mClipStackIdx = 0;
public Rect? mClipRect = null; public Rect? mClipRect = null;
@ -106,6 +110,10 @@ namespace Beefy.gfx
mClipDisposeProxy = new DisposeProxy(); mClipDisposeProxy = new DisposeProxy();
mClipDisposeProxy.mDisposeProxyDelegate = new => PopClip; mClipDisposeProxy.mDisposeProxyDelegate = new => PopClip;
mRenderStateDisposeProxy = new DisposeProxy(); mRenderStateDisposeProxy = new DisposeProxy();
mTexWrapDisableProxy = new DisposeProxy();
mTexWrapDisableProxy.mDisposeProxyDelegate = new () => { PopTexWrap(false); };
mTexWrapEnableProxy = new DisposeProxy();
mTexWrapEnableProxy.mDisposeProxyDelegate = new () => { PopTexWrap(true); };
mWhiteDot = Image.LoadFromFile("!white"); mWhiteDot = Image.LoadFromFile("!white");
@ -341,7 +349,7 @@ namespace Beefy.gfx
Rect rectThing = mClipRect.Value; Rect rectThing = mClipRect.Value;
mClipRect = rectThing; mClipRect = rectThing;
var clipRenderState = AllocRenderState(mDefaultShader, mClipRect); var clipRenderState = AllocRenderState(mDefaultShader, mClipRect, mTexWrap);
//clipRenderState.ClipRect = mClipRect; //clipRenderState.ClipRect = mClipRect;
PushRenderState(clipRenderState); PushRenderState(clipRenderState);
@ -349,7 +357,7 @@ namespace Beefy.gfx
return mClipDisposeProxy; return mClipDisposeProxy;
} }
RenderState AllocRenderState(Shader shader, Rect? clipRect) RenderState AllocRenderState(Shader shader, Rect? clipRect, bool texWrap)
{ {
RenderState renderState = null; RenderState renderState = null;
var curRenderState = mRenderStateStack[mRenderStateStackIdx]; var curRenderState = mRenderStateStack[mRenderStateStackIdx];
@ -365,6 +373,7 @@ namespace Beefy.gfx
} }
else else
renderState = RenderState.Create(curRenderState); renderState = RenderState.Create(curRenderState);
renderState.TexWrap = texWrap;
renderState.Shader = shader; renderState.Shader = shader;
renderState.ClipRect = clipRect; renderState.ClipRect = clipRect;
return renderState; return renderState;
@ -375,16 +384,33 @@ namespace Beefy.gfx
mClipStackIdx++; mClipStackIdx++;
mClipStack[mClipStackIdx] = null; mClipStack[mClipStackIdx] = null;
mClipRect = null; mClipRect = null;
var clipRenderState = AllocRenderState(mDefaultShader, null); var clipRenderState = AllocRenderState(mDefaultShader, mClipRect, mTexWrap);
//clipRenderState.ClipRect = null; //clipRenderState.ClipRect = null;
PushRenderState(clipRenderState); PushRenderState(clipRenderState);
return mClipDisposeProxy; return mClipDisposeProxy;
} }
public DisposeProxy PushTexWrap(bool texWrap)
{
bool prevTexWrap = mTexWrap;
mTexWrap = texWrap;
var clipRenderState = AllocRenderState(mDefaultShader, mClipRect, mTexWrap);
PushRenderState(clipRenderState);
return prevTexWrap ? mTexWrapEnableProxy : mTexWrapDisableProxy;
}
protected void PopTexWrap(bool texWrap)
{
mTexWrap = texWrap;
PopRenderState();
}
public void PushTextRenderState() public void PushTextRenderState()
{ {
var textRenderState = AllocRenderState(mTextShader, mClipRect); var textRenderState = AllocRenderState(mTextShader, mClipRect, mTexWrap);
//textRenderState.ClipRect = mClipRect; //textRenderState.ClipRect = mClipRect;
//textRenderState.Shader = mTextShader; //textRenderState.Shader = mTextShader;
PushRenderState(textRenderState); PushRenderState(textRenderState);
@ -415,14 +441,17 @@ namespace Beefy.gfx
//[CallingConvention(.Stdcall), CLink] //[CallingConvention(.Stdcall), CLink]
//static unsafe extern void Gfx_DrawIndexedVertices2D(void* vtxData, int vtxCount, int* idxData, int idxCount, float a, float b, float c, float d, float tx, float ty, float z); //static unsafe extern void Gfx_DrawIndexedVertices2D(void* vtxData, int vtxCount, int* idxData, int idxCount, float a, float b, float c, float d, float tx, float ty, float z);
[CallingConvention(.Stdcall), CLink]
static extern void Gfx_DrawIndexedVertices(int32 vertexSize, void* vtxData, int32 vtxCount, uint16* idxData, int32 idxCount);
[CallingConvention(.Stdcall), CLink] [CallingConvention(.Stdcall), CLink]
static extern void Gfx_DrawIndexedVertices2D(int32 vertexSize, void* vtxData, int32 vtxCount, uint16* idxData, int32 idxCount, float a, float b, float c, float d, float tx, float ty, float z); static extern void Gfx_DrawIndexedVertices2D(int32 vertexSize, void* vtxData, int32 vtxCount, uint16* idxData, int32 idxCount, float a, float b, float c, float d, float tx, float ty, float z);
[CallingConvention(.Stdcall), CLink] [CallingConvention(.Stdcall), CLink]
static extern void Gfx_SetShaderConstantData(int32 slotIdx, void* data, int32 size); static extern void Gfx_SetShaderConstantData(int32 usageIdx, int32 slotIdx, void* data, int32 size);
[CallingConvention(.Stdcall), CLink] [CallingConvention(.Stdcall), CLink]
static extern void Gfx_SetShaderConstantDataTyped(int32 slotIdx, void* data, int32 size, int32* typeData, int32 typeCount); static extern void Gfx_SetShaderConstantDataTyped(int usageIdx, int32 slotIdx, void* data, int32 size, int32* typeData, int32 typeCount);
[CallingConvention(.Stdcall), CLink] [CallingConvention(.Stdcall), CLink]
static extern void Gfx_DrawQuads(void* textureSegment, Vertex3D* vertices, int32 vtxCount); static extern void Gfx_DrawQuads(void* textureSegment, Vertex3D* vertices, int32 vtxCount);
@ -767,32 +796,57 @@ namespace Beefy.gfx
} }
public void DrawIndexedVertices(VertexDefinition vertexDef, void* vertices, int vtxCount, uint16[] indices) public void DrawIndexedVertices(VertexDefinition vertexDef, void* vertices, int vtxCount, uint16[] indices)
{
if (vertexDef.mPosition2DOffset != -1)
{ {
Gfx_DrawIndexedVertices2D(vertexDef.mVertexSize, vertices, (int32)vtxCount, indices.CArray(), (int32)indices.Count, Gfx_DrawIndexedVertices2D(vertexDef.mVertexSize, vertices, (int32)vtxCount, indices.CArray(), (int32)indices.Count,
mMatrix.a, mMatrix.b, mMatrix.c, mMatrix.d, mMatrix.tx, mMatrix.ty, ZDepth); mMatrix.a, mMatrix.b, mMatrix.c, mMatrix.d, mMatrix.tx, mMatrix.ty, ZDepth);
} }
else
{
Gfx_DrawIndexedVertices(vertexDef.mVertexSize, vertices, (int32)vtxCount, indices.CArray(), (int32)indices.Count);
}
}
public void DrawIndexedVertices(VertexDefinition vertexDef, void* vertices, int vtxCount, uint16* indices, int idxCount) public void DrawIndexedVertices(VertexDefinition vertexDef, void* vertices, int vtxCount, uint16* indices, int idxCount)
{
if (vertexDef.mPosition2DOffset != -1)
{ {
Gfx_DrawIndexedVertices2D(vertexDef.mVertexSize, vertices, (int32)vtxCount, indices, (int32)idxCount, Gfx_DrawIndexedVertices2D(vertexDef.mVertexSize, vertices, (int32)vtxCount, indices, (int32)idxCount,
mMatrix.a, mMatrix.b, mMatrix.c, mMatrix.d, mMatrix.tx, mMatrix.ty, ZDepth); mMatrix.a, mMatrix.b, mMatrix.c, mMatrix.d, mMatrix.tx, mMatrix.ty, ZDepth);
} }
else
public void SetShaderConstantData(int slotIdx, void* data, int size)
{ {
Gfx_SetShaderConstantData((int32)slotIdx, data, (int32)size); Gfx_DrawIndexedVertices(vertexDef.mVertexSize, vertices, (int32)vtxCount, indices, (int32)idxCount);
}
} }
public void SetShaderConstantData(int32 slotIdx, void* data, ConstantDataDefinition constantDataDefinition) public void SetVertexShaderConstantData(int slotIdx, void* data, int size)
{
Gfx_SetShaderConstantData(0, (int32)slotIdx, data, (int32)size);
}
public void SetPixelShaderConstantData(int slotIdx, void* data, int size)
{
Gfx_SetShaderConstantData(1, (int32)slotIdx, data, (int32)size);
}
public void SetVertexShaderConstantData(int32 slotIdx, void* data, ConstantDataDefinition constantDataDefinition)
{ {
int32* dataTypesPtr = (int32*)constantDataDefinition.mDataTypes.CArray(); int32* dataTypesPtr = (int32*)constantDataDefinition.mDataTypes.CArray();
Gfx_SetShaderConstantDataTyped(slotIdx, data, constantDataDefinition.mDataSize, dataTypesPtr, (int32)constantDataDefinition.mDataTypes.Count); Gfx_SetShaderConstantDataTyped(0, slotIdx, data, constantDataDefinition.mDataSize, dataTypesPtr, (int32)constantDataDefinition.mDataTypes.Count);
} }
public void SetShaderConstantData(int32 slotIdx, Matrix4 matrix) public void SetVertexShaderConstantData(int32 slotIdx, Matrix4 matrix)
{ {
var mtx = matrix; var mtx = matrix;
Gfx_SetShaderConstantData(slotIdx, &mtx, (int32)sizeof(Matrix4)); Gfx_SetShaderConstantData(0, slotIdx, &mtx, (int32)sizeof(Matrix4));
}
public void SetPixelShaderConstantData(int32 slotIdx, Matrix4 matrix)
{
var mtx = matrix;
Gfx_SetShaderConstantData(1, slotIdx, &mtx, (int32)sizeof(Matrix4));
} }
public float DrawString(StringView theString, float x, float y, FontAlign alignment = FontAlign.Left, float width = 0, FontOverflowMode overflowMode = FontOverflowMode.Overflow, FontMetrics* fontMetrics = null) public float DrawString(StringView theString, float x, float y, FontAlign alignment = FontAlign.Left, float width = 0, FontOverflowMode overflowMode = FontOverflowMode.Overflow, FontMetrics* fontMetrics = null)
@ -811,12 +865,12 @@ namespace Beefy.gfx
float d = m.d * height; float d = m.d * height;
Gfx_AllocTris(image.mNativeTextureSegment, 6); Gfx_AllocTris(image.mNativeTextureSegment, 6);
Gfx_SetDrawVertex(0, m.tx, m.ty, 0, u1, 0, mColor); Gfx_SetDrawVertex(0, m.tx, m.ty, 0, u1, v1, mColor);
Gfx_SetDrawVertex(1, m.tx + a, m.ty + b, 0, u2, 0, mColor); Gfx_SetDrawVertex(1, m.tx + a, m.ty + b, 0, u2, v1, mColor);
Gfx_SetDrawVertex(2, m.tx + c, m.ty + d, 0, u1, 1, mColor); Gfx_SetDrawVertex(2, m.tx + c, m.ty + d, 0, u1, v2, mColor);
Gfx_CopyDrawVertex(3, 2); Gfx_CopyDrawVertex(3, 2);
Gfx_CopyDrawVertex(4, 1); Gfx_CopyDrawVertex(4, 1);
Gfx_SetDrawVertex(5, m.tx + (a + c), m.ty + (b + d), 0, u2, 1, mColor); Gfx_SetDrawVertex(5, m.tx + (a + c), m.ty + (b + d), 0, u2, v2, mColor);
} }
// Untranslated // Untranslated

View file

@ -210,6 +210,25 @@ namespace Beefy.gfx
} }
} }
} }
public Image[] CreateImageCels(int32 cols, int32 rows)
{
int32 celW = mSrcWidth / cols;
int32 celH = mSrcHeight / rows;
Debug.Assert(celW * cols == mSrcWidth);
Debug.Assert(celH * rows == mSrcHeight);
Image[] celImages = new .[cols * rows];
for (int32 row = 0; row < rows; row++)
{
for (int32 col = 0; col < cols; col++)
{
celImages[row * cols + col] = CreateImageSegment(col * celW, row * celH, celW, celH);
}
}
return celImages;
}
} }
#else #else
public class Image : IDrawable public class Image : IDrawable

View file

@ -49,6 +49,12 @@ namespace Beefy.gfx
#if !STUDIO_CLIENT #if !STUDIO_CLIENT
extension ModelDef extension ModelDef
{ {
public enum ModelCreateFlags
{
None = 0,
NoSetRenderState = 1
}
public class Animation public class Animation
{ {
public void* mNativeModelDefAnimation; public void* mNativeModelDefAnimation;
@ -90,14 +96,32 @@ namespace Beefy.gfx
public void* mNativeModelDef; public void* mNativeModelDef;
public float mFrameRate; public float mFrameRate;
public int32 mJointCount; public int32 mJointCount;
public Animation[] mAnims; public Animation[] mAnims ~ DeleteContainerAndItems!(_);
public Dictionary<String, Animation> mAnimMap = new Dictionary<String, Animation>(); public Dictionary<String, Animation> mAnimMap = new Dictionary<String, Animation>() ~ DeleteDictionaryAndKeys!(_);
[CallingConvention(.Stdcall), CLink] [CallingConvention(.Stdcall), CLink]
extern static void* Res_OpenFBX(String fileName, void* nativeVertexDef); extern static void* Res_OpenFBX(char8* fileName, void* nativeVertexDef);
[CallingConvention(.Stdcall), CLink] [CallingConvention(.Stdcall), CLink]
extern static void* ModelDef_CreateModelInstance(void* nativeModel); extern static void* Res_OpenGLTF(char8* fileName, char8* baseDir, void* nativeVertexDef);
[CallingConvention(.Stdcall), CLink]
extern static void* Res_OpenModel(char8* fileName, char8* baseDir, void* nativeVertexDef);
[CallingConvention(.Stdcall), CLink]
extern static void* ModelDef_CreateModelInstance(void* nativeModel, ModelCreateFlags flags);
[CallingConvention(.Stdcall), CLink]
extern static void ModelDef_Compact(void* nativeModel);
[CallingConvention(.Stdcall), CLink]
extern static void ModelDef_SetBaseDir(void* nativeModel, char8* baseDir);
[CallingConvention(.Stdcall), CLink]
extern static char8* ModelDef_GetInfo(void* nativeModel);
[CallingConvention(.Stdcall), CLink]
extern static void ModelDef_GetBounds(void* nativeModel, out Vector3 min, out Vector3 max);
[CallingConvention(.Stdcall), CLink] [CallingConvention(.Stdcall), CLink]
extern static float ModelDef_GetFrameRate(void* nativeModel); extern static float ModelDef_GetFrameRate(void* nativeModel);
@ -111,6 +135,15 @@ namespace Beefy.gfx
[CallingConvention(.Stdcall), CLink] [CallingConvention(.Stdcall), CLink]
extern static void* ModelDef_GetAnimation(void* nativeModel, int32 animIdx); extern static void* ModelDef_GetAnimation(void* nativeModel, int32 animIdx);
[CallingConvention(.Stdcall), CLink]
extern static void ModelDef_SetTextures(void* nativeModel, int32 meshIdx, int32 primitivesIdx, char8** paths, int32 pathCount);
[CallingConvention(.Stdcall), CLink]
extern static bool ModelDef_RayIntersect(void* nativeModel, Matrix4 worldMtx, Vector3 origin, Vector3 vec, out Vector3 outIntersect, out float outDistance);
[CallingConvention(.Stdcall), CLink]
extern static Span<uint8> Res_SerializeModel(void* nativeModel);
this(void* nativeModelDef) this(void* nativeModelDef)
{ {
mNativeModelDef = nativeModelDef; mNativeModelDef = nativeModelDef;
@ -129,17 +162,23 @@ namespace Beefy.gfx
} }
} }
public static ModelDef LoadModel(String fileName) public static ModelDef LoadModel(String fileName, String baseDir)
{ {
void* nativeModelDef = Res_OpenFBX(fileName, VertexDef.sVertexDefinition.mNativeVertexDefinition); void* nativeModelDef = null;
if (fileName.EndsWith(".gltf", .OrdinalIgnoreCase))
nativeModelDef = Res_OpenGLTF(fileName, baseDir, VertexDef.sVertexDefinition.mNativeVertexDefinition);
else if (fileName.EndsWith(".fbx", .OrdinalIgnoreCase))
nativeModelDef = Res_OpenFBX(fileName, VertexDef.sVertexDefinition.mNativeVertexDefinition);
else
nativeModelDef = Res_OpenModel(fileName, baseDir, VertexDef.sVertexDefinition.mNativeVertexDefinition);
if (nativeModelDef == null) if (nativeModelDef == null)
return null; return null;
return new ModelDef(nativeModelDef); return new ModelDef(nativeModelDef);
} }
public ModelInstance CreateInstance() public ModelInstance CreateInstance(ModelCreateFlags flags = .None)
{ {
void* nativeModelInstance = ModelDef_CreateModelInstance(mNativeModelDef); void* nativeModelInstance = ModelDef_CreateModelInstance(mNativeModelDef, flags);
if (nativeModelInstance == null) if (nativeModelInstance == null)
return null; return null;
var modelInstance = new ModelInstance(nativeModelInstance, this); var modelInstance = new ModelInstance(nativeModelInstance, this);
@ -150,6 +189,42 @@ namespace Beefy.gfx
{ {
return mAnimMap[name]; return mAnimMap[name];
} }
public void GetInfo(String str)
{
str.Append(ModelDef_GetInfo(mNativeModelDef));
}
public void GetBounds(out Vector3 min, out Vector3 max)
{
ModelDef_GetBounds(mNativeModelDef, out min, out max);
}
public void Compact()
{
ModelDef_Compact(mNativeModelDef);
}
public void SetBaseDir(StringView baseDir)
{
ModelDef_SetBaseDir(mNativeModelDef, baseDir.ToScopeCStr!());
}
public void SetTextures(int meshIdx, int primitivesIdx, Span<char8*> paths)
{
ModelDef_SetTextures(mNativeModelDef, (.)meshIdx, (.)primitivesIdx, paths.Ptr, (.)paths.Length);
}
public void Serialize(List<uint8> data)
{
var span = Res_SerializeModel(mNativeModelDef);
data.AddRange(span);
}
public bool RayIntersect(Matrix4 worldMtx, Vector3 origin, Vector3 vec, out Vector3 outIntersect, out float outDistance)
{
return ModelDef_RayIntersect(mNativeModelDef, worldMtx, origin, vec, out outIntersect, out outDistance);
}
} }
public class ModelInstance : RenderCmd public class ModelInstance : RenderCmd

View file

@ -19,6 +19,12 @@ namespace Beefy.gfx
Always Always
} }
public enum Topology
{
TriangleList,
LineList
}
#if !STUDIO_CLIENT #if !STUDIO_CLIENT
public class RenderState public class RenderState
{ {
@ -31,6 +37,12 @@ namespace Beefy.gfx
[CallingConvention(.Stdcall), CLink] [CallingConvention(.Stdcall), CLink]
static extern void RenderState_SetClip(void* renderState, float x, float y, float width, float height); static extern void RenderState_SetClip(void* renderState, float x, float y, float width, float height);
[CallingConvention(.Stdcall), CLink]
static extern void RenderState_SetTexWrap(void* renderState, bool texWrap);
[CallingConvention(.Stdcall), CLink]
static extern void RenderState_SetWireframe(void* renderState, bool wireframe);
[CallingConvention(.Stdcall), CLink] [CallingConvention(.Stdcall), CLink]
static extern void RenderState_DisableClip(void* renderState); static extern void RenderState_DisableClip(void* renderState);
@ -43,6 +55,9 @@ namespace Beefy.gfx
[CallingConvention(.Stdcall), CLink] [CallingConvention(.Stdcall), CLink]
static extern void RenderState_SetDepthWrite(void* nativeRenderState, int32 depthWrite); static extern void RenderState_SetDepthWrite(void* nativeRenderState, int32 depthWrite);
[CallingConvention(.Stdcall), CLink]
static extern void RenderState_SetTopology(void* nativeRenderState, int32 topology);
public void* mNativeRenderState; public void* mNativeRenderState;
public bool mIsFromDefaultRenderState; public bool mIsFromDefaultRenderState;
@ -104,6 +119,30 @@ namespace Beefy.gfx
RenderState_DisableClip(mNativeRenderState); RenderState_DisableClip(mNativeRenderState);
} }
} }
public bool TexWrap
{
set
{
RenderState_SetTexWrap(mNativeRenderState, value);
}
}
public bool Wireframe
{
set
{
RenderState_SetWireframe(mNativeRenderState, value);
}
}
public Topology Topology
{
set
{
RenderState_SetTopology(mNativeRenderState, (.)value);
}
}
} }
#else #else
public class RenderState public class RenderState

View file

@ -424,9 +424,9 @@ namespace Beefy.theme.dark
if (selEnd > selStart) if (selEnd > selStart)
{ {
String selPrevString = scope String(selStart); String selPrevString = new:ScopedAlloc! String(selStart);
selPrevString.Append(sectionText, 0, selStart); selPrevString.Append(sectionText, 0, selStart);
String selIncludeString = scope String(selEnd); String selIncludeString = new:ScopedAlloc! String(selEnd);
selIncludeString.Append(sectionText, 0, selEnd); selIncludeString.Append(sectionText, 0, selEnd);
float selStartX = GetTabbedWidth(selPrevString, curX); float selStartX = GetTabbedWidth(selPrevString, curX);
@ -473,7 +473,7 @@ namespace Beefy.theme.dark
if (isInside) if (isInside)
{ {
String subText = scope String(mCursorTextPos - lineDrawStart); String subText = new:ScopedAlloc! String(mCursorTextPos - lineDrawStart);
subText.Append(sectionText, 0, mCursorTextPos - lineDrawStart); subText.Append(sectionText, 0, mCursorTextPos - lineDrawStart);
aX = GetTabbedWidth(subText, curX); aX = GetTabbedWidth(subText, curX);
} }
@ -587,7 +587,7 @@ namespace Beefy.theme.dark
if (char8Count < lineText.Length) if (char8Count < lineText.Length)
{ {
String subString = scope String(char8Count); String subString = new:ScopedAlloc! String(char8Count);
subString.Append(lineText, 0, char8Count); subString.Append(lineText, 0, char8Count);
float subWidth = GetTabbedWidth(subString, 0); float subWidth = GetTabbedWidth(subString, 0);

View file

@ -398,12 +398,12 @@ namespace Beefy.theme.dark
func(mRightTab); func(mRightTab);
} }
public override TabButton AddTab(String label, float width, Widget content, bool ownsContent) public override TabButton AddTab(String label, float width, Widget content, bool ownsContent, int insertIdx)
{ {
float useWidth = width; float useWidth = width;
if (useWidth == 0) if (useWidth == 0)
useWidth = DarkTheme.sDarkTheme.mSmallFont.GetWidth(label) + GS!(30); useWidth = DarkTheme.sDarkTheme.mSmallFont.GetWidth(label) + GS!(30);
return base.AddTab(label, useWidth, content, ownsContent); return base.AddTab(label, useWidth, content, ownsContent, insertIdx);
} }
public override void RemoveTab(TabButton tabButton, bool deleteTab = true) public override void RemoveTab(TabButton tabButton, bool deleteTab = true)

View file

@ -0,0 +1,54 @@
using System;
using System.Collections;
namespace utils
{
class Compression
{
[CallingConvention(.Stdcall), CLink]
extern static bool Compression_Compress(void* ptr, int size, void** outPtr, int* outSize);
[CallingConvention(.Stdcall), CLink]
extern static bool Compression_Decompress(void* ptr, int size, void** outPtr, int* outSize);
public static Result<void> Compress(Span<uint8> inData, List<uint8> outData)
{
void* outPtr = null;
int outSize = 0;
if (!Compression_Compress(inData.Ptr, inData.Length, &outPtr, &outSize))
return .Err;
outData.AddRange(.((.)outPtr, outSize));
return .Ok;
}
public static Result<void> Compress(Span<uint8> inData, String outData)
{
void* outPtr = null;
int outSize = 0;
if (!Compression_Compress(inData.Ptr, inData.Length, &outPtr, &outSize))
return .Err;
outData.Insert(outData.Length, StringView((.)outPtr, outSize));
return .Ok;
}
public static Result<void> Decompress(Span<uint8> inData, List<uint8> outData)
{
void* outPtr = null;
int outSize = 0;
if (!Compression_Decompress(inData.Ptr, inData.Length, &outPtr, &outSize))
return .Err;
outData.AddRange(.((.)outPtr, outSize));
return .Ok;
}
public static Result<void> Decompress(Span<uint8> inData, String outData)
{
void* outPtr = null;
int outSize = 0;
if (!Compression_Decompress(inData.Ptr, inData.Length, &outPtr, &outSize))
return .Err;
outData.Insert(outData.Length, StringView((.)outPtr, outSize));
return .Ok;
}
}
}

View file

@ -405,7 +405,7 @@ namespace Beefy.utils
return; return;
switch (obj.GetType()) switch (obj.GetType())
{ {
case typeof(Int32): val = (int32)obj; case typeof(Int64): val = (.)(int64)obj;
default: default:
} }
} }
@ -417,7 +417,7 @@ namespace Beefy.utils
return; return;
switch (obj.GetType()) switch (obj.GetType())
{ {
case typeof(Int32): val = (int32)obj; case typeof(Int64): val = (int64)obj;
case typeof(Float): val = (float)obj; case typeof(Float): val = (float)obj;
default: default:
} }
@ -470,6 +470,7 @@ namespace Beefy.utils
Object val = Get(name); Object val = Get(name);
outString.Clear(); outString.Clear();
if (val is uint64) if (val is uint64)
val.ToString(outString); val.ToString(outString);
@ -493,58 +494,112 @@ namespace Beefy.utils
return; return;
} }
public int32 GetInt(String name, int32 theDefault = 0) public int32 GetInt(String name, int32 defaultVal = 0)
{
Object aVal = Get(name);
if ((aVal == null) || (!(aVal is int32)))
return theDefault;
return (int32)aVal;
}
public int64 GetLong(String name, int64 theDefault = 0)
{
Object aVal = Get(name);
if (aVal is int32)
return (int64)(int32)aVal;
if ((aVal == null) || (!(aVal is int64)))
return theDefault;
return (int64)aVal;
}
public uint64 GetULong(String name, uint64 theDefault = 0)
{
Object aVal = Get(name);
if (aVal is int32)
return (uint64)(int32)aVal;
if ((aVal == null) || (!(aVal is uint64)))
return theDefault;
return (uint64)aVal;
}
public float GetFloat(String name, float theDefault = 0)
{ {
Object val = Get(name); Object val = Get(name);
if (val == null) if (val == null)
return theDefault; return defaultVal;
switch (val.GetType()) switch (val.GetType())
{ {
case typeof(Float): return (float)val; case typeof(Float): return (.)(float)val;
case typeof(Int32): return (int32)val; case typeof(Int32): return (.)(int32)val;
case typeof(Int): return (int)val; case typeof(Int64): return (.)(int64)val;
default: return theDefault; case typeof(Int): return (.)(int)val;
case typeof(String):
if (int32.Parse((String)val) case .Ok(var fVal))
return (.)fVal;
return defaultVal;
case typeof(StringView):
if (int32.Parse((StringView)val) case .Ok(var fVal))
return (.)fVal;
return defaultVal;
default: return defaultVal;
} }
} }
public bool GetBool(String name, bool theDefault = false) public int64 GetLong(String name, int64 defaultVal = 0)
{ {
Object aVal = Get(name); Object val = Get(name);
if ((aVal == null) || (!(aVal is bool))) if (val == null)
return theDefault; return defaultVal;
return (bool)aVal; switch (val.GetType())
{
case typeof(Float): return (.)(float)val;
case typeof(Int32): return (.)(int32)val;
case typeof(Int64): return (.)(int64)val;
case typeof(Int): return (.)(int)val;
case typeof(String):
if (int64.Parse((String)val) case .Ok(var parsedVal))
return (.)parsedVal;
return defaultVal;
case typeof(StringView):
if (int64.Parse((StringView)val) case .Ok(var parsedVal))
return (.)parsedVal;
return defaultVal;
default: return defaultVal;
}
}
public uint64 GetULong(String name, uint64 defaultVal = 0)
{
Object val = Get(name);
if (val == null)
return defaultVal;
switch (val.GetType())
{
case typeof(Float): return (.)(float)val;
case typeof(Int32): return (.)(int32)val;
case typeof(Int64): return (.)(int64)val;
case typeof(Int): return (.)(int)val;
case typeof(String):
if (int64.Parse((String)val) case .Ok(var parsedVal))
return (.)parsedVal;
return defaultVal;
case typeof(StringView):
if (int64.Parse((StringView)val) case .Ok(var parsedVal))
return (.)parsedVal;
return defaultVal;
default: return defaultVal;
}
}
public float GetFloat(String name, float defaultVal = 0)
{
Object val = Get(name);
if (val == null)
return defaultVal;
switch (val.GetType())
{
case typeof(Float): return (.)(float)val;
case typeof(Int32): return (.)(int32)val;
case typeof(Int64): return (.)(int64)val;
case typeof(Int): return (.)(int)val;
case typeof(String):
if (float.Parse((String)val) case .Ok(var parsedVal))
return parsedVal;
return defaultVal;
case typeof(StringView):
if (float.Parse((StringView)val) case .Ok(var parsedVal))
return parsedVal;
return defaultVal;
default: return defaultVal;
}
}
public bool GetBool(String name, bool defaultVal = false)
{
Object val = Get(name);
if (val == null)
return defaultVal;
switch (val.GetType())
{
case typeof(Boolean): return (bool)val;
case typeof(String):
if (bool.Parse((String)val) case .Ok(var parsedVal))
return (.)parsedVal;
return defaultVal;
default: return defaultVal;
}
} }
public T GetEnum<T>(String name, T defaultVal = default(T)) where T : enum public T GetEnum<T>(String name, T defaultVal = default(T)) where T : enum
@ -634,9 +689,9 @@ namespace Beefy.utils
public int32 GetCurInt(int32 theDefault = 0) public int32 GetCurInt(int32 theDefault = 0)
{ {
Object aVal = GetCurrent(); Object aVal = GetCurrent();
if ((aVal == null) || (!(aVal is int32))) if ((aVal == null) || (!(aVal is int64)))
return theDefault; return theDefault;
return (int32)aVal; return (.)(int64)aVal;
} }
public uint32 GetCurUInt(uint32 theDefault = 0) public uint32 GetCurUInt(uint32 theDefault = 0)
@ -1786,7 +1841,7 @@ namespace Beefy.utils
} }
else else
{ {
var parseVal = int32.Parse(strView); var parseVal = int64.Parse(strView);
if (parseVal case .Ok(var intVal)) if (parseVal case .Ok(var intVal))
aValue = new:mBumpAllocator box intVal; aValue = new:mBumpAllocator box intVal;
else else
@ -2187,7 +2242,7 @@ namespace Beefy.utils
} }
} }
switch (Int32.Parse(value)) switch (Int64.Parse(value))
{ {
case .Err: return null; case .Err: return null;
case .Ok(let num): return new:mBumpAllocator box num; case .Ok(let num): return new:mBumpAllocator box num;
@ -2344,6 +2399,223 @@ namespace Beefy.utils
} }
} }
Result<void, Error> LoadXMLHelper(String contentStr, Values values, ref int32 idx, ref int32 lineNum)
{
LoadSection loadRoot = scope LoadSection();
loadRoot.mSectionDict = new Dictionary<String, LoadSection>();
loadRoot.mCurrentEntry = CurrentEntry(values);
//LoadSection loadSection = loadRoot;
//CurrentEntry currentEntry = default;
char8* cPtr = contentStr.CStr();
char8 NextChar()
{
char8 c = cPtr[idx];
if (c != 0)
idx++;
return c;
}
char8* GetCharPtr()
{
return &cPtr[idx];
}
char8 PeekNextChar()
{
return cPtr[idx];
}
void EatWhiteSpace()
{
while (true)
{
char8 nextC = PeekNextChar();
if ((nextC != ' ') && (nextC != '\t'))
return;
idx++;
}
}
void ReadSection(ref CurrentEntry arrayEntry)
{
char8* dataStart = null;
void FlushData()
{
if (dataStart != null)
{
StringView valueSV = StringView(dataStart, GetCharPtr() - dataStart - 1);
valueSV.Trim();
String value = new:mBumpAllocator String(valueSV);
DoAdd(ref arrayEntry, value);
}
dataStart = null;
}
MainLoop: while (true)
{
char8 c = NextChar();
if (c == 0)
{
break;
}
if (c == '<')
{
FlushData();
EatWhiteSpace();
c = PeekNextChar();
if (c == '/')
{
// Is closing
while (true)
{
c = NextChar();
if ((c == 0) || (c == '>'))
return;
}
}
NamedValues childNamedValues = null;
CurrentEntry childTableEntry = default;
void EnsureChildEntry()
{
if (childNamedValues != null)
return;
childNamedValues = new:mBumpAllocator NamedValues();
childTableEntry = CurrentEntry(childNamedValues);
DoAdd(ref arrayEntry, childNamedValues);
}
char8* namePtr = null;
char8* nameEndPtr = null;
char8* equalPtr = null;
char8* valuePtr = null;
while (true)
{
c = NextChar();
if (c.IsWhiteSpace)
{
if ((namePtr != null) && (nameEndPtr == null))
nameEndPtr = GetCharPtr() - 1;
continue;
}
if (valuePtr != null)
{
if (c == '"')
{
EnsureChildEntry();
StringView name = StringView(namePtr, nameEndPtr - namePtr + 1);
name.Trim();
StringView valueSV = StringView(valuePtr, GetCharPtr() - valuePtr - 1);
String value = new:mBumpAllocator String(valueSV);
DoAdd(ref childTableEntry, name, value);
namePtr = null;
nameEndPtr = null;
equalPtr = null;
valuePtr = null;
continue;
}
continue;
}
if ((c == '?') || (c == '/'))
{
// Wait for close. Not nested.
while (true)
{
c = NextChar();
if ((c == 0) || (c == '>'))
continue MainLoop;
}
}
if (c == '>')
{
// Closing, but we're nested
EnsureChildEntry();
Values childArrayValues = new:mBumpAllocator Values();
CurrentEntry childArrayEntry = CurrentEntry(childArrayValues);
DoAdd(ref childTableEntry, ".", childArrayValues);
ReadSection(ref childArrayEntry);
continue MainLoop;
}
if (namePtr == null)
{
namePtr = GetCharPtr() - 1;
continue;
}
if (equalPtr == null)
{
if (c == '=')
{
equalPtr = GetCharPtr() - 1;
if (nameEndPtr == null)
nameEndPtr = equalPtr - 1;
continue;
}
}
else
{
if (c == '"')
{
valuePtr = GetCharPtr();
continue;
}
}
if (nameEndPtr == null)
continue;
// Flush
StringView name = StringView(namePtr, nameEndPtr - namePtr + 1);
name.Trim();
if (name.IsEmpty)
continue;
EnsureChildEntry();
if (childTableEntry.mLastKey == -1)
{
Object value = new:mBumpAllocator String(name);
DoAdd(ref childTableEntry, "", value);
}
else
{
Object value = new:mBumpAllocator box true;
DoAdd(ref childTableEntry, name, value);
}
namePtr = null;
nameEndPtr = null;
idx--;
continue;
}
}
if ((!c.IsWhiteSpace) && (dataStart == null))
dataStart = GetCharPtr() - 1;
}
FlushData();
}
ReadSection(ref loadRoot.mCurrentEntry);
return .Ok;
}
protected Result<void, Error> Load() protected Result<void, Error> Load()
{ {
EnsureHasData(); EnsureHasData();
@ -2354,14 +2626,35 @@ namespace Beefy.utils
mNextKeys.Reserve(guessItems); mNextKeys.Reserve(guessItems);
bool isJson = false; bool isJson = false;
bool isXml = false;
bool mayBeJsonArray = false;
for (char8 c in mSource.RawChars) for (char8 c in mSource.RawChars)
{ {
if (c.IsWhiteSpace) if (c.IsWhiteSpace)
continue; continue;
if (c == '{')
if (mayBeJsonArray)
{
if (c == '[')
continue; // Still ambiguous
if ((c == '{') || (c == '"'))
isJson = true; isJson = true;
break; break;
} }
else
{
if (c == '{')
isJson = true;
if (c == '<')
isXml = true;
if (c == '[')
{
mayBeJsonArray = true;
continue;
}
break;
}
}
int32 aLineNum = 1; int32 aLineNum = 1;
int32 anIdx = 0; int32 anIdx = 0;
@ -2373,6 +2666,14 @@ namespace Beefy.utils
return .Err(err); return .Err(err);
objResult = result.Get(); objResult = result.Get();
} }
else if (isXml)
{
var values = new:mBumpAllocator Values();
let result = LoadXMLHelper(mSource, values, ref anIdx, ref aLineNum);
if (result case .Err(var err))
return .Err(err);
objResult = values;
}
else else
{ {
var values = new:mBumpAllocator NamedValues(); var values = new:mBumpAllocator NamedValues();

View file

@ -459,7 +459,7 @@ namespace Beefy.widgets
public UndoManager mUndoManager = new UndoManager() ~ delete _; public UndoManager mUndoManager = new UndoManager() ~ delete _;
public int32 mNextCharId = 1; // public int32 mNextCharId = 1; //
public int32 mCurTextVersionId = 1; // Changes when text is modified public int32 mCurTextVersionId = 1; // Changes when text is modified
//public int mCurComplexChangeId = 1; // Changes when text is modified by more than a single-char8acter insertion or deletion //public int mCurComplexChangeId = 1; // Changes when text is modified by more than a single-character insertion or deletion
public List<EditWidgetContent> mUsers = new List<EditWidgetContent>() ~ delete _; public List<EditWidgetContent> mUsers = new List<EditWidgetContent>() ~ delete _;
@ -1985,6 +1985,9 @@ namespace Beefy.widgets
{ {
scope AutoBeefPerf("EWC.Undo"); scope AutoBeefPerf("EWC.Undo");
if (CheckReadOnly())
return;
//Profiler.StartSampling(); //Profiler.StartSampling();
if (WantsUndo) if (WantsUndo)
mData.mUndoManager.Undo(); mData.mUndoManager.Undo();
@ -1995,6 +1998,9 @@ namespace Beefy.widgets
{ {
scope AutoBeefPerf("EWC.Redo"); scope AutoBeefPerf("EWC.Redo");
if (CheckReadOnly())
return;
if (WantsUndo) if (WantsUndo)
mData.mUndoManager.Redo(); mData.mUndoManager.Redo();
} }

View file

@ -82,6 +82,8 @@ namespace Beefy.widgets
F12 = 0x7B, F12 = 0x7B,
Numlock = 0x90, Numlock = 0x90,
Scroll = 0x91, Scroll = 0x91,
RAlt = 0xA5,
RMenu = 0xA5,
Semicolon = 0xBA, Semicolon = 0xBA,
Equals = 0xBB, Equals = 0xBB,
Comma = 0xBC, Comma = 0xBC,

View file

@ -339,7 +339,7 @@ namespace Beefy.widgets
} }
else else
{ {
if (item.Selected) if ((item.Selected) && (item.mMouseOver))
{ {
item.mOnMouseUp.AddFront(new => ItemMouseUpHandler); item.mOnMouseUp.AddFront(new => ItemMouseUpHandler);

View file

@ -103,13 +103,13 @@ namespace Beefy.widgets
} }
} }
public bool HorzScrollTo(double horzPos) public bool HorzScrollTo(double horzPos, bool immediate = false)
{ {
double aHorzPos = Math.Max(0, Math.Min(horzPos, mScrollContent.mWidth - mScrollContentContainer.mWidth)); double aHorzPos = Math.Max(0, Math.Min(horzPos, mScrollContent.mWidth - mScrollContentContainer.mWidth));
if (aHorzPos == mHorzPos.mDest) if (aHorzPos == mHorzPos.mDest)
return false; return false;
mHorzPos.Set(aHorzPos); mHorzPos.Set(aHorzPos, immediate);
if (mHorzScrollbar != null) if (mHorzScrollbar != null)
{ {
mHorzScrollbar.mContentPos = mHorzPos.v; mHorzScrollbar.mContentPos = mHorzPos.v;

View file

@ -162,7 +162,7 @@ namespace Beefy.widgets
if ((mSrcDraggingWindow != null) && (mSrcDraggingWindow.mCaptureWidget != null)) if ((mSrcDraggingWindow != null) && (mSrcDraggingWindow.mCaptureWidget != null))
mSrcDraggingWindow.ReleaseMouseCaptures(); mSrcDraggingWindow.ReleaseMouseCaptures();
mTabbedView.mParentDockingFrame.GetRootDockingFrame().HideDragTarget(this, !mDragHelper.mAborted); mTabbedView.mParentDockingFrame?.GetRootDockingFrame().HideDragTarget(this, !mDragHelper.mAborted);
if (mNewDraggingWindow != null) if (mNewDraggingWindow != null)
{ {
mNewDraggingWindow.mOnWindowLostFocus.Remove(scope => WindowDragLostFocusHandler, true); mNewDraggingWindow.mOnWindowLostFocus.Remove(scope => WindowDragLostFocusHandler, true);
@ -176,7 +176,7 @@ namespace Beefy.widgets
public void MouseDrag(float x, float y, float dX, float dY) public void MouseDrag(float x, float y, float dX, float dY)
{ {
mTabbedView.mParentDockingFrame.GetRootDockingFrame().ShowDragTarget(this); mTabbedView.mParentDockingFrame?.GetRootDockingFrame().ShowDragTarget(this);
} }
public override void MouseUp(float x, float y, int32 btn) public override void MouseUp(float x, float y, int32 btn)
@ -198,6 +198,8 @@ namespace Beefy.widgets
public virtual bool IsTotalWindowContent() public virtual bool IsTotalWindowContent()
{ {
if (mTabbedView.mParentDockingFrame == null)
return false;
return (mTabbedView.mParentDockingFrame.mParentDockingFrame == null) && return (mTabbedView.mParentDockingFrame.mParentDockingFrame == null) &&
(mTabbedView.mParentDockingFrame.GetDockedWindowCount() == 1) && (mTabbedView.mParentDockingFrame.GetDockedWindowCount() == 1) &&
(mTabbedView.GetTabCount() == 1) && (mTabbedView.GetTabCount() == 1) &&
@ -318,7 +320,7 @@ namespace Beefy.widgets
//tabbedView.mSharedData.mOpenNewWindowDelegate = mTabbedView.mSharedData.mOpenNewWindowDelegate; //tabbedView.mSharedData.mOpenNewWindowDelegate = mTabbedView.mSharedData.mOpenNewWindowDelegate;
tabbedView.SetRequestedSize(mTabbedView.mWidth, mTabbedView.mHeight); tabbedView.SetRequestedSize(mTabbedView.mWidth, mTabbedView.mHeight);
mTabbedView.RemoveTab(this, false); mTabbedView.RemoveTab(this, false);
tabbedView.AddTab(this); tabbedView.AddTab(this, 0);
float rootX; float rootX;
float rootY; float rootY;
@ -470,7 +472,7 @@ namespace Beefy.widgets
return activeTab; return activeTab;
} }
public virtual TabButton AddTab(String label, float width, Widget content, bool ownsContent) public virtual TabButton AddTab(String label, float width, Widget content, bool ownsContent, int insertIdx)
{ {
TabButton aTabButton = CreateTabButton(); TabButton aTabButton = CreateTabButton();
aTabButton.mTabbedView = this; aTabButton.mTabbedView = this;
@ -479,7 +481,7 @@ namespace Beefy.widgets
aTabButton.mWantWidth = width; aTabButton.mWantWidth = width;
aTabButton.mHeight = mTabHeight; aTabButton.mHeight = mTabHeight;
aTabButton.mContent = content; aTabButton.mContent = content;
AddTab(aTabButton); AddTab(aTabButton, insertIdx);
return aTabButton; return aTabButton;
} }
@ -499,7 +501,7 @@ namespace Beefy.widgets
return bestIdx; return bestIdx;
} }
public virtual void AddTab(TabButton tabButton, int insertIdx = 0) public virtual void AddTab(TabButton tabButton, int insertIdx)
{ {
AddWidget(tabButton); AddWidget(tabButton);
mTabs.Insert(insertIdx, tabButton); mTabs.Insert(insertIdx, tabButton);

View file

@ -121,7 +121,7 @@ namespace Beefy.widgets
KeyFlags keyFlags = default; KeyFlags keyFlags = default;
if (IsKeyDown(KeyCode.Shift)) if (IsKeyDown(KeyCode.Shift))
keyFlags |= KeyFlags.Shift; keyFlags |= KeyFlags.Shift;
if (IsKeyDown(KeyCode.Control)) if ((IsKeyDown(KeyCode.Control)) && (!IsKeyDown(KeyCode.RAlt)))
keyFlags |= KeyFlags.Ctrl; keyFlags |= KeyFlags.Ctrl;
if (IsKeyDown(KeyCode.Menu)) if (IsKeyDown(KeyCode.Menu))
keyFlags |= KeyFlags.Alt; keyFlags |= KeyFlags.Alt;

View file

@ -192,7 +192,8 @@ namespace SDL2
return; return;
int32 channel = SDLMixer.PlayChannel(-1, sound.mChunk, 0); int32 channel = SDLMixer.PlayChannel(-1, sound.mChunk, 0);
//SDLMixer.SetPanning() if (channel < 0)
return;
SDLMixer.Volume(channel, (int32)(volume * 128)); SDLMixer.Volume(channel, (int32)(volume * 128));
} }

View file

@ -36,6 +36,7 @@ namespace System
public bool IsEmpty public bool IsEmpty
{ {
[Inline]
get get
{ {
return mLength == 0; return mLength == 0;
@ -259,6 +260,46 @@ namespace System
} }
} }
public ref T this[Index index]
{
[Checked, Inline]
get
{
int idx;
switch (index)
{
case .FromFront(let offset): idx = offset;
case .FromEnd(let offset): idx = mLength - offset;
}
if ((uint)idx >= (uint)mLength)
Internal.ThrowIndexOutOfRange(1);
return ref (&mFirstElement)[idx];
}
[Unchecked, Inline]
get
{
int idx;
switch (index)
{
case .FromFront(let offset): idx = offset;
case .FromEnd(let offset): idx = mLength - offset;
}
return ref (&mFirstElement)[idx];
}
}
public Span<T> this[IndexRange range]
{
#if !DEBUG
[Inline]
#endif
get
{
return Span<T>(&mFirstElement, mLength)[range];
}
}
[Inline] [Inline]
public T* CArray() public T* CArray()
{ {
@ -276,7 +317,7 @@ namespace System
Debug.Assert(length >= 0); Debug.Assert(length >= 0);
Debug.Assert((uint)srcOffset + (uint)length <= (uint)mLength); Debug.Assert((uint)srcOffset + (uint)length <= (uint)mLength);
Debug.Assert((uint)dstOffset + (uint)length <= (uint)arrayTo.mLength); Debug.Assert((uint)dstOffset + (uint)length <= (uint)arrayTo.mLength);
Internal.MemCpy(&arrayTo.GetRef(dstOffset), &GetRef(srcOffset), strideof(T) * length, alignof(T)); Internal.MemMove(&arrayTo.GetRef(dstOffset), &GetRef(srcOffset), strideof(T) * length, alignof(T));
} }
public void CopyTo<T2>(T2[] arrayTo, int srcOffset, int dstOffset, int length) where T2 : operator explicit T public void CopyTo<T2>(T2[] arrayTo, int srcOffset, int dstOffset, int length) where T2 : operator explicit T
@ -299,17 +340,18 @@ namespace System
public void CopyTo(Span<T> destination) public void CopyTo(Span<T> destination)
{ {
Debug.Assert(destination.[Friend]mLength >= mLength); Debug.Assert(destination.[Friend]mLength >= mLength);
Internal.MemCpy(destination.Ptr, &GetRef(0), strideof(T) * mLength, alignof(T)); Internal.MemMove(destination.Ptr, &GetRef(0), strideof(T) * mLength, alignof(T));
} }
public void CopyTo(Span<T> destination, int srcOffset) public void CopyTo(Span<T> destination, int srcOffset)
{ {
Debug.Assert((uint)srcOffset + (uint)destination.[Friend]mLength <= (uint)mLength); Debug.Assert((uint)srcOffset + (uint)destination.[Friend]mLength <= (uint)mLength);
Internal.MemCpy(destination.Ptr, &GetRef(srcOffset), strideof(T) * (destination.[Friend]mLength - srcOffset), alignof(T)); Internal.MemMove(destination.Ptr, &GetRef(srcOffset), strideof(T) * (destination.[Friend]mLength - srcOffset), alignof(T));
} }
public void CopyTo<T2>(Span<T2> destination, int srcOffset) where T2 : operator explicit T public void CopyTo<T2>(Span<T2> destination, int srcOffset) where T2 : operator explicit T
{ {
//TODO: Handle src/dest overlap (MemMove)
Debug.Assert((uint)srcOffset + (uint)destination.[Friend]mLength <= (uint)mLength); Debug.Assert((uint)srcOffset + (uint)destination.[Friend]mLength <= (uint)mLength);
var ptr = destination.[Friend]mPtr; var ptr = destination.[Friend]mPtr;
for (int i = 0; i < destination.[Friend]mLength; i++) for (int i = 0; i < destination.[Friend]mLength; i++)

View file

@ -1,6 +1,6 @@
namespace System namespace System
{ {
struct Char16 : char16, IHashable, IIsNaN struct Char16 : char16, ICharacter, IHashable, IIsNaN
{ {
const int UNICODE_PLANE00_END = 0x00ffff; const int UNICODE_PLANE00_END = 0x00ffff;
// The starting codepoint for Unicode plane 1. Plane 1 contains 0x010000 ~ 0x01ffff. // The starting codepoint for Unicode plane 1. Plane 1 contains 0x010000 ~ 0x01ffff.

View file

@ -1,6 +1,6 @@
namespace System namespace System
{ {
struct Char32 : char32, IHashable, IIsNaN struct Char32 : char32, ICharacter, IHashable, IIsNaN
{ {
public int GetHashCode() public int GetHashCode()
{ {

View file

@ -1,7 +1,7 @@
namespace System namespace System
{ {
#unwarn #unwarn
struct Char8 : char8, IHashable, IIsNaN struct Char8 : char8, ICharacter, IHashable, IIsNaN
{ {
bool IIsNaN.IsNaN bool IIsNaN.IsNaN
{ {

View file

@ -26,7 +26,7 @@ namespace System.Collections
{ {
public TKey mKey; // Key of entry public TKey mKey; // Key of entry
public TValue mValue; // Value of entry public TValue mValue; // Value of entry
public int32 mHashCode; // Lower 31 bits of hash code, -1 if unused public int_cosize mHashCode; // some bits of hash code, -1 if unused
public int_cosize mNext; // Index of next entry, -1 if last public int_cosize mNext; // Index of next entry, -1 if last
} }
@ -257,22 +257,10 @@ namespace System.Collections
} }
public bool ContainsValue(TValue value) public bool ContainsValue(TValue value)
{
if (value == null)
{ {
for (int_cosize i = 0; i < mCount; i++) for (int_cosize i = 0; i < mCount; i++)
{ {
if (mEntries[i].mHashCode >= 0 && mEntries[i].mValue == null) return true; if (mEntries[i].mHashCode >= 0 && mEntries[i].mValue == value) return true;
}
}
else
{
//TODO: IMPORTANT!
/*EqualityComparer<TValue> c = EqualityComparer<TValue>.Default;
for (int i = 0; i < count; i++)
{
if (entries[i].hashCode >= 0 && c.Equals(entries[i].value, value)) return true;
}*/
} }
return false; return false;
} }
@ -290,6 +278,19 @@ namespace System.Collections
} }
} }
public bool ContainsAlt<TAltKey>((TAltKey key, TValue value) kvPair) where TAltKey : IHashable where bool : operator TKey == TAltKey
{
TValue value;
if (TryGetValueAlt(kvPair.key, out value))
{
return value == kvPair.value;
}
else
{
return false;
}
}
public void CopyTo(Span<KeyValuePair> kvPair) public void CopyTo(Span<KeyValuePair> kvPair)
{ {
Debug.Assert(kvPair.Length >= mCount); Debug.Assert(kvPair.Length >= mCount);
@ -306,12 +307,21 @@ namespace System.Collections
return Enumerator(this, Enumerator.[Friend]KeyValuePair); return Enumerator(this, Enumerator.[Friend]KeyValuePair);
} }
static int_cosize GetKeyHash(int hashCode)
{
if (sizeof(int) == 4)
return (int32)hashCode & 0x7FFFFFFF;
if (sizeof(int_cosize) == 8)
return (int_cosize)(hashCode & 0x7FFFFFFF'FFFFFFFFL);
return ((int32)hashCode ^ (int32)((int64)hashCode >> 33)) & 0x7FFFFFFF;
}
[DisableObjectAccessChecks] [DisableObjectAccessChecks]
private int FindEntry(TKey key) private int FindEntry(TKey key)
{ {
if (mBuckets != null) if (mBuckets != null)
{ {
int hashCode = key.GetHashCode() & 0x7FFFFFFF; int_cosize hashCode = GetKeyHash(key.GetHashCode());
for (int i = mBuckets[hashCode % mAllocSize]; i >= 0; i = mEntries[i].mNext) for (int i = mBuckets[hashCode % mAllocSize]; i >= 0; i = mEntries[i].mNext)
{ {
if (mEntries[i].mHashCode == hashCode && (mEntries[i].mKey == key)) return i; if (mEntries[i].mHashCode == hashCode && (mEntries[i].mKey == key)) return i;
@ -329,7 +339,7 @@ namespace System.Collections
{ {
if (mBuckets != null) if (mBuckets != null)
{ {
int_cosize hashCode = (int_cosize)key.GetHashCode() & 0x7FFFFFFF; int_cosize hashCode = GetKeyHash(key.GetHashCode());
for (int_cosize i = mBuckets[hashCode % mAllocSize]; i >= 0; i = mEntries[i].mNext) for (int_cosize i = mBuckets[hashCode % mAllocSize]; i >= 0; i = mEntries[i].mNext)
{ {
if (mEntries[i].mHashCode == hashCode && (mEntries[i].mKey == key)) return i; if (mEntries[i].mHashCode == hashCode && (mEntries[i].mKey == key)) return i;
@ -350,10 +360,10 @@ namespace System.Collections
private void Insert(TKey key, TValue value, bool add) private void Insert(TKey key, TValue value, bool add)
{ {
if (mBuckets == null) Initialize(0); if (mBuckets == null) Initialize(0);
int32 hashCode = (int32)key.GetHashCode() & 0x7FFFFFFF; int_cosize hashCode = GetKeyHash(key.GetHashCode());
int_cosize targetBucket = hashCode % (int_cosize)mAllocSize; int targetBucket = hashCode % mAllocSize;
for (int_cosize i = mBuckets[targetBucket]; i >= 0; i = mEntries[i].mNext) for (int i = mBuckets[targetBucket]; i >= 0; i = mEntries[i].mNext)
{ {
if (mEntries[i].mHashCode == hashCode && (mEntries[i].mKey == key)) if (mEntries[i].mHashCode == hashCode && (mEntries[i].mKey == key))
{ {
@ -402,7 +412,7 @@ namespace System.Collections
private bool Insert(TKey key, bool add, out TKey* keyPtr, out TValue* valuePtr, Entry** outOldData) private bool Insert(TKey key, bool add, out TKey* keyPtr, out TValue* valuePtr, Entry** outOldData)
{ {
if (mBuckets == null) Initialize(0); if (mBuckets == null) Initialize(0);
int32 hashCode = (int32)key.GetHashCode() & 0x7FFFFFFF; int_cosize hashCode = GetKeyHash(key.GetHashCode());
int_cosize targetBucket = hashCode % (int_cosize)mAllocSize; int_cosize targetBucket = hashCode % (int_cosize)mAllocSize;
for (int_cosize i = mBuckets[targetBucket]; i >= 0; i = mEntries[i].mNext) for (int_cosize i = mBuckets[targetBucket]; i >= 0; i = mEntries[i].mNext)
{ {
@ -458,9 +468,9 @@ namespace System.Collections
private bool InsertAlt<TAltKey>(TAltKey key, bool add, out TKey* keyPtr, out TValue* valuePtr, Entry** outOldData) where TAltKey : IHashable where bool : operator TKey == TAltKey private bool InsertAlt<TAltKey>(TAltKey key, bool add, out TKey* keyPtr, out TValue* valuePtr, Entry** outOldData) where TAltKey : IHashable where bool : operator TKey == TAltKey
{ {
if (mBuckets == null) Initialize(0); if (mBuckets == null) Initialize(0);
int32 hashCode = (int32)key.GetHashCode() & 0x7FFFFFFF; int_cosize hashCode = GetKeyHash(key.GetHashCode());
int_cosize targetBucket = hashCode % (int_cosize)mAllocSize; int targetBucket = hashCode % (int_cosize)mAllocSize;
for (int_cosize i = mBuckets[targetBucket]; i >= 0; i = mEntries[i].mNext) for (int i = mBuckets[targetBucket]; i >= 0; i = mEntries[i].mNext)
{ {
if (mEntries[i].mHashCode == hashCode && (mEntries[i].mKey == key)) if (mEntries[i].mHashCode == hashCode && (mEntries[i].mKey == key))
{ {
@ -541,7 +551,7 @@ namespace System.Collections
{ {
if (newEntries[i].mHashCode != -1) if (newEntries[i].mHashCode != -1)
{ {
newEntries[i].mHashCode = (int32)newEntries[i].mKey.GetHashCode() & 0x7FFFFFFF; newEntries[i].mHashCode = GetKeyHash(newEntries[i].mKey.GetHashCode());
} }
} }
} }
@ -572,7 +582,7 @@ namespace System.Collections
{ {
if (mBuckets != null) if (mBuckets != null)
{ {
int hashCode = key.GetHashCode() & 0x7FFFFFFF; int_cosize hashCode = GetKeyHash(key.GetHashCode());
int bucket = hashCode % (int_cosize)mAllocSize; int bucket = hashCode % (int_cosize)mAllocSize;
int last = -1; int last = -1;
for (int_cosize i = mBuckets[bucket]; i >= 0; last = i,i = mEntries[i].mNext) for (int_cosize i = mBuckets[bucket]; i >= 0; last = i,i = mEntries[i].mNext)
@ -609,7 +619,7 @@ namespace System.Collections
{ {
if (mBuckets != null) if (mBuckets != null)
{ {
int hashCode = key.GetHashCode() & 0x7FFFFFFF; int_cosize hashCode = GetKeyHash(key.GetHashCode());
int bucket = hashCode % (int_cosize)mAllocSize; int bucket = hashCode % (int_cosize)mAllocSize;
int last = -1; int last = -1;
for (int_cosize i = mBuckets[bucket]; i >= 0; last = i,i = mEntries[i].mNext) for (int_cosize i = mBuckets[bucket]; i >= 0; last = i,i = mEntries[i].mNext)
@ -653,8 +663,8 @@ namespace System.Collections
if (mBuckets != null) if (mBuckets != null)
{ {
int_cosize hashCode = (int_cosize)key.GetHashCode() & 0x7FFFFFFF; int_cosize hashCode = GetKeyHash(key.GetHashCode());
int_cosize bucket = hashCode % (int_cosize)mAllocSize; int bucket = hashCode % (int_cosize)mAllocSize;
int_cosize last = -1; int_cosize last = -1;
for (int_cosize i = mBuckets[bucket]; i >= 0; last = i,i = mEntries[i].mNext) for (int_cosize i = mBuckets[bucket]; i >= 0; last = i,i = mEntries[i].mNext)
{ {
@ -694,8 +704,8 @@ namespace System.Collections
if (mBuckets != null) if (mBuckets != null)
{ {
int_cosize hashCode = (int_cosize)key.GetHashCode() & 0x7FFFFFFF; int_cosize hashCode = GetKeyHash(key.GetHashCode());
int_cosize bucket = hashCode % (int_cosize)mAllocSize; int bucket = hashCode % (int_cosize)mAllocSize;
int_cosize last = -1; int_cosize last = -1;
for (int_cosize i = mBuckets[bucket]; i >= 0; last = i,i = mEntries[i].mNext) for (int_cosize i = mBuckets[bucket]; i >= 0; last = i,i = mEntries[i].mNext)
{ {
@ -742,6 +752,18 @@ namespace System.Collections
return false; return false;
} }
public bool TryGetValueAlt<TAltKey>(TAltKey key, out TValue value) where TAltKey : IHashable where bool : operator TKey == TAltKey
{
int_cosize i = (int_cosize)FindEntryAlt<TAltKey>(key);
if (i >= 0)
{
value = mEntries[i].mValue;
return true;
}
value = default(TValue);
return false;
}
public bool TryGet(TKey key, out TKey matchKey, out TValue value) public bool TryGet(TKey key, out TKey matchKey, out TValue value)
{ {
int_cosize i = (int_cosize)FindEntry(key); int_cosize i = (int_cosize)FindEntry(key);
@ -876,6 +898,16 @@ namespace System.Collections
mDictionary.mEntries[mCurrentIndex].mValue = value; mDictionary.mEntries[mCurrentIndex].mValue = value;
} }
public void Remove() mut
{
int_cosize curIdx = mIndex - 1;
mDictionary.Remove(mDictionary.mEntries[curIdx].mKey);
#if VERSION_DICTIONARY
mVersion = mDictionary.mVersion;
#endif
mIndex = curIdx;
}
public void Reset() mut public void Reset() mut
{ {
#if VERSION_DICTIONARY #if VERSION_DICTIONARY
@ -1017,6 +1049,16 @@ namespace System.Collections
{ {
} }
public void Remove() mut
{
int_cosize curIdx = mIndex - 1;
mDictionary.Remove(mDictionary.mEntries[curIdx].mKey);
#if VERSION_DICTIONARY
mVersion = mDictionary.mVersion;
#endif
mIndex = curIdx;
}
public void Reset() mut public void Reset() mut
{ {
#if VERSION_DICTIONARY #if VERSION_DICTIONARY
@ -1113,6 +1155,16 @@ namespace System.Collections
{ {
} }
public void Remove() mut
{
int_cosize curIdx = mIndex - 1;
mDictionary.Remove(mDictionary.mEntries[curIdx].mKey);
#if VERSION_DICTIONARY
mVersion = mDictionary.mVersion;
#endif
mIndex = curIdx;
}
public void Reset() mut public void Reset() mut
{ {
#if VERSION_DICTIONARY #if VERSION_DICTIONARY

View file

@ -196,7 +196,13 @@ namespace System.Collections
return false; return false;
} }
[Obsolete("Method renamed to ContainsAlt", false)]
public bool ContainsWith<TAltKey>(TAltKey item) where TAltKey : IHashable where bool : operator T == TAltKey public bool ContainsWith<TAltKey>(TAltKey item) where TAltKey : IHashable where bool : operator T == TAltKey
{
return ContainsAlt(item);
}
public bool ContainsAlt<TAltKey>(TAltKey item) where TAltKey : IHashable where bool : operator T == TAltKey
{ {
if (mBuckets != null) if (mBuckets != null)
{ {
@ -346,6 +352,11 @@ namespace System.Collections
return Add(item, out entryPtr); return Add(item, out entryPtr);
} }
public bool TryAddAlt<TAltKey>(TAltKey item, out T* entryPtr) where TAltKey : IHashable where bool : operator T == TAltKey
{
return AddAlt(item, out entryPtr);
}
public void CopyTo(T[] array) { CopyTo(array, 0, mCount); } public void CopyTo(T[] array) { CopyTo(array, 0, mCount); }
public void CopyTo(T[] array, int32 arrayIndex, int32 count) public void CopyTo(T[] array, int32 arrayIndex, int32 count)
@ -632,6 +643,71 @@ namespace System.Collections
mVersion++; mVersion++;
#endif #endif
#if FEATURE_RANDOMIZED_STRING_HASHING && !FEATURE_NETCORE
if(collisionCount > HashHelpers.HashCollisionThreshold && HashHelpers.IsWellKnownEqualityComparer(m_comparer)) {
m_comparer = (IEqualityComparer<T>) HashHelpers.GetRandomizedEqualityComparer(m_comparer);
SetCapacity(m_buckets.Length, true);
}
#endif // FEATURE_RANDOMIZED_STRING_HASHING
entryPtr = &mSlots[index].mValue;
return true;
}
/// Adds value to HashSet if not contained already
/// @return true if added and false if already present
/// @param value value to find
/// @param entryPtr ponter to entry
public bool AddAlt<TAltKey>(TAltKey value, out T* entryPtr) where TAltKey : IHashable where bool : operator T == TAltKey
{
if (mBuckets == null)
{
Initialize(0);
}
int32 hashCode = (int32)InternalGetHashCodeAlt(value);
int32 bucket = hashCode % (int32)mBuckets.Count;
#if FEATURE_RANDOMIZED_STRING_HASHING && !FEATURE_NETCORE
int collisionCount = 0;
#endif
for (int32 i = mBuckets[hashCode % mBuckets.Count] - 1; i >= 0; i = mSlots[i].mNext)
{
if (mSlots[i].mHashCode == hashCode && /*m_comparer.Equals*/(mSlots[i].mValue == value))
{
entryPtr = &mSlots[i].mValue;
return false;
}
#if FEATURE_RANDOMIZED_STRING_HASHING && !FEATURE_NETCORE
collisionCount++;
#endif
}
int32 index;
if (mFreeList >= 0)
{
index = mFreeList;
mFreeList = mSlots[index].mNext;
}
else
{
if (mLastIndex == mSlots.Count)
{
IncreaseCapacity();
// this will change during resize
bucket = hashCode % (int32)mBuckets.Count;
}
index = mLastIndex;
mLastIndex++;
}
mSlots[index].mHashCode = hashCode;
//mSlots[index].mValue = value;
mSlots[index].mNext = mBuckets[bucket] - 1;
mBuckets[bucket] = index + 1;
mCount++;
#if VERSION_HASHSET
mVersion++;
#endif
#if FEATURE_RANDOMIZED_STRING_HASHING && !FEATURE_NETCORE #if FEATURE_RANDOMIZED_STRING_HASHING && !FEATURE_NETCORE
if(collisionCount > HashHelpers.HashCollisionThreshold && HashHelpers.IsWellKnownEqualityComparer(m_comparer)) { if(collisionCount > HashHelpers.HashCollisionThreshold && HashHelpers.IsWellKnownEqualityComparer(m_comparer)) {
m_comparer = (IEqualityComparer<T>) HashHelpers.GetRandomizedEqualityComparer(m_comparer); m_comparer = (IEqualityComparer<T>) HashHelpers.GetRandomizedEqualityComparer(m_comparer);
@ -1071,6 +1147,15 @@ namespace System.Collections
return item.GetHashCode() & Lower31BitMask; return item.GetHashCode() & Lower31BitMask;
} }
private int InternalGetHashCodeAlt<TAltKey>(TAltKey item) where TAltKey : IHashable
{
if (item == null)
{
return 0;
}
return item.GetHashCode() & Lower31BitMask;
}
#endregion #endregion
// used for set checking operations (using enumerables) that rely on counting // used for set checking operations (using enumerables) that rely on counting

View file

@ -148,6 +148,7 @@ namespace System.Collections
public int Count public int Count
{ {
[Inline]
get get
{ {
return mSize; return mSize;
@ -210,6 +211,76 @@ namespace System.Collections
} }
} }
public ref T this[Index index]
{
[Checked]
get
{
int idx;
switch (index)
{
case .FromFront(let offset): idx = offset;
case .FromEnd(let offset): idx = mSize - offset;
}
Runtime.Assert((uint)idx < (uint)mSize);
return ref mItems[idx];
}
[Unchecked, Inline]
get
{
int idx;
switch (index)
{
case .FromFront(let offset): idx = offset;
case .FromEnd(let offset): idx = mSize - offset;
}
return ref mItems[idx];
}
[Checked]
set
{
int idx;
switch (index)
{
case .FromFront(let offset): idx = offset;
case .FromEnd(let offset): idx = mSize - offset;
}
Runtime.Assert((uint)idx < (uint)mSize);
mItems[idx] = value;
#if VERSION_LIST
mVersion++;
#endif
}
[Unchecked, Inline]
set
{
int idx;
switch (index)
{
case .FromFront(let offset): idx = offset;
case .FromEnd(let offset): idx = mSize - offset;
}
mItems[idx] = value;
#if VERSION_LIST
mVersion++;
#endif
}
}
public Span<T> this[IndexRange range]
{
#if !DEBUG
[Inline]
#endif
get
{
return Span<T>(mItems, mSize)[range];
}
}
public ref T Front public ref T Front
{ {
get get
@ -534,7 +605,7 @@ namespace System.Collections
if (mSize == AllocSize) EnsureCapacity(mSize + 1, true); if (mSize == AllocSize) EnsureCapacity(mSize + 1, true);
if (index < mSize) if (index < mSize)
{ {
Internal.MemCpy(mItems + index + 1, mItems + index, (mSize - index) * strideof(T), alignof(T)); Internal.MemMove(mItems + index + 1, mItems + index, (mSize - index) * strideof(T), alignof(T));
} }
mItems[index] = item; mItems[index] = item;
mSize++; mSize++;
@ -553,7 +624,7 @@ namespace System.Collections
if (mSize + addCount > AllocSize) EnsureCapacity(mSize + addCount, true); if (mSize + addCount > AllocSize) EnsureCapacity(mSize + addCount, true);
if (index < mSize) if (index < mSize)
{ {
Internal.MemCpy(mItems + index + addCount, mItems + index, (mSize - index) * strideof(T), alignof(T)); Internal.MemMove(mItems + index + addCount, mItems + index, (mSize - index) * strideof(T), alignof(T));
} }
Internal.MemCpy(mItems + index, items.Ptr, addCount * strideof(T)); Internal.MemCpy(mItems + index, items.Ptr, addCount * strideof(T));
mSize += (int_cosize)addCount; mSize += (int_cosize)addCount;
@ -567,7 +638,7 @@ namespace System.Collections
Debug.Assert((uint)index < (uint)mSize); Debug.Assert((uint)index < (uint)mSize);
if (index < mSize - 1) if (index < mSize - 1)
{ {
Internal.MemCpy(mItems + index, mItems + index + 1, (mSize - index - 1) * strideof(T), alignof(T)); Internal.MemMove(mItems + index, mItems + index + 1, (mSize - index - 1) * strideof(T), alignof(T));
} }
mSize--; mSize--;
#if VERSION_LIST #if VERSION_LIST
@ -930,6 +1001,59 @@ namespace System.Collections
} }
} }
extension List<T> where T : String
{
public bool Contains(T item, StringComparison comparison)
{
if (item == null)
{
for (int i = 0; i < mSize; i++)
if (mItems[i] == null)
return true;
return false;
}
else
{
for (int i = 0; i < mSize; i++)
if (mItems[i].Equals(item, comparison))
return true;
return false;
}
}
public int IndexOf(T item, StringComparison comparison)
{
for (int i = 0; i < mSize; i++)
if (mItems[i].Equals(item, comparison))
return i;
return -1;
}
public int IndexOf(T item, int index, StringComparison comparison)
{
for (int i = index; i < mSize; i++)
if (mItems[i].Equals(item, comparison))
return i;
return -1;
}
public int IndexOf(T item, int index, int count, StringComparison comparison)
{
for (int i = index; i < index + count; i++)
if (mItems[i].Equals(item, comparison))
return i;
return -1;
}
public int LastIndexOf(T item, StringComparison comparison)
{
for (int i = mSize - 1; i >= 0; i--)
if (mItems[i].Equals(item, comparison))
return i;
return -1;
}
}
class ListWithAlloc<T> : List<T> class ListWithAlloc<T> : List<T>
{ {
IRawAllocator mAlloc; IRawAllocator mAlloc;

View file

@ -18,6 +18,12 @@ namespace System
} }
} }
public static class Options
{
[LinkName("#AllocStackCount")]
public static extern int32 AllocStackCount;
}
[LinkName("#CallerLineNum")] [LinkName("#CallerLineNum")]
public static extern int CallerLineNum; public static extern int CallerLineNum;
@ -37,7 +43,7 @@ namespace System
public static extern String CallerProject; public static extern String CallerProject;
[LinkName("#CallerExpression")] [LinkName("#CallerExpression")]
public static extern String[Int32.MaxValue] CallerExpression; public static extern String[0x0FFFFFFF] CallerExpression;
[LinkName("#ProjectName")] [LinkName("#ProjectName")]
public static extern String ProjectName; public static extern String ProjectName;

View file

@ -7,6 +7,12 @@ namespace System
{ {
public static class Console public static class Console
{ {
public enum CancelKind
{
CtrlC,
CtrlBreak
}
static Encoding InputEncoding = Encoding.ASCII; static Encoding InputEncoding = Encoding.ASCII;
static Encoding OutputEncoding = Encoding.ASCII; static Encoding OutputEncoding = Encoding.ASCII;
@ -16,6 +22,9 @@ namespace System
static readonly ConsoleColor sOriginalForegroundColor = sForegroundColor; static readonly ConsoleColor sOriginalForegroundColor = sForegroundColor;
static readonly ConsoleColor sOriginalBackgroundColor = sBackgroundColor; static readonly ConsoleColor sOriginalBackgroundColor = sBackgroundColor;
static Event<delegate void (CancelKind cancelKind, ref bool terminate)> sOnCancel ~ _.Dispose();
static bool sCancelEventRegistered;
public static ConsoleColor ForegroundColor public static ConsoleColor ForegroundColor
{ {
get { return sForegroundColor; } get { return sForegroundColor; }
@ -42,16 +51,57 @@ namespace System
public uint16[2] mMaximumWindowSize; public uint16[2] mMaximumWindowSize;
} }
[CLink, CallingConvention(.Stdcall)] [CRepr]
static extern int SetConsoleTextAttribute(void* hConsoleOutput, uint16 wAttributes); struct COORD : this(int16 X, int16 Y)
{
}
[CLink, CallingConvention(.Stdcall)] public static ref Event<delegate void (CancelKind cancelKind, ref bool terminate)> OnCancel
static extern int GetConsoleScreenBufferInfo(void* hConsoleOutput, out CONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo); {
get
[CLink, CallingConvention(.Stdcall)] {
static extern void* GetStdHandle(uint32 nStdHandle); if (!sCancelEventRegistered)
{
sCancelEventRegistered = true;
#if BF_PLATFORM_WINDOWS
SetConsoleCtrlHandler(=> ConsoleCtrlHandler, true);
#endif
}
return ref sOnCancel;
}
}
#if BF_PLATFORM_WINDOWS #if BF_PLATFORM_WINDOWS
[CallingConvention(.Stdcall)]
public static Windows.IntBool ConsoleCtrlHandler(int32 ctrlType)
{
bool terminate = true;
if ((ctrlType == 0) || (ctrlType == 1))
sOnCancel((.)ctrlType, ref terminate);
return terminate ? false : true;
}
[CLink, CallingConvention(.Stdcall)]
static extern Windows.IntBool SetConsoleTextAttribute(Windows.Handle hConsoleOutput, uint16 wAttributes);
[CLink, CallingConvention(.Stdcall)]
static extern Windows.IntBool GetConsoleScreenBufferInfo(Windows.Handle hConsoleOutput, out CONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo);
[CLink, CallingConvention(.Stdcall)]
static extern Windows.Handle GetStdHandle(uint32 nStdHandle);
[CallingConvention(.Stdcall)]
function Windows.IntBool ConsoleCtrlHandler(int32 ctrlType);
[CLink, CallingConvention(.Stdcall)]
static extern Windows.IntBool SetConsoleCtrlHandler(ConsoleCtrlHandler handler, Windows.IntBool addHandler);
[CLink, CallingConvention(.Stdcall)]
static extern Windows.IntBool FillConsoleOutputCharacterW(Windows.Handle hConsoleOutput, char16 cCharacter, uint32 nLength, COORD dwWriteCoord, uint32* lpNumberOfCharsWritten);
[CLink, CallingConvention(.Stdcall)]
static extern Windows.IntBool FillConsoleOutputAttribute(Windows.Handle hConsoleOutput, uint16 wAttribute, uint32 nLength, COORD dwWriteCoord, uint32* lpNumberOfAttrsWritten);
[CLink, CallingConvention(.Stdcall)]
static extern Windows.IntBool SetConsoleCursorPosition(Windows.Handle hConsoleOutput, COORD dwCursorPosition);
public static this() public static this()
{ {
let handle = GetStdHandle(STD_OUTPUT_HANDLE); let handle = GetStdHandle(STD_OUTPUT_HANDLE);
@ -219,6 +269,49 @@ namespace System
#else #else
Write("\x1B[{}m", ForegroundColor.AnsiCode); Write("\x1B[{}m", ForegroundColor.AnsiCode);
Write("\x1B[{}m", BackgroundColor.AnsiCode + 10); Write("\x1B[{}m", BackgroundColor.AnsiCode + 10);
#endif
}
public static void Clear()
{
#if BF_PLATFORM_WINDOWS
Windows.Handle hStdOut;
CONSOLE_SCREEN_BUFFER_INFO csbi;
uint32 count;
uint32 cellCount;
COORD homeCoords = .(0, 0);
hStdOut = GetStdHandle( STD_OUTPUT_HANDLE );
if (hStdOut == .InvalidHandle)
return;
/* Get the number of cells in the current buffer */
if (!GetConsoleScreenBufferInfo( hStdOut, out csbi ))
return;
cellCount = csbi.mSize[0] * csbi.mSize[1];
/* Fill the entire buffer with spaces */
if (!FillConsoleOutputCharacterW(
hStdOut,
' ',
cellCount,
homeCoords,
&count
)) return;
/* Fill the entire buffer with the current colors and attributes */
if (!FillConsoleOutputAttribute(
hStdOut,
csbi.mAttributes,
cellCount,
homeCoords,
&count
)) return;
/* Move the cursor home */
SetConsoleCursorPosition( hStdOut, homeCoords );
#else
Write("\x1B[H\x1B[J");
#endif #endif
} }
} }

View file

@ -19,7 +19,7 @@ namespace System.Diagnostics
private char8[] char8Buffer; private char8[] char8Buffer;
// Record the number of valid bytes in the byteBuffer, for a few checks. // Record the number of valid bytes in the byteBuffer, for a few checks.
// This is the maximum number of char8s we can get from one call to // This is the maximum number of chars we can get from one call to
// ReadBuffer. Used so ReadBuffer can tell when to copy data into // ReadBuffer. Used so ReadBuffer can tell when to copy data into
// a user's char8[] directly, instead of our internal char8[]. // a user's char8[] directly, instead of our internal char8[].
private int32 mMaxCharsPerBuffer; private int32 mMaxCharsPerBuffer;
@ -194,7 +194,7 @@ namespace System.Diagnostics
int lineStart = 0; int lineStart = 0;
int len = sb.Length; int len = sb.Length;
// skip a beginning '\n' char8acter of new block if last block ended // skip a beginning '\n' character of new block if last block ended
// with '\r' // with '\r'
if (bLastCarriageReturn && (len > 0) && sb[0] == '\n') if (bLastCarriageReturn && (len > 0) && sb[0] == '\n')
{ {
@ -206,7 +206,7 @@ namespace System.Diagnostics
while (currentIndex < len) while (currentIndex < len)
{ {
char8 ch = sb[currentIndex]; char8 ch = sb[currentIndex];
// Note the following common line feed char8s: // Note the following common line feed chars:
// \n - UNIX \r\n - DOS \r - Mac // \n - UNIX \r\n - DOS \r - Mac
if (ch == '\r' || ch == '\n') if (ch == '\r' || ch == '\n')
{ {
@ -214,7 +214,7 @@ namespace System.Diagnostics
s.Append(sb, lineStart, currentIndex - lineStart); s.Append(sb, lineStart, currentIndex - lineStart);
lineStart = currentIndex + 1; lineStart = currentIndex + 1;
// skip the "\n" char8acter following "\r" char8acter // skip the "\n" character following "\r" character
if ((ch == '\r') && (lineStart < len) && (sb[lineStart] == '\n')) if ((ch == '\r') && (lineStart < len) && (sb[lineStart] == '\n'))
{ {
lineStart++; lineStart++;
@ -232,7 +232,7 @@ namespace System.Diagnostics
{ {
bLastCarriageReturn = true; bLastCarriageReturn = true;
} }
// Keep the rest char8acaters which can't form a new line in string builder. // Keep the rest characaters which can't form a new line in string builder.
if (lineStart < len) if (lineStart < len)
{ {
if (lineStart == 0) if (lineStart == 0)

View file

@ -1,6 +1,6 @@
namespace System.Diagnostics namespace System.Diagnostics
{ {
class Check static class Check
{ {
[Unchecked, SkipCall] [Unchecked, SkipCall]

View file

@ -1,6 +1,6 @@
namespace System.Diagnostics.Contracts namespace System.Diagnostics.Contracts
{ {
class Contract static class Contract
{ {
public enum ContractFailureKind public enum ContractFailureKind
{ {

View file

@ -1,6 +1,6 @@
namespace System.Diagnostics namespace System.Diagnostics
{ {
class Debug static class Debug
{ {
#if !DEBUG #if !DEBUG
[SkipCall] [SkipCall]
@ -44,6 +44,11 @@ namespace System.Diagnostics
Write(line.Ptr, line.Length); Write(line.Ptr, line.Length);
} }
public static void Write(StringView sv)
{
Write(sv.[Friend]mPtr, sv.[Friend]mLength);
}
public static void Write(String fmt, params Object[] args) public static void Write(String fmt, params Object[] args)
{ {
String str = scope String(4096); String str = scope String(4096);

View file

@ -136,7 +136,7 @@ namespace System
} }
} }
public void Remove(T compareDelegate, bool deleteDelegate = false) mut public Result<void> Remove(T compareDelegate, bool deleteDelegate = false) mut
{ {
Object data = Target; Object data = Target;
@ -150,9 +150,7 @@ namespace System
break; break;
} }
if (idx == -1) if (idx == -1)
{ return .Err;
Runtime.FatalError("Not found");
}
if (deleteDelegate) if (deleteDelegate)
delete list[idx]; delete list[idx];
@ -177,18 +175,14 @@ namespace System
else else
{ {
T dlgMember = (T)data; T dlgMember = (T)data;
if (Delegate.Equals(compareDelegate, dlgMember)) if (!Delegate.Equals(compareDelegate, dlgMember))
{ return .Err;
if (deleteDelegate) if (deleteDelegate)
delete dlgMember; delete dlgMember;
Target = null; Target = null;
return;
}
else
{
Runtime.FatalError("Not found");
}
} }
return .Ok;
} }
public rettype(T) Invoke(params T p) mut public rettype(T) Invoke(params T p) mut

View file

@ -175,6 +175,17 @@ namespace System
{ {
char8 c = val.Ptr[i]; char8 c = val.Ptr[i];
//Exponent prefix used in scientific notation. E.g. 1.2E5
if ((c == 'e') || (c == 'E'))
{
//Error if there are no numbers after the prefix
if(i == val.Length - 1)
return .Err;
var exponent = Try!(int32.Parse(val.Substring(i + 1)));
result *= Math.Pow(10, (double)exponent);
break;
}
if (c == '.') if (c == '.')
{ {
if (decimalMultiplier != 0) if (decimalMultiplier != 0)

View file

@ -173,6 +173,10 @@ namespace System
// or the memory would already be registered with the GC // or the memory would already be registered with the GC
} }
public static mixin Mark<T>(T val)
{
}
public static mixin Mark<TSizedArray, T, Size>(TSizedArray val) where Size : const int where TSizedArray : SizedArray<T, Size> public static mixin Mark<TSizedArray, T, Size>(TSizedArray val) where Size : const int where TSizedArray : SizedArray<T, Size>
{ {
#if BF_ENABLE_REALTIME_LEAK_CHECK #if BF_ENABLE_REALTIME_LEAK_CHECK

View file

@ -29,7 +29,7 @@ namespace System.Globalization
// cache for the invariant culture. // cache for the invariant culture.
// invariantInfo is constant irrespective of your current culture. // invariantInfo is constant irrespective of your current culture.
private static volatile DateTimeFormatInfo invariantInfo; private static volatile DateTimeFormatInfo invariantInfo ~ delete _;
// an index which points to a record in Culture Data Table. // an index which points to a record in Culture Data Table.
private CultureData m_cultureData; private CultureData m_cultureData;
@ -139,6 +139,8 @@ namespace System.Globalization
List<Object> ownedObjects = new .() ~ DeleteContainerAndItems!(_); List<Object> ownedObjects = new .() ~ DeleteContainerAndItems!(_);
public this() public this()
: this(CultureInfo.InvariantCulture.[Friend]m_cultureData,
GregorianCalendar.[Friend]GetDefaultInstance())
{ {
} }

View file

@ -63,7 +63,7 @@ namespace System.Globalization {
0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366
) ~ delete _; ) ~ delete _;
private static volatile Calendar s_defaultInstance; private static volatile Calendar s_defaultInstance ~ delete _;
#region Serialization #region Serialization

View file

@ -23,6 +23,10 @@ namespace System
{ {
} }
interface ICharacter
{
}
[Obsolete("Consider operator constraint such as `where bool : operator T == T`", false)] [Obsolete("Consider operator constraint such as `where bool : operator T == T`", false)]
interface IOpEquals interface IOpEquals
{ {

View file

@ -68,7 +68,7 @@ namespace System.IO
public override Result<int> TryRead(Span<uint8> data) public override Result<int> TryRead(Span<uint8> data)
{ {
int spaceLeft = (.)(mBufferEnd - mPos); int64 spaceLeft = (.)(mBufferEnd - mPos);
if (mPos < mBufferPos) if (mPos < mBufferPos)
spaceLeft = 0; spaceLeft = 0;
if (data.Length <= spaceLeft) if (data.Length <= spaceLeft)
@ -83,18 +83,16 @@ namespace System.IO
var data; var data;
if (spaceLeft > 0) if (spaceLeft > 0)
{ {
Internal.MemCpy(data.Ptr, mBuffer.Ptr + (mPos - mBufferPos), spaceLeft); Internal.MemCpy(data.Ptr, mBuffer.Ptr + (mPos - mBufferPos), (.)spaceLeft);
mPos += spaceLeft; mPos += spaceLeft;
data.RemoveFromStart(spaceLeft); data.RemoveFromStart((.)spaceLeft);
} }
if (mWriteDirtyPos >= 0)
Try!(Flush()); Try!(Flush());
if ((mBuffer == null) || (data.Length > mBuffer.Count)) if ((mBuffer == null) || (data.Length > mBuffer.Count))
{ {
var result = TryReadUnderlying(mPos, data); let len = Try!(TryReadUnderlying(mPos, data));
if (result case .Ok(let len))
mPos += len; mPos += len;
return (.)(mPos - readStart); return (.)(mPos - readStart);
} }
@ -148,10 +146,9 @@ namespace System.IO
if ((mBuffer == null) || (data.Length > mBuffer.Count)) if ((mBuffer == null) || (data.Length > mBuffer.Count))
{ {
var result = TryWriteUnderlying(mPos, data); let len = Try!(TryWriteUnderlying(mPos, data));
if (result case .Ok(let len))
mPos += len; mPos += len;
writeCount += result; writeCount += len;
return writeCount; return writeCount;
} }

View file

@ -240,7 +240,7 @@ namespace System.IO
} }
} }
struct FileEnumerator : IEnumerator<FileFindEntry> struct FileEnumerator : IEnumerator<FileFindEntry>, IDisposable
{ {
String mSearchStr; String mSearchStr;
Platform.BfpFindFileData* mFindFileData; Platform.BfpFindFileData* mFindFileData;

View file

@ -15,6 +15,11 @@ namespace System.IO
mOwnsData = true; mOwnsData = true;
} }
public this(List<uint8> data)
{
mData = data;
}
public uint8* Ptr public uint8* Ptr
{ {
get get
@ -112,4 +117,100 @@ namespace System.IO
mData.RemoveRange(0, count); mData.RemoveRange(0, count);
} }
} }
class DynMemStreamSequential : Stream
{
List<uint8> mData ~ { if (mOwnsData) delete _; };
bool mOwnsData;
public this()
{
mData = new .();
mOwnsData = true;
}
public this(List<uint8> data)
{
mData = data;
}
public uint8* Ptr
{
get
{
return mData.Ptr;
}
}
public Span<uint8> Content
{
get
{
return mData;
}
}
public override int64 Position
{
get
{
return mData.Count;
}
set
{
Runtime.FatalError();
}
}
public override int64 Length
{
get
{
return mData.Count;
}
}
public override bool CanRead
{
get
{
return true;
}
}
public override bool CanWrite
{
get
{
return true;
}
}
public List<uint8> TakeOwnership()
{
Debug.Assert(mOwnsData);
mOwnsData = false;
return mData;
}
public override Result<int> TryRead(Span<uint8> data)
{
return .Err;
}
public override Result<int> TryWrite(Span<uint8> data)
{
let count = data.Length;
if (count == 0)
return .Ok(0);
Internal.MemCpy(mData.GrowUnitialized(count), data.Ptr, count);
return .Ok(count);
}
public override Result<void> Close()
{
return .Ok;
}
}
} }

View file

@ -23,7 +23,7 @@ namespace System.IO
case FileReadError(FileReadError); case FileReadError(FileReadError);
} }
class File static class File
{ {
public static Result<void, FileError> ReadAll(StringView path, List<uint8> outData) public static Result<void, FileError> ReadAll(StringView path, List<uint8> outData)
{ {
@ -49,7 +49,7 @@ namespace System.IO
public static Result<void> WriteAll(StringView path, Span<uint8> data, bool doAppend = false) public static Result<void> WriteAll(StringView path, Span<uint8> data, bool doAppend = false)
{ {
FileStream fs = scope FileStream(); UnbufferedFileStream fs = scope UnbufferedFileStream();
var result = fs.Open(path, doAppend ? .Append : .Create, .Write); var result = fs.Open(path, doAppend ? .Append : .Create, .Write);
if (result case .Err) if (result case .Err)
return .Err; return .Err;
@ -76,7 +76,7 @@ namespace System.IO
public static Result<void> WriteAllText(StringView path, StringView text, bool doAppend = false) public static Result<void> WriteAllText(StringView path, StringView text, bool doAppend = false)
{ {
FileStream fs = scope FileStream(); UnbufferedFileStream fs = scope UnbufferedFileStream();
var result = fs.Open(path, doAppend ? .Append : .Create, .Write); var result = fs.Open(path, doAppend ? .Append : .Create, .Write);
if (result case .Err) if (result case .Err)
return .Err; return .Err;
@ -87,7 +87,7 @@ namespace System.IO
public static Result<void> WriteAllText(StringView path, StringView text, Encoding encoding) public static Result<void> WriteAllText(StringView path, StringView text, Encoding encoding)
{ {
FileStream fs = scope FileStream(); UnbufferedFileStream fs = scope UnbufferedFileStream();
int len = encoding.GetEncodedSize(text); int len = encoding.GetEncodedSize(text);
uint8* data = new uint8[len]*; uint8* data = new uint8[len]*;

View file

@ -17,16 +17,16 @@ namespace System.IO
/// Opens an existing file. Fails if the file does not exist. /// Opens an existing file. Fails if the file does not exist.
Open = 3, Open = 3,
// Opens the file if it exists. Otherwise, creates a new file. /// Opens the file if it exists. Otherwise, creates a new file.
OpenOrCreate = 4, OpenOrCreate = 4,
// Opens an existing file. Once opened, the file is truncated so that its /// Opens an existing file. Once opened, the file is truncated so that its
// size is zero bytes. The calling process must open the file with at least /// size is zero bytes. The calling process must open the file with at least
// WRITE access. Fails if the file does not exist. /// WRITE access. Fails if the file does not exist.
Truncate = 5, Truncate = 5,
// Opens the file if it exists and seeks to the end. Otherwise, /// Opens the file if it exists and seeks to the end. Otherwise,
// creates a new file. /// creates a new file.
Append = 6, Append = 6,
} }
} }

View file

@ -29,6 +29,16 @@ namespace System.IO
} }
} }
public int Handle
{
get
{
if (mBfpFile == null)
return 0;
return Platform.BfpFile_GetSystemHandle(mBfpFile);
}
}
public ~this() public ~this()
{ {
Delete(); Delete();
@ -165,12 +175,13 @@ namespace System.IO
createKind = .CreateIfNotExists; createKind = .CreateIfNotExists;
case .Create: case .Create:
createKind = .CreateAlways; createKind = .CreateAlways;
createFlags |= .Truncate;
case .Open: case .Open:
createKind = .OpenExisting; createKind = .OpenExisting;
case .OpenOrCreate: case .OpenOrCreate:
createKind = .CreateAlways; createKind = .OpenAlways;
case .Truncate: case .Truncate:
createKind = .CreateAlways; createKind = .OpenExisting;
createFlags |= .Truncate; createFlags |= .Truncate;
case .Append: case .Append:
createKind = .CreateAlways; createKind = .CreateAlways;
@ -225,6 +236,32 @@ namespace System.IO
return .Err; return .Err;
return .Ok; return .Ok;
} }
public override Result<void> SetLength(int64 length)
{
int64 pos = Position;
if (pos != length)
Seek(length);
Platform.BfpFileResult result = .Ok;
Platform.BfpFile_Truncate(mBfpFile, &result);
if (result != .Ok)
{
Seek(pos);
return .Err;
}
if (pos != length)
{
if (pos < length)
Seek(pos);
else
Seek(0, .FromEnd);
}
return .Ok;
}
} }
class BufferedFileStream : BufferedStream class BufferedFileStream : BufferedStream
@ -233,6 +270,32 @@ namespace System.IO
protected int64 mBfpFilePos; protected int64 mBfpFilePos;
FileAccess mFileAccess; FileAccess mFileAccess;
public int Handle
{
get
{
if (mBfpFile == null)
return 0;
return Platform.BfpFile_GetSystemHandle(mBfpFile);
}
}
public override bool CanRead
{
get
{
return mFileAccess.HasFlag(FileAccess.Read);
}
}
public override bool CanWrite
{
get
{
return mFileAccess.HasFlag(FileAccess.Write);
}
}
public this() public this()
{ {
@ -254,22 +317,6 @@ namespace System.IO
mFileAccess = access; mFileAccess = access;
} }
public override bool CanRead
{
get
{
return mFileAccess.HasFlag(FileAccess.Read);
}
}
public override bool CanWrite
{
get
{
return mFileAccess.HasFlag(FileAccess.Write);
}
}
public Result<void, FileOpenError> Create(StringView path, FileAccess access = .ReadWrite, FileShare share = .None, int bufferSize = 4096, FileOptions options = .None, SecurityAttributes* secAttrs = null) public Result<void, FileOpenError> Create(StringView path, FileAccess access = .ReadWrite, FileShare share = .None, int bufferSize = 4096, FileOptions options = .None, SecurityAttributes* secAttrs = null)
{ {
return Open(path, FileMode.Create, access, share, bufferSize, options, secAttrs); return Open(path, FileMode.Create, access, share, bufferSize, options, secAttrs);
@ -317,7 +364,7 @@ namespace System.IO
case .Open: case .Open:
createKind = .OpenExisting; createKind = .OpenExisting;
case .OpenOrCreate: case .OpenOrCreate:
createKind = .CreateAlways; createKind = .OpenAlways;
case .Truncate: case .Truncate:
createKind = .CreateAlways; createKind = .CreateAlways;
createFlags |= .Truncate; createFlags |= .Truncate;
@ -386,15 +433,20 @@ namespace System.IO
mUnderlyingLength = Platform.BfpFile_GetFileSize(mBfpFile); mUnderlyingLength = Platform.BfpFile_GetFileSize(mBfpFile);
} }
protected Result<void> SeekUnderlying(int64 offset, Platform.BfpFileSeekKind seekKind = .Absolute)
{
int64 newPos = Platform.BfpFile_Seek(mBfpFile, offset, seekKind);
Result<void> result = ((seekKind == .Absolute) && (newPos != offset)) ? .Err : .Ok;
if (result case .Ok)
mBfpFilePos = newPos;
return result;
}
protected override Result<int> TryReadUnderlying(int64 pos, Span<uint8> data) protected override Result<int> TryReadUnderlying(int64 pos, Span<uint8> data)
{ {
if (mBfpFilePos != pos) if (mBfpFilePos != pos)
{ Try!(SeekUnderlying(pos));
int64 newPos = Platform.BfpFile_Seek(mBfpFile, pos, .Absolute);
if (newPos != pos)
return .Err;
mBfpFilePos = pos;
}
Platform.BfpFileResult result = .Ok; Platform.BfpFileResult result = .Ok;
int numBytesRead = Platform.BfpFile_Read(mBfpFile, data.Ptr, data.Length, -1, &result); int numBytesRead = Platform.BfpFile_Read(mBfpFile, data.Ptr, data.Length, -1, &result);
if ((result != .Ok) && (result != .PartialData)) if ((result != .Ok) && (result != .PartialData))
@ -406,12 +458,8 @@ namespace System.IO
protected override Result<int> TryWriteUnderlying(int64 pos, Span<uint8> data) protected override Result<int> TryWriteUnderlying(int64 pos, Span<uint8> data)
{ {
if (mBfpFilePos != pos) if (mBfpFilePos != pos)
{ Try!(SeekUnderlying(pos));
int64 newPos = Platform.BfpFile_Seek(mBfpFile, pos, .Absolute);
if (newPos != pos)
return .Err;
mBfpFilePos = pos;
}
Platform.BfpFileResult result = .Ok; Platform.BfpFileResult result = .Ok;
int numBytesRead = Platform.BfpFile_Write(mBfpFile, data.Ptr, data.Length, -1, &result); int numBytesRead = Platform.BfpFile_Write(mBfpFile, data.Ptr, data.Length, -1, &result);
if ((result != .Ok) && (result != .PartialData)) if ((result != .Ok) && (result != .PartialData))
@ -423,12 +471,7 @@ namespace System.IO
public Result<int> TryRead(Span<uint8> data, int timeoutMS) public Result<int> TryRead(Span<uint8> data, int timeoutMS)
{ {
if (mBfpFilePos != mPos) if (mBfpFilePos != mPos)
{ Try!(SeekUnderlying(mPos));
int64 newPos = Platform.BfpFile_Seek(mBfpFile, mPos, .Absolute);
if (newPos != mPos)
return .Err;
mBfpFilePos = mPos;
}
Platform.BfpFileResult result = .Ok; Platform.BfpFileResult result = .Ok;
int numBytesRead = Platform.BfpFile_Read(mBfpFile, data.Ptr, data.Length, timeoutMS, &result); int numBytesRead = Platform.BfpFile_Read(mBfpFile, data.Ptr, data.Length, timeoutMS, &result);
@ -436,6 +479,40 @@ namespace System.IO
return .Err; return .Err;
return numBytesRead; return numBytesRead;
} }
public override Result<void> SetLength(int64 length)
{
Try!(Flush());
int64 pos = Position;
if (pos != length || pos != mBfpFilePos)
{
Try!(SeekUnderlying(length));
mPos = length;
}
Platform.BfpFileResult result = .Ok;
Platform.BfpFile_Truncate(mBfpFile, &result);
if (result != .Ok)
{
Try!(SeekUnderlying(pos));
return .Err;
}
mUnderlyingLength = length;
mPos = Math.Min(pos, Length);
if (pos != length)
{
if (pos < length)
Try!(SeekUnderlying(pos));
else
Try!(SeekUnderlying(0, .FromEnd));
}
return .Ok;
}
} }
class FileStream : BufferedFileStream class FileStream : BufferedFileStream

View file

@ -4,7 +4,7 @@ namespace System.IO
{ {
class MemoryStream : Stream class MemoryStream : Stream
{ {
List<uint8> mMemory = new List<uint8>() ~ delete _; List<uint8> mMemory ~ delete _;
int mPosition = 0; int mPosition = 0;
public override int64 Position public override int64 Position
@ -44,6 +44,16 @@ namespace System.IO
} }
} }
public this()
{
mMemory = new List<uint8>();
}
public this(List<uint8> memory)
{
mMemory = memory;
}
public override Result<int> TryRead(Span<uint8> data) public override Result<int> TryRead(Span<uint8> data)
{ {
let count = data.Length; let count = data.Length;

View file

@ -15,7 +15,7 @@ namespace System.IO
public const char8 DirectorySeparatorChar = '/'; public const char8 DirectorySeparatorChar = '/';
#endif //BF_PLATFORM_WINDOWS #endif //BF_PLATFORM_WINDOWS
// Platform specific alternate directory separator char8acter. // Platform specific alternate directory separator character.
// This is backslash ('\') on Unix, and slash ('/') on Windows // This is backslash ('\') on Unix, and slash ('/') on Windows
// and MacOS. // and MacOS.
// //
@ -25,7 +25,7 @@ namespace System.IO
public const char8 AltDirectorySeparatorChar = '\\'; public const char8 AltDirectorySeparatorChar = '\\';
#endif //BF_PLATFORM_WINDOWS #endif //BF_PLATFORM_WINDOWS
// Platform specific volume separator char8acter. This is colon (':') // Platform specific volume separator character. This is colon (':')
// on Windows and MacOS, and slash ('/') on Unix. This is mostly // on Windows and MacOS, and slash ('/') on Unix. This is mostly
// useful for parsing paths like "c:\windows" or "MacVolume:System Folder". // useful for parsing paths like "c:\windows" or "MacVolume:System Folder".
// //
@ -37,7 +37,7 @@ namespace System.IO
// Make this public sometime. // Make this public sometime.
// The max total path is 260, and the max individual component length is 255. // The max total path is 260, and the max individual component length is 255.
// For example, D:\<256 char8 file name> isn't legal, even though it's under 260 char8s. // For example, D:\<256 char file name> isn't legal, even though it's under 260 chars.
protected const int32 MaxPath = 260; protected const int32 MaxPath = 260;
private const int32 MaxDirectoryLength = 255; private const int32 MaxDirectoryLength = 255;
@ -297,7 +297,7 @@ namespace System.IO
return .Ok; return .Ok;
} }
public static void InternalCombine(String target, params String[] components) public static void InternalCombine(String target, params StringView[] components)
{ {
for (var component in components) for (var component in components)
{ {

View file

@ -97,25 +97,32 @@ namespace System.IO
} }
} }
//Read sized string from stream /// Read sized string from stream
public Result<void> ReadStrSized32(int64 size, String output) public Result<void> ReadStrSized32(int size, String output)
{ {
if (size <= 0) if (size < 0)
return .Err; return .Err;
for (int64 i = 0; i < size; i++) int prevLen = output.Length;
char8* buf = output.PrepareBuffer(size);
switch (TryRead(.((uint8*)buf, size)))
{ {
Result<char8> char = Read<char8>(); case .Ok(let readLen):
if (char == .Err) if (readLen < size)
return .Err; output.Length = prevLen + readLen;
output.Append(char);
}
return .Ok; return .Ok;
case .Err:
return .Err;
}
} }
//Reads null terminated ASCII string from the stream. Null terminator is read from stream but isn't appended to output string public Result<void> ReadStrSized32(String output)
{
int size = Try!(Read<int32>());
return ReadStrSized32(size, output);
}
/// Reads null terminated ASCII string from the stream. Null terminator is read from stream but isn't appended to output string
public Result<void> ReadStrC(String output) public Result<void> ReadStrC(String output)
{ {
Result<char8> char0; Result<char8> char0;
@ -197,6 +204,11 @@ namespace System.IO
return .Ok; return .Ok;
} }
public virtual Result<void> SetLength(int64 length)
{
return .Err;
}
public void Align(int alignSize) public void Align(int alignSize)
{ {
int64 pos = Length; int64 pos = Length;

View file

@ -256,7 +256,7 @@ namespace System.IO
{ {
char8 ch = tmpCharBuffer[i]; char8 ch = tmpCharBuffer[i];
// Note the following common line feed char8s: // Note the following common line feed chars:
// \n - UNIX \r\n - DOS \r - Mac // \n - UNIX \r\n - DOS \r - Mac
if (ch == '\r' || ch == '\n') if (ch == '\r' || ch == '\n')
{ {
@ -481,7 +481,7 @@ namespace System.IO
} }
while (mCharLen == 0); while (mCharLen == 0);
//Console.WriteLine("ReadBuffer called. char8s: "+char8Len); //Console.WriteLine("ReadBuffer called. chars: "+char8Len);
return mCharLen; return mCharLen;
} }
@ -522,7 +522,7 @@ namespace System.IO
repeat repeat
{ {
char8 ch = mCharBuffer[i]; char8 ch = mCharBuffer[i];
// Note the following common line feed char8s: // Note the following common line feed chars:
// \n - UNIX \r\n - DOS \r - Mac // \n - UNIX \r\n - DOS \r - Mac
if (ch == '\r' || ch == '\n') if (ch == '\r' || ch == '\n')
{ {

View file

@ -243,6 +243,7 @@ namespace System
} }
} }
[AlwaysInclude]
public static String[] CreateParamsArray() public static String[] CreateParamsArray()
{ {
char8* cmdLine = GetCommandLineArgs(); char8* cmdLine = GetCommandLineArgs();
@ -347,6 +348,7 @@ namespace System
return strVals; return strVals;
} }
[AlwaysInclude]
public static void DeleteStringArray(String[] arr) public static void DeleteStringArray(String[] arr)
{ {
for (var str in arr) for (var str in arr)

View file

@ -25,6 +25,8 @@ namespace System
private static float[7] sRoundPower10Single = .( private static float[7] sRoundPower10Single = .(
1E0f, 1E1f, 1E2f, 1E3f, 1E4f, 1E5f, 1E6f); 1E0f, 1E1f, 1E2f, 1E3f, 1E4f, 1E5f, 1E6f);
private static float sMachineEpsilonFloat = GetMachineEpsilonFloat();
public const double PI_d = 3.14159265358979323846; public const double PI_d = 3.14159265358979323846;
public const double E_d = 2.7182818284590452354; public const double E_d = 2.7182818284590452354;
public const float PI_f = 3.14159265358979323846f; public const float PI_f = 3.14159265358979323846f;
@ -48,6 +50,33 @@ namespace System
public static extern float Floor(float f); public static extern float Floor(float f);
public static extern double Floor(double d); public static extern double Floor(double d);
public static bool WithinEpsilon(float a, float b)
{
return Math.Abs(a - b) < sMachineEpsilonFloat;
}
/// <summary>
/// Find the current machine's Epsilon for the float data type.
/// (That is, the largest float, e, where e == 0.0f is true.)
/// </summary>
private static float GetMachineEpsilonFloat()
{
float machineEpsilon = 1.0f;
float comparison;
/* Keep halving the working value of machineEpsilon until we get a number that
* when added to 1.0f will still evaluate as equal to 1.0f.
*/
repeat
{
machineEpsilon *= 0.5f;
comparison = 1.0f + machineEpsilon;
}
while (comparison > 1.0f);
return machineEpsilon;
}
private static float InternalRound(float value, int32 digits, MidpointRounding mode) private static float InternalRound(float value, int32 digits, MidpointRounding mode)
{ {
if (Abs(value) < cSingleRoundLimit) if (Abs(value) < cSingleRoundLimit)
@ -476,5 +505,125 @@ namespace System
{ {
return ((val) + (align - 1)) & ~(align - 1); return ((val) + (align - 1)) & ~(align - 1);
} }
/// Interpolates between two values using a cubic equation.
/// @param name Source value.
/// @param name Source value.
/// @param name Weighting value.
/// @returns Interpolated value.
public static float SmoothStep(float value1, float value2, float amount)
{
/* It is expected that 0 < amount < 1.
* If amount < 0, return value1.
* If amount > 1, return value2.
*/
float result = Clamp(amount, 0f, 1f);
result = Hermite(value1, 0f, value2, 0f, result);
return result;
}
/// Performs a Hermite spline interpolation.
/// @param value1 Source position.
/// @param tangent1 Source tangent.
/// @param value2 Source position.
/// @param tangent2 Source tangent.
/// @param amount Weighting factor.
/// @returns The result of the Hermite spline interpolation.
public static float Hermite(
float value1,
float tangent1,
float value2,
float tangent2,
float amount
) {
/* All transformed to double not to lose precision
* Otherwise, for high numbers of param:amount the result is NaN instead
* of Infinity.
*/
double v1 = value1, v2 = value2, t1 = tangent1, t2 = tangent2, s = amount;
double result;
double sCubed = s * s * s;
double sSquared = s * s;
if (WithinEpsilon(amount, 0f))
{
result = value1;
}
else if (WithinEpsilon(amount, 1f))
{
result = value2;
}
else
{
result = (
((2 * v1 - 2 * v2 + t2 + t1) * sCubed) +
((3 * v2 - 3 * v1 - 2 * t1 - t2) * sSquared) +
(t1 * s) +
v1
);
}
return (float) result;
}
/// Returns the Cartesian coordinate for one axis of a point that is defined by a
/// given triangle and two normalized barycentric (areal) coordinates.
/// <param name="value1">
/// The coordinate on one axis of vertex 1 of the defining triangle.
/// </param>
/// <param name="value2">
/// The coordinate on the same axis of vertex 2 of the defining triangle.
/// </param>
/// <param name="value3">
/// The coordinate on the same axis of vertex 3 of the defining triangle.
/// </param>
/// <param name="amount1">
/// The normalized barycentric (areal) coordinate b2, equal to the weighting factor
/// for vertex 2, the coordinate of which is specified in value2.
/// </param>
/// @param amount2
/// The normalized barycentric (areal) coordinate b3, equal to the weighting factor
/// for vertex 3, the coordinate of which is specified in value3.
/// </param>
/// @returns Cartesian coordinate of the specified point with respect to the axis being used.
public static float Barycentric(
float value1,
float value2,
float value3,
float amount1,
float amount2
) {
return value1 + (value2 - value1) * amount1 + (value3 - value1) * amount2;
}
/// Performs a Catmull-Rom interpolation using the specified positions.
/// @param value1 The first position in the interpolation.
/// @param value2">The second position in the interpolation.
/// @param value3">The third position in the interpolation.
/// @param value4">The fourth position in the interpolation.
/// @param name="amount">Weighting factor.
/// @returns A position that is the result of the Catmull-Rom interpolation.
public static float CatmullRom(
float value1,
float value2,
float value3,
float value4,
float amount
) {
/* Using formula from http://www.mvps.org/directx/articles/catmull/
* Internally using doubles not to lose precision.
*/
double amountSquared = amount * amount;
double amountCubed = amountSquared * amount;
return (float) (
0.5 *
(
((2.0 * value2 + (value3 - value1) * amount) +
((2.0 * value1 - 5.0 * value2 + 4.0 * value3 - value4) * amountSquared) +
(3.0 * value2 - value1 - 3.0 * value3 + value4) * amountCubed)
)
);
}
} }
} }

View file

@ -5,6 +5,7 @@ namespace System.Net
{ {
class Socket class Socket
{ {
const uint16 WINSOCK_VERSION = 0x0202;
const int32 WSAENETRESET = 10052; const int32 WSAENETRESET = 10052;
const int32 WSAECONNABORTED = 10053; const int32 WSAECONNABORTED = 10053;
const int32 WSAECONNRESET = 10054; const int32 WSAECONNRESET = 10054;
@ -170,11 +171,21 @@ namespace System.Net
[Import("wsock32.lib"), CLink, CallingConvention(.Stdcall)] [Import("wsock32.lib"), CLink, CallingConvention(.Stdcall)]
static extern int32 WSAStartup(uint16 versionRequired, WSAData* wsaData); static extern int32 WSAStartup(uint16 versionRequired, WSAData* wsaData);
[Import("wsock32.lib"), CLink, CallingConvention(.Stdcall)]
static extern int32 WSACleanup();
[Import("wsock32.lib"), CLink, CallingConvention(.Stdcall)] [Import("wsock32.lib"), CLink, CallingConvention(.Stdcall)]
static extern int32 WSAGetLastError(); static extern int32 WSAGetLastError();
#elif BF_PLATFORM_LINUX
[LinkName("__errno_location")]
static extern int32* _errno();
#elif BF_PLATFORM_MACOS
[LinkName("__error")]
static extern int32* _errno();
#else #else
[CLink] [CLink]
static int32 errno; static int32 errno;
static int32* _errno() => &errno;
#endif #endif
[CLink, CallingConvention(.Stdcall)] [CLink, CallingConvention(.Stdcall)]
@ -230,11 +241,22 @@ namespace System.Net
#endif #endif
} }
public static void Init() public static int32 Init(uint16 versionRequired = WINSOCK_VERSION)
{ {
#if BF_PLATFORM_WINDOWS #if BF_PLATFORM_WINDOWS
WSAData wsaData = default; WSAData wsaData = default;
WSAStartup(0x202, &wsaData); return WSAStartup(versionRequired, &wsaData);
#else
return 0;
#endif
}
public static int32 Uninit()
{
#if BF_PLATFORM_WINDOWS
return WSACleanup();
#else
return 0;
#endif #endif
} }
@ -243,7 +265,7 @@ namespace System.Net
#if BF_PLATFORM_WINDOWS #if BF_PLATFORM_WINDOWS
return WSAGetLastError(); return WSAGetLastError();
#else #else
return errno; return *_errno();
#endif #endif
} }

View file

@ -2675,7 +2675,7 @@ namespace System
return; return;
int i = sb.Length + (end - start); int i = sb.Length + (end - start);
sb.Length = i; sb.PrepareBuffer(i);
var end; var end;
var start; var start;

View file

@ -271,6 +271,7 @@ namespace System
CreateAlways, CreateAlways,
CreateIfNotExists, CreateIfNotExists,
OpenExisting, OpenExisting,
OpenAlways,
}; };
public enum BfpFileCreateFlags : int32 public enum BfpFileCreateFlags : int32
@ -337,6 +338,8 @@ namespace System
[CallingConvention(.Stdcall), CLink] [CallingConvention(.Stdcall), CLink]
public static extern BfpFile* BfpFile_GetStd(BfpFileStdKind kind, BfpFileResult* outResult); public static extern BfpFile* BfpFile_GetStd(BfpFileStdKind kind, BfpFileResult* outResult);
[CallingConvention(.Stdcall), CLink] [CallingConvention(.Stdcall), CLink]
public static extern int BfpFile_GetSystemHandle(BfpFile* file);
[CallingConvention(.Stdcall), CLink]
public static extern void BfpFile_Release(BfpFile* file); public static extern void BfpFile_Release(BfpFile* file);
[CallingConvention(.Stdcall), CLink] [CallingConvention(.Stdcall), CLink]
public static extern int BfpFile_Write(BfpFile* file, void* buffer, int size, int timeoutMS, BfpFileResult* outResult); public static extern int BfpFile_Write(BfpFile* file, void* buffer, int size, int timeoutMS, BfpFileResult* outResult);
@ -349,7 +352,7 @@ namespace System
[CallingConvention(.Stdcall), CLink] [CallingConvention(.Stdcall), CLink]
public static extern int64 BfpFile_Seek(BfpFile* file, int64 offset, BfpFileSeekKind seekKind); public static extern int64 BfpFile_Seek(BfpFile* file, int64 offset, BfpFileSeekKind seekKind);
[CallingConvention(.Stdcall), CLink] [CallingConvention(.Stdcall), CLink]
public static extern void BfpFile_Truncate(BfpFile* file); public static extern void BfpFile_Truncate(BfpFile* file, BfpFileResult* outResult);
[CallingConvention(.Stdcall), CLink] [CallingConvention(.Stdcall), CLink]
public static extern BfpTimeStamp BfpFile_GetTime_LastWrite(char8* path); public static extern BfpTimeStamp BfpFile_GetTime_LastWrite(char8* path);
[CallingConvention(.Stdcall), CLink] [CallingConvention(.Stdcall), CLink]
@ -410,7 +413,8 @@ namespace System
AppData_LocalLow, AppData_LocalLow,
AppData_Roaming, AppData_Roaming,
Programs, Programs,
Programs_Common Programs_Common,
Documents
} }
public static Result<void, Platform.Result> GetStrHelper(String outStr, delegate void (char8* outPtr, int32* outSize, Result* outResult) func) public static Result<void, Platform.Result> GetStrHelper(String outStr, delegate void (char8* outPtr, int32* outSize, Result* outResult) func)

View file

@ -0,0 +1,468 @@
using System.Collections;
using System.Diagnostics;
namespace System
{
interface RangeExpression
{
}
enum Index
{
case FromFront(int offset);
case FromEnd(int offset);
public override void ToString(String strBuffer)
{
switch (this)
{
case .FromFront(let offset):
offset.ToString(strBuffer);
case .FromEnd(let offset):
strBuffer.Append('^');
offset.ToString(strBuffer);
}
}
}
struct Range : RangeExpression, IEnumerable<int>
{
protected int mStart;
protected int mEnd;
public this()
{
mStart = 0;
mEnd = 0;
}
[Inline]
public this(int start, int end)
{
Debug.Assert(end >= start);
mStart = start;
mEnd = end;
}
public int Length
{
[Inline]
get
{
return mEnd - mStart;
}
[Inline]
set mut
{
mEnd = mStart + value;
}
}
public int Start
{
[Inline]
get
{
return mStart;
}
[Inline]
set mut
{
mStart = value;
}
}
public int End
{
[Inline]
get
{
return mEnd;
}
set mut
{
mEnd = value;
}
}
public bool IsEmpty
{
[Inline]
get
{
return mEnd == mStart;
}
}
public ReverseEnumerator Reversed
{
[Inline]
get
{
return ReverseEnumerator(mEnd - 1, mStart);
}
}
public bool Contains(int idx)
{
return (idx >= mStart) && (idx < mEnd);
}
public bool Contains(Range val)
{
return (val.[Friend]mStart >= mStart) && (val.[Friend]mEnd <= mEnd);
}
public bool Contains(ClosedRange val)
{
return (val.[Friend]mStart >= mStart) && (val.[Friend]mEnd <= mEnd - 1);
}
public void Clear() mut
{
mStart = 0;
mEnd = 0;
}
public static operator IndexRange(Range list)
{
return .(.FromFront(list.mStart), .FromFront(list.mEnd), false);
}
[Inline]
public Enumerator GetEnumerator()
{
return Enumerator(this);
}
public override void ToString(String strBuffer)
{
strBuffer.AppendF($"{mStart}..<{mEnd}");
}
public struct Enumerator : IEnumerator<int>
{
private int mEnd;
private int mIndex;
[Inline]
public this(Range range)
{
mIndex = range.mStart - 1;
mEnd = range.mEnd;
}
public void Dispose()
{
}
public ref int Index
{
get mut
{
return ref mIndex;
}
}
public int End => mEnd;
[Inline]
public Result<int> GetNext() mut
{
if (mIndex + 1 >= mEnd)
return .Err;
return ++mIndex;
}
}
public struct ReverseEnumerator : IEnumerator<int>
{
private int mEnd;
private int mIndex;
[Inline]
public this(int start, int end)
{
mIndex = start + 1;
mEnd = end;
}
public void Dispose()
{
}
public ref int Index
{
get mut
{
return ref mIndex;
}
}
public int End => mEnd;
[Inline]
public Result<int> GetNext() mut
{
if (mIndex <= mEnd)
return .Err;
return --mIndex;
}
}
}
struct IndexRange : RangeExpression
{
protected Index mStart;
protected Index mEnd;
protected bool mIsClosed;
public this()
{
this = default;
}
[Inline]
public this(Index start, Index end, bool isClosed=true)
{
mStart = start;
mEnd = end;
mIsClosed = isClosed;
}
[Inline]
public this(int start, Index end, bool isClosed=true)
{
mStart = .FromFront(start);
mEnd = end;
mIsClosed = isClosed;
}
[Inline]
public this(Index start, int end, bool isClosed=true)
{
mStart = start;
mEnd = .FromFront(end);
mIsClosed = isClosed;
}
[Inline]
public this(int start, int end, bool isClosed=true)
{
mStart = .FromFront(start);
mEnd = .FromFront(end);
mIsClosed = isClosed;
}
public Index Start
{
[Inline]
get
{
return mStart;
}
[Inline]
set mut
{
mStart = value;
}
}
public Index End
{
[Inline]
get
{
return mEnd;
}
set mut
{
mEnd = value;
}
}
public bool IsClosed
{
[Inline]
get
{
return mIsClosed;
}
set mut
{
mIsClosed = value;
}
}
public override void ToString(String strBuffer)
{
mStart.ToString(strBuffer);
if (mIsClosed)
strBuffer.Append("...");
else
strBuffer.Append("..<");
mEnd.ToString(strBuffer);
}
}
struct ClosedRange : RangeExpression, IEnumerable<int>
{
protected int mStart;
protected int mEnd;
public this()
{
mStart = 0;
mEnd = 0;
}
[Inline]
public this(int start, int end)
{
Debug.Assert(end >= start);
mStart = start;
mEnd = end;
}
public int Length
{
[Inline]
get
{
return mEnd - mStart;
}
[Inline]
set mut
{
mEnd = mStart + value;
}
}
public int Start
{
[Inline]
get
{
return mStart;
}
[Inline]
set mut
{
mStart = value;
}
}
public int End
{
[Inline]
get
{
return mEnd;
}
set mut
{
mEnd = value;
}
}
public bool IsEmpty
{
[Inline]
get
{
return mEnd == mStart;
}
}
public Range.ReverseEnumerator Reversed
{
[Inline]
get
{
return Range.ReverseEnumerator(mEnd, mStart);
}
}
public bool Contains(int idx)
{
return (idx >= mStart) && (idx <= mEnd);
}
public bool Contains(Range val)
{
return (val.[Friend]mStart >= mStart) && (val.[Friend]mEnd - 1 <= mEnd);
}
public bool Contains(ClosedRange val)
{
return (val.[Friend]mStart >= mStart) && (val.[Friend]mEnd <= mEnd);
}
public void Clear() mut
{
mStart = 0;
mEnd = 0;
}
public static operator IndexRange(ClosedRange list)
{
return .(.FromFront(list.mStart), .FromFront(list.mEnd), true);
}
[Inline]
public Enumerator GetEnumerator()
{
return Enumerator(this);
}
public override void ToString(String strBuffer)
{
strBuffer.AppendF($"{mStart}...{mEnd}");
}
public struct Enumerator : IEnumerator<int>
{
private int mEnd;
private int mIndex;
[Inline]
public this(ClosedRange range)
{
mIndex = range.mStart - 1;
mEnd = range.mEnd;
}
public void Dispose()
{
}
public ref int Index
{
get mut
{
return ref mIndex;
}
}
public int End => mEnd;
[Inline]
public Result<int> GetNext() mut
{
if (mIndex >= mEnd)
return .Err;
return ++mIndex;
}
}
}
}

View file

@ -92,6 +92,9 @@ namespace System.Reflection
.Double: .Double:
let attrData = Decode!<int64>(data); let attrData = Decode!<int64>(data);
args[argIdx] = scope:AttrBlock box attrData; args[argIdx] = scope:AttrBlock box attrData;
case (TypeCode)51: //BfConstType_TypeOf
let argTypeId = Decode!<int32>(data);
args[argIdx] = Type.[Friend]GetType((.)argTypeId);
case (TypeCode)255: case (TypeCode)255:
let stringId = Decode!<int32>(data); let stringId = Decode!<int32>(data);
String str = String.[Friend]sIdStringLiterals[stringId]; String str = String.[Friend]sIdStringLiterals[stringId];

View file

@ -29,8 +29,8 @@ namespace System.Reflection
get get
{ {
if (Compiler.IsComptime) if (Compiler.IsComptime)
Type.[Friend]Comptime_Method_GetName(mNativeMethodInstance); return Type.[Friend]Comptime_Method_GetName(mNativeMethodInstance);
return ""; return "?";
} }
} }
public int ParamCount public int ParamCount

View file

@ -20,53 +20,13 @@ namespace System.Reflection
mFieldData = fieldData; mFieldData = fieldData;
} }
public int32 MemberOffset public TypeInstance DeclaringType => mTypeInstance;
{ public int32 MemberOffset => (int32)mFieldData.mData;
get public Type FieldType => Type.[Friend]GetType(mFieldData.mFieldTypeId);
{ public bool IsConst => mFieldData.mFlags.HasFlag(.Const);
return (int32)mFieldData.mData; public bool IsStatic => mFieldData.mFlags.HasFlag(.Static);
} public bool IsInstanceField => !mFieldData.mFlags.HasFlag(.Static) && !mFieldData.mFlags.HasFlag(.Const);
} public StringView Name => mFieldData.mName;
public Type FieldType
{
get
{
return Type.[Friend]GetType(mFieldData.mFieldTypeId);
}
}
public bool IsConst
{
get
{
return mFieldData.mFlags.HasFlag(.Const);
}
}
public bool IsStatic
{
get
{
return mFieldData.mFlags.HasFlag(.Static);
}
}
public bool IsInstanceField
{
get
{
return !mFieldData.mFlags.HasFlag(.Static) && !mFieldData.mFlags.HasFlag(.Const);
}
}
public StringView Name
{
get
{
return mFieldData.mName;
}
}
public Result<void, Error> SetValue(Object obj, Object value) public Result<void, Error> SetValue(Object obj, Object value)
{ {
@ -525,7 +485,15 @@ namespace System.Reflection
{ {
mIdx++; mIdx++;
if (mIdx == mTypeInstance.[Friend]mFieldDataCount) if (mIdx == mTypeInstance.[Friend]mFieldDataCount)
{
if (mBindingFlags.HasFlag(.DeclaredOnly))
return false; return false;
if (mTypeInstance.[Friend]mBaseType == 0)
return false;
mTypeInstance = Type.[Friend]GetType(mTypeInstance.[Friend]mBaseType) as TypeInstance;
mIdx = -1;
continue;
}
var fieldData = &mTypeInstance.[Friend]mFieldDataPtr[mIdx]; var fieldData = &mTypeInstance.[Friend]mFieldDataPtr[mIdx];
bool matches = (mBindingFlags.HasFlag(BindingFlags.Static) && (fieldData.mFlags.HasFlag(FieldFlags.Static))); bool matches = (mBindingFlags.HasFlag(BindingFlags.Static) && (fieldData.mFlags.HasFlag(FieldFlags.Static)));
matches |= (mBindingFlags.HasFlag(BindingFlags.Instance) && (!fieldData.mFlags.HasFlag(FieldFlags.Static))); matches |= (mBindingFlags.HasFlag(BindingFlags.Instance) && (!fieldData.mFlags.HasFlag(FieldFlags.Static)));

View file

@ -18,6 +18,7 @@ namespace System.Reflection
mMethodData = methodData; mMethodData = methodData;
} }
public TypeInstance DeclaringType => mTypeInstance;
public bool IsInitialized => mMethodData != null; public bool IsInitialized => mMethodData != null;
public StringView Name => mMethodData.[Friend]mName; public StringView Name => mMethodData.[Friend]mName;
public int ParamCount => mMethodData.[Friend]mParamCount; public int ParamCount => mMethodData.[Friend]mParamCount;
@ -37,11 +38,22 @@ namespace System.Reflection
return mMethodData.mParamData[paramIdx].mName; return mMethodData.mParamData[paramIdx].mName;
} }
public Result<T> GetParamCustomAttribute<T>(int paramIdx) where T : Attribute
{
Debug.Assert((uint)paramIdx < (uint)mMethodData.mParamCount);
return mTypeInstance.[Friend]GetCustomAttribute<T>(mMethodData.mParamData[paramIdx].mCustomAttributesIdx);
}
public Result<T> GetCustomAttribute<T>() where T : Attribute public Result<T> GetCustomAttribute<T>() where T : Attribute
{ {
return mTypeInstance.[Friend]GetCustomAttribute<T>(mMethodData.mCustomAttributesIdx); return mTypeInstance.[Friend]GetCustomAttribute<T>(mMethodData.mCustomAttributesIdx);
} }
public Result<T> GetReturnCustomAttribute<T>() where T : Attribute
{
return mTypeInstance.[Friend]GetCustomAttribute<T>(mMethodData.mReturnCustomAttributesIdx);
}
public enum CallError public enum CallError
{ {
case None; case None;
@ -777,7 +789,15 @@ namespace System.Reflection
{ {
mIdx++; mIdx++;
if (mIdx == mTypeInstance.[Friend]mMethodDataCount) if (mIdx == mTypeInstance.[Friend]mMethodDataCount)
{
if (mBindingFlags.HasFlag(.DeclaredOnly))
return false; return false;
if (mTypeInstance.[Friend]mBaseType == 0)
return false;
mTypeInstance = Type.[Friend]GetType(mTypeInstance.[Friend]mBaseType) as TypeInstance;
mIdx = -1;
continue;
}
var methodData = &mTypeInstance.[Friend]mMethodDataPtr[mIdx]; var methodData = &mTypeInstance.[Friend]mMethodDataPtr[mIdx];
bool matches = (mBindingFlags.HasFlag(BindingFlags.Static) && (methodData.mFlags.HasFlag(.Static))); bool matches = (mBindingFlags.HasFlag(BindingFlags.Static) && (methodData.mFlags.HasFlag(.Static)));
matches |= (mBindingFlags.HasFlag(BindingFlags.Instance) && (!methodData.mFlags.HasFlag(.Static))); matches |= (mBindingFlags.HasFlag(BindingFlags.Instance) && (!methodData.mFlags.HasFlag(.Static)));

View file

@ -41,6 +41,26 @@ namespace System
return .Ok(matched); return .Ok(matched);
} }
[Comptime]
public virtual Result<ComptimeMethodInfo, MethodError> GetMethod(StringView methodName, BindingFlags bindingFlags = cDefaultLookup)
{
ComptimeMethodInfo matched = default;
for (let methodInfo in ComptimeMethodInfo.Enumerator(this as TypeInstance, bindingFlags))
{
if (methodInfo.Name == methodName)
{
if (matched.mNativeMethodInstance != 0)
return .Err(.MultipleResults);
else
matched = methodInfo;
}
}
if (matched.mNativeMethodInstance == 0)
return .Err(.NoResults);
return .Ok(matched);
}
public virtual Result<MethodInfo, MethodError> GetMethod(int methodIdx) public virtual Result<MethodInfo, MethodError> GetMethod(int methodIdx)
{ {
return .Err(.NoResults); return .Err(.NoResults);
@ -123,7 +143,10 @@ namespace System.Reflection
let objType = typeof(Object) as TypeInstance; let objType = typeof(Object) as TypeInstance;
#if BF_ENABLE_OBJECT_DEBUG_FLAGS #if BF_ENABLE_OBJECT_DEBUG_FLAGS
obj = Internal.Dbg_ObjectAlloc(mTypeClassVData, mInstSize, mInstAlign, 1); int32 stackCount = Compiler.Options.AllocStackCount;
if (mAllocStackCountOverride != 0)
stackCount = mAllocStackCountOverride;
obj = Internal.Dbg_ObjectAlloc(mTypeClassVData, mInstSize, mInstAlign, stackCount);
#else #else
void* mem = new [Align(16)] uint8[mInstSize]* (?); void* mem = new [Align(16)] uint8[mInstSize]* (?);
obj = Internal.UnsafeCastToObject(mem); obj = Internal.UnsafeCastToObject(mem);

View file

@ -20,22 +20,26 @@ namespace System
public T Value public T Value
{ {
[Inline]
get get
{ {
return Unwrap(); return Unwrap();
} }
} }
[Inline]
public static implicit operator Result<T>(T value) public static implicit operator Result<T>(T value)
{ {
return .Ok(value); return .Ok(value);
} }
[Inline]
public static implicit operator T(Result<T> result) public static implicit operator T(Result<T> result)
{ {
return result.Unwrap(); return result.Unwrap();
} }
[Inline]
public void IgnoreError() public void IgnoreError()
{ {
} }

View file

@ -5,8 +5,8 @@ using System.Threading;
namespace System namespace System
{ {
[StaticInitPriority(100)] [StaticInitPriority(101)]
class Runtime static class Runtime
{ {
const int32 cVersion = 8; const int32 cVersion = 8;
@ -102,7 +102,7 @@ namespace System
function void* (int size) mAlloc; function void* (int size) mAlloc;
function void (void* ptr) mFree; function void (void* ptr) mFree;
function void (Object obj) mObject_Delete; function void (Object obj) mObject_Delete;
function void (Object obj, String str) mObject_ToString; void* mUnused0;
function Type (Object obj) mObject_GetType; function Type (Object obj) mObject_GetType;
function void (Object obj) mObject_GCMarkMembers; function void (Object obj) mObject_GCMarkMembers;
function Object (Object obj, int32 typeId) mObject_DynamicCastToTypeId; function Object (Object obj, int32 typeId) mObject_DynamicCastToTypeId;
@ -141,13 +141,6 @@ namespace System
delete obj; delete obj;
} }
static void Object_ToString(Object obj, String str)
{
#if BF_DBG_RUNTIME
obj.ToString(str);
#endif
}
static Type Object_GetType(Object obj) static Type Object_GetType(Object obj)
{ {
#if BF_DBG_RUNTIME #if BF_DBG_RUNTIME
@ -241,7 +234,6 @@ namespace System
mAlloc = => Alloc; mAlloc = => Alloc;
mFree = => Free; mFree = => Free;
mObject_Delete = => Object_Delete; mObject_Delete = => Object_Delete;
mObject_ToString = => Object_ToString;
mObject_GetType = => Object_GetType; mObject_GetType = => Object_GetType;
mObject_GCMarkMembers = => Object_GCMarkMembers; mObject_GCMarkMembers = => Object_GCMarkMembers;
mObject_DynamicCastToTypeId = => Object_DynamicCastToTypeId; mObject_DynamicCastToTypeId = => Object_DynamicCastToTypeId;

View file

@ -1,5 +1,35 @@
namespace System.Security.Cryptography namespace System.Security.Cryptography
{ {
struct HashEncode
{
// Only 63 chars - skip zero
const char8[?] cHash64bToChar = .( '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', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '_' );
public static void HashEncode64(uint64 val, String outStr)
{
var val;
if ((int64)val < 0)
{
uint64 flippedNum = (uint64)-(int64)val;
// Only flip if the encoded result would actually be shorter
if (flippedNum <= 0x00FFFFFFFFFFFFFFL)
{
val = flippedNum;
outStr.Append('_');
}
}
for (int i = 0; i < 10; i++)
{
int charIdx = (int)((val >> (i * 6)) & 0x3F) - 1;
if (charIdx != -1)
outStr.Append(cHash64bToChar[charIdx]);
}
}
}
struct MD5Hash struct MD5Hash
{ {
public uint8[16] mHash; public uint8[16] mHash;
@ -50,6 +80,14 @@ namespace System.Security.Cryptography
val.ToString(strBuffer, "X2", null); val.ToString(strBuffer, "X2", null);
} }
} }
public void Encode(String outStr)
{
#unwarn
HashEncode.HashEncode64(((uint64*)&mHash)[0], outStr);
#unwarn
HashEncode.HashEncode64(((uint64*)&mHash)[1], outStr);
}
} }
class MD5 class MD5

View file

@ -16,18 +16,35 @@ namespace System
public this(T[] array) public this(T[] array)
{ {
if (array == null)
{
this = default;
return;
}
mPtr = &array.[Friend]GetRef(0); mPtr = &array.[Friend]GetRef(0);
mLength = array.[Friend]mLength; mLength = array.[Friend]mLength;
} }
public this(T[] array, int index) public this(T[] array, int index)
{ {
if (array == null)
{
Debug.Assert(index == 0);
this = default;
return;
}
mPtr = &array[index]; mPtr = &array[index];
mLength = array.[Friend]mLength - index; mLength = array.[Friend]mLength - index;
} }
public this(T[] array, int index, int length) public this(T[] array, int index, int length)
{ {
if (array == null)
{
Debug.Assert(index == 0 && length == 0);
this = default;
return;
}
if (length == 0) if (length == 0)
mPtr = null; mPtr = null;
else else
@ -110,13 +127,95 @@ namespace System
public ref T this[int index] public ref T this[int index]
{ {
[Inline] [Checked]
get
{
Runtime.Assert((uint)index < (uint)mLength);
return ref mPtr[index];
}
[Unchecked, Inline]
get get
{ {
return ref mPtr[index]; return ref mPtr[index];
} }
} }
public ref T this[Index index]
{
[Checked]
get
{
int idx;
switch (index)
{
case .FromFront(let offset): idx = offset;
case .FromEnd(let offset): idx = mLength - offset;
}
Runtime.Assert((uint)idx < (uint)mLength);
return ref mPtr[idx];
}
[Unchecked, Inline]
get
{
int idx;
switch (index)
{
case .FromFront(let offset): idx = offset;
case .FromEnd(let offset): idx = mLength - offset;
}
return ref mPtr[idx];
}
}
public Span<T> this[IndexRange range]
{
#if !DEBUG
[Inline]
#endif
get
{
T* start;
switch (range.[Friend]mStart)
{
case .FromFront(let offset):
Debug.Assert((uint)offset <= (uint)mLength);
start = mPtr + offset;
case .FromEnd(let offset):
Debug.Assert((uint)offset <= (uint)mLength);
start = mPtr + mLength - offset;
}
T* end;
if (range.[Friend]mIsClosed)
{
switch (range.[Friend]mEnd)
{
case .FromFront(let offset):
Debug.Assert((uint)offset < (uint)mLength);
end = mPtr + offset + 1;
case .FromEnd(let offset):
Debug.Assert((uint)(offset - 1) <= (uint)mLength);
end = mPtr + mLength - offset + 1;
}
}
else
{
switch (range.[Friend]mEnd)
{
case .FromFront(let offset):
Debug.Assert((uint)offset <= (uint)mLength);
end = mPtr + offset;
case .FromEnd(let offset):
Debug.Assert((uint)offset <= (uint)mLength);
end = mPtr + mLength - offset;
}
}
return .(start, end - start);
}
}
public Span<T> Slice(int index) public Span<T> Slice(int index)
{ {
Debug.Assert((uint)index <= (uint)mLength); Debug.Assert((uint)index <= (uint)mLength);
@ -200,6 +299,8 @@ namespace System
return Enumerator(this); return Enumerator(this);
} }
public ReverseEnumerator Reversed => ReverseEnumerator(this);
public override void ToString(String strBuffer) public override void ToString(String strBuffer)
{ {
strBuffer.Append("("); strBuffer.Append("(");
@ -281,6 +382,95 @@ namespace System
} }
public Result<T> GetNext() mut
{
if (!MoveNext())
return .Err;
return Current;
}
public Result<T*> GetNextRef() mut
{
if (!MoveNext())
return .Err;
return &CurrentRef;
}
}
public struct ReverseEnumerator : IEnumerator<T>, IRefEnumerator<T*>
{
private Span<T> mList;
private int mIndex;
private T* mCurrent;
public this(Span<T> list)
{
mList = list;
mIndex = list.mLength - 1;
mCurrent = null;
}
public void Dispose()
{
}
public bool MoveNext() mut
{
if (mIndex >= 0)
{
mCurrent = &mList.mPtr[mIndex];
mIndex--;
return true;
}
return MoveNextRare();
}
private bool MoveNextRare() mut
{
mIndex = mList.mLength + 1;
mCurrent = null;
return false;
}
public T Current
{
get
{
return *mCurrent;
}
}
public ref T CurrentRef
{
get
{
return ref *mCurrent;
}
}
public int Index
{
get
{
return mIndex + 1;
}
}
public int Length
{
get
{
return mList.mLength;
}
}
public void Reset() mut
{
mIndex = 0;
mCurrent = null;
}
public Result<T> GetNext() mut public Result<T> GetNext() mut
{ {
if (!MoveNext()) if (!MoveNext())

View file

@ -329,7 +329,7 @@ namespace System
set set
{ {
Debug.Assert((uint)mLength <= (uint)value); Debug.Assert((uint)value <= (uint)mLength);
mLength = (int_strsize)value; mLength = (int_strsize)value;
} }
} }
@ -1010,17 +1010,95 @@ namespace System
public ref char8 this[int index] public ref char8 this[int index]
{ {
[Checked]
get get
{ {
Debug.Assert((uint)index < (uint)mLength); Debug.Assert((uint)index < (uint)mLength);
return ref Ptr[index]; return ref Ptr[index];
} }
[Unchecked, Inline]
get
{
return ref Ptr[index];
}
[Checked]
set set
{ {
Debug.Assert((uint)index < (uint)mLength); Debug.Assert((uint)index < (uint)mLength);
Ptr[index] = value; Ptr[index] = value;
} }
[Unchecked, Inline]
set
{
Ptr[index] = value;
}
}
public ref char8 this[Index index]
{
[Checked]
get
{
int idx;
switch (index)
{
case .FromFront(let offset): idx = offset;
case .FromEnd(let offset): idx = mLength - offset;
}
Debug.Assert((uint)idx < (uint)mLength);
return ref Ptr[idx];
}
[Unchecked, Inline]
get
{
int idx;
switch (index)
{
case .FromFront(let offset): idx = offset;
case .FromEnd(let offset): idx = mLength - offset;
}
return ref Ptr[idx];
}
[Checked]
set
{
int idx;
switch (index)
{
case .FromFront(let offset): idx = offset;
case .FromEnd(let offset): idx = mLength - offset;
}
Debug.Assert((uint)idx < (uint)mLength);
Ptr[idx] = value;
}
[Unchecked, Inline]
set
{
int idx;
switch (index)
{
case .FromFront(let offset): idx = offset;
case .FromEnd(let offset): idx = mLength - offset;
}
Ptr[idx] = value;
}
}
public StringView this[IndexRange range]
{
#if !DEBUG
[Inline]
#endif
get
{
return StringView(Ptr, Length)[range];
}
} }
public void Concat(params Object[] objects) public void Concat(params Object[] objects)
@ -1351,12 +1429,7 @@ namespace System
return -1; return -1;
} }
public bool Contains(String str) public bool Contains(StringView str, bool ignoreCase = false)
{
return IndexOf(str) != -1;
}
public bool Contains(String str, bool ignoreCase)
{ {
return IndexOf(str, ignoreCase) != -1; return IndexOf(str, ignoreCase) != -1;
} }
@ -1542,7 +1615,7 @@ namespace System
mLength = newLength; mLength = newLength;
} }
public void Insert(int_strsize idx, char8 c) public void Insert(int idx, char8 c)
{ {
Contract.Requires(idx >= 0); Contract.Requires(idx >= 0);
@ -1557,7 +1630,7 @@ namespace System
mLength = newLength; mLength = newLength;
} }
public void Insert(int_strsize idx, char8 c, int count) public void Insert(int idx, char8 c, int count)
{ {
Contract.Requires(idx >= 0); Contract.Requires(idx >= 0);
@ -1576,7 +1649,7 @@ namespace System
mLength = newLength; mLength = newLength;
} }
public void Insert(int_strsize idx, char32 c) public void Insert(int idx, char32 c)
{ {
Contract.Requires(idx >= 0); Contract.Requires(idx >= 0);
@ -1625,7 +1698,7 @@ namespace System
} }
} }
public void Insert(int_strsize idx, char32 c, int count) public void Insert(int idx, char32 c, int count)
{ {
Contract.Requires(idx >= 0); Contract.Requires(idx >= 0);
@ -1700,7 +1773,7 @@ namespace System
//Contract.Assert((char8A | char8B) <= 0x7F, "strings have to be ASCII"); //Contract.Assert((char8A | char8B) <= 0x7F, "strings have to be ASCII");
// uppercase both char8s - notice that we need just one compare per char8 // uppercase both chars - notice that we need just one compare per char
if ((uint32)(charA - 'a') <= (uint32)('z' - 'a')) charA -= 0x20; if ((uint32)(charA - 'a') <= (uint32)('z' - 'a')) charA -= 0x20;
if ((uint32)(charB - 'a') <= (uint32)('z' - 'a')) charB -= 0x20; if ((uint32)(charB - 'a') <= (uint32)('z' - 'a')) charB -= 0x20;
@ -1708,7 +1781,7 @@ namespace System
if (charA != charB) if (charA != charB)
return false; return false;
// Next char8 // Next char
curA++;curB++; curA++;curB++;
curLength--; curLength--;
} }
@ -1733,7 +1806,7 @@ namespace System
//Contract.Assert((char8A | char8B) <= 0x7F, "strings have to be ASCII"); //Contract.Assert((char8A | char8B) <= 0x7F, "strings have to be ASCII");
// uppercase both char8s - notice that we need just one compare per char8 // uppercase both chars - notice that we need just one compare per char
if ((uint32)(charA - 'a') <= (uint32)('z' - 'a')) charA -= 0x20; if ((uint32)(charA - 'a') <= (uint32)('z' - 'a')) charA -= 0x20;
if ((uint32)(charB - 'a') <= (uint32)('z' - 'a')) charB -= 0x20; if ((uint32)(charB - 'a') <= (uint32)('z' - 'a')) charB -= 0x20;
@ -1741,7 +1814,7 @@ namespace System
if (charA != charB) if (charA != charB)
return charA - charB; return charA - charB;
// Next char8 // Next char
a++;b++; a++;b++;
length--; length--;
} }
@ -1761,7 +1834,7 @@ namespace System
int_strsize charB = (int_strsize)*b; int_strsize charB = (int_strsize)*b;
//Contract.Assert((char8A | char8B) <= 0x7F, "strings have to be ASCII"); //Contract.Assert((char8A | char8B) <= 0x7F, "strings have to be ASCII");
// uppercase both char8s - notice that we need just one compare per char8 // uppercase both chars - notice that we need just one compare per char
if ((uint32)(charA - 'a') <= (uint32)('z' - 'a')) charA -= 0x20; if ((uint32)(charA - 'a') <= (uint32)('z' - 'a')) charA -= 0x20;
if ((uint32)(charB - 'a') <= (uint32)('z' - 'a')) charB -= 0x20; if ((uint32)(charB - 'a') <= (uint32)('z' - 'a')) charB -= 0x20;
@ -1769,7 +1842,7 @@ namespace System
if (charA != charB) if (charA != charB)
return charA - charB; return charA - charB;
// Next char8 // Next char
a++;b++; a++;b++;
length--; length--;
} }
@ -2130,6 +2203,82 @@ namespace System
TrimEnd(); TrimEnd();
} }
public void TrimEnd(char32 trimChar)
{
let ptr = Ptr;
for (int i = mLength - 1; i >= 0; i--)
{
char8 c = ptr[i];
if (c >= (char8)0x80)
{
var (c32, idx, len) = GetChar32WithBacktrack(i);
if (c32 != trimChar)
{
if (i < mLength - 1)
RemoveToEnd(i + 1);
return;
}
i = idx;
}
else if ((char32)c != trimChar)
{
if (i < mLength - 1)
RemoveToEnd(i + 1);
return;
}
}
Clear();
}
public void TrimEnd(char8 trimChar)
{
TrimEnd((char32)trimChar);
}
public void TrimStart(char32 trimChar)
{
let ptr = Ptr;
for (int i = 0; i < mLength; i++)
{
char8 c = ptr[i];
if (c >= (char8)0x80)
{
var (c32, len) = GetChar32(i);
if (c32 != trimChar)
{
if (i > 0)
Remove(0, i);
return;
}
i += len - 1;
}
else if ((char32)c != trimChar)
{
if (i > 0)
Remove(0, i);
return;
}
}
Clear();
}
public void TrimStart(char8 trimChar)
{
TrimStart((char32)trimChar);
}
public void Trim(char32 trimChar)
{
TrimStart(trimChar);
TrimEnd(trimChar);
}
public void Trim(char8 trimChar)
{
TrimStart((.)trimChar);
TrimEnd((.)trimChar);
}
public void Join(StringView sep, IEnumerator<String> enumerable) public void Join(StringView sep, IEnumerator<String> enumerable)
{ {
bool isFirst = true; bool isFirst = true;
@ -2271,6 +2420,7 @@ namespace System
public RawEnumerator RawChars public RawEnumerator RawChars
{ {
[Inline]
get get
{ {
return RawEnumerator(Ptr, 0, mLength); return RawEnumerator(Ptr, 0, mLength);
@ -2279,6 +2429,7 @@ namespace System
public UTF8Enumerator DecodedChars public UTF8Enumerator DecodedChars
{ {
[Inline]
get get
{ {
return UTF8Enumerator(Ptr, 0, mLength); return UTF8Enumerator(Ptr, 0, mLength);
@ -2440,6 +2591,7 @@ namespace System
int_strsize mIdx; int_strsize mIdx;
int_strsize mLength; int_strsize mLength;
[Inline]
public this(char8* ptr, int idx, int length) public this(char8* ptr, int idx, int length)
{ {
mPtr = ptr; mPtr = ptr;
@ -2449,11 +2601,13 @@ namespace System
public char8 Current public char8 Current
{ {
[Inline]
get get
{ {
return mPtr[mIdx]; return mPtr[mIdx];
} }
[Inline]
set set
{ {
mPtr[mIdx] = value; mPtr[mIdx] = value;
@ -2462,6 +2616,7 @@ namespace System
public ref char8 CurrentRef public ref char8 CurrentRef
{ {
[Inline]
get get
{ {
return ref mPtr[mIdx]; return ref mPtr[mIdx];
@ -2470,6 +2625,7 @@ namespace System
public int Index public int Index
{ {
[Inline]
get get
{ {
return mIdx; return mIdx;
@ -2478,42 +2634,29 @@ namespace System
public int Length public int Length
{ {
[Inline]
get get
{ {
return mLength; return mLength;
} }
} }
public void Dispose() [Inline]
{ public Result<char8> GetNext() mut
}
public void Reset()
{
}
public bool MoveNext() mut
{ {
++mIdx; ++mIdx;
if (mIdx >= mLength) if (mIdx >= mLength)
return false;
return true;
}
public Result<char8> GetNext() mut
{
if (!MoveNext())
return .Err; return .Err;
return Current; return mPtr[mIdx];
} }
[Inline]
public Result<char8*> GetNextRef() mut public Result<char8*> GetNextRef() mut
{ {
if (!MoveNext()) ++mIdx;
if (mIdx >= mLength)
return .Err; return .Err;
return &CurrentRef; return &mPtr[mIdx];
} }
} }
@ -2670,6 +2813,14 @@ namespace System
} }
} }
public int32 MatchIndex
{
get
{
return mCurCount - 1;
}
}
public bool HasMore public bool HasMore
{ {
get get
@ -2821,6 +2972,97 @@ namespace System
mLength = length; mLength = length;
} }
public ref char8 this[int index]
{
[Checked]
get
{
Runtime.Assert((uint)index < (uint)mLength);
return ref mPtr[index];
}
[Unchecked, Inline]
get
{
return ref mPtr[index];
}
}
public ref char8 this[Index index]
{
[Checked]
get
{
int idx;
switch (index)
{
case .FromFront(let offset): idx = offset;
case .FromEnd(let offset): idx = mLength - offset;
}
Runtime.Assert((uint)idx < (uint)mLength);
return ref mPtr[idx];
}
[Unchecked, Inline]
get
{
int idx;
switch (index)
{
case .FromFront(let offset): idx = offset;
case .FromEnd(let offset): idx = mLength - offset;
}
return ref mPtr[idx];
}
}
public StringView this[IndexRange range]
{
#if !DEBUG
[Inline]
#endif
get
{
char8* start;
switch (range.[Friend]mStart)
{
case .FromFront(let offset):
Debug.Assert((uint)offset <= (uint)mLength);
start = mPtr + offset;
case .FromEnd(let offset):
Debug.Assert((uint)offset <= (uint)mLength);
start = mPtr + mLength - offset;
}
char8* end;
if (range.[Friend]mIsClosed)
{
switch (range.[Friend]mEnd)
{
case .FromFront(let offset):
Debug.Assert((uint)offset < (uint)mLength);
end = mPtr + offset + 1;
case .FromEnd(let offset):
Debug.Assert((uint)(offset - 1) <= (uint)mLength);
end = mPtr + mLength - offset + 1;
}
}
else
{
switch (range.[Friend]mEnd)
{
case .FromFront(let offset):
Debug.Assert((uint)offset <= (uint)mLength);
end = mPtr + offset;
case .FromEnd(let offset):
Debug.Assert((uint)offset <= (uint)mLength);
end = mPtr + mLength - offset;
}
}
return .(start, end - start);
}
}
public String.RawEnumerator RawChars public String.RawEnumerator RawChars
{ {
get get
@ -2914,6 +3156,13 @@ namespace System
return String.[Friend]CompareOrdinalHelper(val1.mPtr, val1.mLength, val2.mPtr, val2.mLength); return String.[Friend]CompareOrdinalHelper(val1.mPtr, val1.mLength, val2.mPtr, val2.mLength);
} }
public int CompareTo(StringView strB, bool ignoreCase = false)
{
if (ignoreCase)
return String.[Friend]CompareOrdinalIgnoreCaseHelper(Ptr, Length, strB.Ptr, strB.Length);
return String.[Friend]CompareOrdinalHelper(Ptr, Length, strB.Ptr, strB.Length);
}
public bool Equals(StringView str) public bool Equals(StringView str)
{ {
if (mLength != str.[Friend]mLength) if (mLength != str.[Friend]mLength)
@ -3037,9 +3286,9 @@ namespace System
return false; return false;
} }
public bool Contains(StringView stringView) public bool Contains(StringView stringView, bool ignoreCase = false)
{ {
return IndexOf(stringView) != -1; return IndexOf(stringView, ignoreCase) != -1;
} }
public bool StartsWith(StringView b, StringComparison comparisonType = StringComparison.Ordinal) public bool StartsWith(StringView b, StringComparison comparisonType = StringComparison.Ordinal)
@ -3130,6 +3379,92 @@ namespace System
TrimEnd(); TrimEnd();
} }
public void TrimEnd(char32 trimChar) mut
{
let ptr = Ptr;
for (int i = mLength - 1; i >= 0; i--)
{
char8 c = ptr[i];
if (c >= (char8)0x80)
{
var (c32, idx, len) = GetChar32WithBacktrack(i);
if (c32 != trimChar)
{
if (i < mLength - 1)
{
mLength = i + 1;
}
return;
}
i = idx;
}
else if (c != (char32)trimChar)
{
if (i < mLength - 1)
{
mLength = i + 1;
}
return;
}
}
Clear();
}
public void TrimEnd(char8 trimChar) mut
{
TrimEnd((char32)trimChar);
}
public void TrimStart(char32 trimChar) mut
{
let ptr = Ptr;
for (int i = 0; i < mLength; i++)
{
char8 c = ptr[i];
if (c >= (char8)0x80)
{
var (c32, len) = GetChar32(i);
if (c32 != trimChar)
{
if (i > 0)
{
mPtr += i;
mLength -= i;
}
return;
}
i += len - 1;
}
else if (c != (char32)trimChar)
{
if (i > 0)
{
mPtr += i;
mLength -= i;
}
return;
}
}
Clear();
}
public void TrimStart(char8 trimChar) mut
{
TrimStart((char32)trimChar);
}
public void Trim(char32 trimChar) mut
{
TrimStart(trimChar);
TrimEnd(trimChar);
}
public void Trim(char8 trimChar) mut
{
TrimStart((.)trimChar);
TrimEnd((.)trimChar);
}
public bool StartsWith(char8 c) public bool StartsWith(char8 c)
{ {
if (mLength == 0) if (mLength == 0)
@ -3137,6 +3472,15 @@ namespace System
return Ptr[0] == c; return Ptr[0] == c;
} }
public bool StartsWith(char32 c)
{
if (c < '\x80')
return StartsWith((char8)c);
if (mLength == 0)
return false;
return UTF8.Decode(Ptr, mLength).c == c;
}
public bool EndsWith(char8 c) public bool EndsWith(char8 c)
{ {
if (mLength == 0) if (mLength == 0)
@ -3144,6 +3488,19 @@ namespace System
return Ptr[mLength - 1] == c; return Ptr[mLength - 1] == c;
} }
public bool EndsWith(char32 c)
{
if (c < '\x80')
return EndsWith((char8)c);
if (mLength == 0)
return false;
char8* ptr = Ptr;
int idx = mLength - 1;
while ((idx > 0) && ((uint8)ptr[idx] & 0xC0 == 0x80))
idx--;
return UTF8.Decode(ptr + idx, mLength - idx).c == c;
}
public void QuoteString(String outString) public void QuoteString(String outString)
{ {
String.QuoteString(Ptr, Length, outString); String.QuoteString(Ptr, Length, outString);
@ -3226,6 +3583,34 @@ namespace System
return StringSplitEnumerator(Ptr, Length, separators, count, options); return StringSplitEnumerator(Ptr, Length, separators, count, options);
} }
public String Intern()
{
using (String.[Friend]sMonitor.Enter())
{
bool needsLiteralPass = String.[Friend]sInterns.Count == 0;
String* internalLinkPtr = *((String**)(String.[Friend]sStringLiterals));
if (internalLinkPtr != String.[Friend]sPrevInternLinkPtr)
{
String.[Friend]sPrevInternLinkPtr = internalLinkPtr;
needsLiteralPass = true;
}
if (needsLiteralPass)
String.[Friend]CheckLiterals(String.[Friend]sStringLiterals);
String* entryPtr;
if (String.[Friend]sInterns.TryAddAlt(this, out entryPtr))
{
String result = new String(mLength + 1);
result.Append(this);
result.EnsureNullTerminator();
*entryPtr = result;
String.[Friend]sOwnedInterns.Add(result);
return result;
}
return *entryPtr;
}
}
public static operator StringView (String str) public static operator StringView (String str)
{ {
StringView sv; StringView sv;

View file

@ -227,6 +227,26 @@ static
} }
} }
public static mixin DeleteContainerAndDisposeItems(var container)
{
if (container != null)
{
for (var value in container)
value.Dispose();
delete container;
}
}
public static mixin ClearAndDisposeItems(var container)
{
if (container != null)
{
for (var value in container)
value.Dispose();
container.Clear();
}
}
public static mixin DeleteAndNullify(var val) public static mixin DeleteAndNullify(var val)
{ {
delete val; delete val;

View file

@ -1,6 +1,7 @@
using System.Diagnostics; using System.Diagnostics;
namespace System.Text namespace System.Text
{ {
[StaticInitPriority(100)]
abstract class Encoding abstract class Encoding
{ {
public enum DecodeError public enum DecodeError

View file

@ -1,7 +1,7 @@
using System.Diagnostics; using System.Diagnostics;
namespace System.Text namespace System.Text
{ {
public class UTF16 public static class UTF16
{ {
public enum EncodeError public enum EncodeError
{ {
@ -140,10 +140,10 @@ namespace System.Text
public static int GetMaxEncodedLen(int utf8Len) public static int GetMaxEncodedLen(int utf8Len)
{ {
// Consider all incoming char8s are < \u80, each incoming char88 equals one outgoing char816 (utfLen * 1) // Consider all incoming chars are < \u80, each incoming char8 equals one outgoing char16 (utfLen * 1)
// For char8s from \u80 to \u7FF, then two incoming char88 equals one outgoing char816 (utfLen * 0.5) // For chars from \u80 to \u7FF, then two incoming char8 equals one outgoing char16 (utfLen * 0.5)
// For char8s from \u800 to \u7FFF, then three incoming char88 equals one or two char816s (utfLen * 0.33) to (utfLen * 0.67) // For chars from \u800 to \u7FFF, then three incoming char8 equals one or two char16s (utfLen * 0.33) to (utfLen * 0.67)
// For char8s from \u1000 to \u10FFFF, then four incoming char88 equals two outgoing char816s (utfLen * 0.5) // For chars from \u1000 to \u10FFFF, then four incoming char8 equals two outgoing char16s (utfLen * 0.5)
return utf8Len; return utf8Len;
} }
@ -211,7 +211,7 @@ namespace System.Text
if (c <= '\u{FFFF}') if (c <= '\u{FFFF}')
{ {
#if BF_UTF_PEDANTIC #if BF_UTF_PEDANTIC
// Illegal UTF16 char8? // Illegal UTF16 char?
Debug.Assert((c <= '\u{D7FF}') || (c >= '\u{E000}')); Debug.Assert((c <= '\u{D7FF}') || (c >= '\u{E000}'));
#endif #endif
EncodeChar((char16)c); EncodeChar((char16)c);

View file

@ -1,7 +1,7 @@
using System.Diagnostics; using System.Diagnostics;
namespace System.Text namespace System.Text
{ {
class UTF8 static class UTF8
{ {
public const int8[256] sTrailingBytesForUTF8 = public const int8[256] sTrailingBytesForUTF8 =
.( .(

View file

@ -8,10 +8,11 @@ namespace System.Threading
public delegate void ThreadStart(); public delegate void ThreadStart();
public delegate void ParameterizedThreadStart(Object obj); public delegate void ParameterizedThreadStart(Object obj);
[StaticInitPriority(100)]
public sealed class Thread public sealed class Thread
{ {
private int mInternalThread; private int mInternalThread;
private int32 mPriority; private ThreadPriority mPriority = .Normal;
public int32 mMaxStackSize; public int32 mMaxStackSize;
private String mName ~ delete _; private String mName ~ delete _;
private Delegate mDelegate; private Delegate mDelegate;
@ -21,7 +22,7 @@ namespace System.Threading
bool mAutoDelete; bool mAutoDelete;
public static Thread sMainThread = new Thread() ~ delete _; public static Thread sMainThread = new Thread() ~ delete _;
[StaticInitPriority(101)] [StaticInitPriority(102)]
struct RuntimeThreadInit struct RuntimeThreadInit
{ {
static Object Thread_Alloc() static Object Thread_Alloc()
@ -67,6 +68,8 @@ namespace System.Threading
if (thread.mName != null) if (thread.mName != null)
thread.InformThreadNameChange(thread.mName); thread.InformThreadNameChange(thread.mName);
if (thread.mPriority != .Normal)
thread.SetPriorityNative((.)thread.mPriority);
int32 stackStart = 0; int32 stackStart = 0;
thread.SetStackStart((void*)&stackStart); thread.SetStackStart((void*)&stackStart);
@ -219,8 +222,18 @@ namespace System.Threading
public ThreadPriority Priority public ThreadPriority Priority
{ {
get { return (ThreadPriority)GetPriorityNative(); } get
set { SetPriorityNative((int32)value); } {
if (mInternalThread != 0)
return (ThreadPriority)GetPriorityNative();
return mPriority;
}
set
{
mPriority = value;
if (mInternalThread != 0)
SetPriorityNative((int32)value);
}
} }
[CallingConvention(.Cdecl)] [CallingConvention(.Cdecl)]
private extern int32 GetPriorityNative(); private extern int32 GetPriorityNative();

View file

@ -253,7 +253,10 @@ namespace System {
if (rule != null) if (rule != null)
rule = rule.Clone(); rule = rule.Clone();
oneYearLocFromUtc = new OffsetAndRule(year, currentYear.BaseUtcOffset, rule); oneYearLocFromUtc = new OffsetAndRule(year, currentYear.BaseUtcOffset, rule);
m_oneYearLocalFromUtc = oneYearLocFromUtc; if (Interlocked.CompareExchange(ref m_oneYearLocalFromUtc, null, oneYearLocFromUtc) != null) {
delete oneYearLocFromUtc;
oneYearLocFromUtc = m_oneYearLocalFromUtc;
}
} }
return oneYearLocFromUtc; return oneYearLocFromUtc;
} }

View file

@ -27,6 +27,7 @@ namespace System
protected int32 mMemberDataOffset; protected int32 mMemberDataOffset;
protected TypeCode mTypeCode; protected TypeCode mTypeCode;
protected uint8 mAlign; protected uint8 mAlign;
protected uint8 mAllocStackCountOverride;
public static TypeId TypeIdEnd public static TypeId TypeIdEnd
{ {
@ -683,13 +684,7 @@ namespace System
namespace System.Reflection namespace System.Reflection
{ {
public struct TypeId : int32 public struct TypeId : int32 {}
{
public Type ToType()
{
return Type.[Friend]sTypes[(int32)this];
}
}
[Ordered, AlwaysInclude(AssumeInstantiated=true)] [Ordered, AlwaysInclude(AssumeInstantiated=true)]
public class TypeInstance : Type public class TypeInstance : Type
@ -724,6 +719,7 @@ namespace System.Reflection
public int32 mMethodIdx; public int32 mMethodIdx;
public int32 mVirtualIdx; public int32 mVirtualIdx;
public int32 mCustomAttributesIdx; public int32 mCustomAttributesIdx;
public int32 mReturnCustomAttributesIdx;
} }
public enum ParamFlags : int16 public enum ParamFlags : int16
@ -740,6 +736,7 @@ namespace System.Reflection
public TypeId mType; public TypeId mType;
public ParamFlags mParamFlags; public ParamFlags mParamFlags;
public int32 mDefaultIdx; public int32 mDefaultIdx;
public int32 mCustomAttributesIdx;
} }
public struct InterfaceData public struct InterfaceData
@ -1137,7 +1134,7 @@ namespace System.Reflection
public Type GetGenericArg(int argIdx) public Type GetGenericArg(int argIdx)
{ {
return mResolvedTypeRefs[argIdx].ToType(); return Type.GetType(mResolvedTypeRefs[argIdx]);
} }
public override void GetFullName(String strBuffer) public override void GetFullName(String strBuffer)
@ -1191,7 +1188,10 @@ namespace System.Reflection
let genericType = GetGenericArg(0); let genericType = GetGenericArg(0);
let arraySize = [Friend]mInstSize - genericType.Size + genericType.Stride * count; let arraySize = [Friend]mInstSize - genericType.Size + genericType.Stride * count;
#if BF_ENABLE_OBJECT_DEBUG_FLAGS #if BF_ENABLE_OBJECT_DEBUG_FLAGS
obj = Internal.Dbg_ObjectAlloc([Friend]mTypeClassVData, arraySize, [Friend]mInstAlign, 1); int32 stackCount = Compiler.Options.AllocStackCount;
if (mAllocStackCountOverride != 0)
stackCount = mAllocStackCountOverride;
obj = Internal.Dbg_ObjectAlloc([Friend]mTypeClassVData, arraySize, [Friend]mInstAlign, stackCount);
#else #else
void* mem = new [Align(16)] uint8[arraySize]* (?); void* mem = new [Align(16)] uint8[arraySize]* (?);
obj = Internal.UnsafeCastToObject(mem); obj = Internal.UnsafeCastToObject(mem);

View file

@ -48,8 +48,8 @@ namespace System
public struct VTable public struct VTable
{ {
public function HResult(COM_IUnknown* self, ref Guid riid, void** result) QueryInterface; public function HResult(COM_IUnknown* self, ref Guid riid, void** result) QueryInterface;
public function HResult(COM_IUnknown* self) AddRef; public function uint32(COM_IUnknown* self) AddRef;
public function HResult(COM_IUnknown* self) Release; public function uint32(COM_IUnknown* self) Release;
} }
public enum HResult : int32 public enum HResult : int32

View file

@ -876,7 +876,7 @@ namespace CURL
static extern int curl_easy_perform(void* curl); static extern int curl_easy_perform(void* curl);
[CLink, CallingConvention(.Stdcall)] [CLink, CallingConvention(.Stdcall)]
static extern void* curl_easy_getinfo(void* curl, Option option, void* ptr); static extern void* curl_easy_getinfo(void* curl, CurlInfo info, void* ptr);
[CLink, CallingConvention(.Stdcall)] [CLink, CallingConvention(.Stdcall)]
static extern void* curl_easy_reset(void* curl); static extern void* curl_easy_reset(void* curl);
@ -917,6 +917,12 @@ namespace CURL
return WrapResult((ReturnCode)curl_easy_setopt(mCURL, (int)option, (int)(void*)val.CStr())); return WrapResult((ReturnCode)curl_easy_setopt(mCURL, (int)option, (int)(void*)val.CStr()));
} }
public Result<void, ReturnCode> SetOpt(Option option, StringView val)
{
Debug.Assert((int)option / 10000 == 1);
return WrapResult((ReturnCode)curl_easy_setopt(mCURL, (int)option, (int)(void*)scope String(4096)..Append(val).CStr()));
}
public Result<void, ReturnCode> SetOpt(Option option, int val) public Result<void, ReturnCode> SetOpt(Option option, int val)
{ {
Debug.Assert(((int)option / 10000 == 0) || ((int)option / 10000 == 3)); Debug.Assert(((int)option / 10000 == 0) || ((int)option / 10000 == 3));
@ -935,6 +941,16 @@ namespace CURL
return WrapResult((ReturnCode)curl_easy_setopt(mCURL, (int)option, (int)funcPtr)); return WrapResult((ReturnCode)curl_easy_setopt(mCURL, (int)option, (int)funcPtr));
} }
public Result<void> GetInfo(CurlInfo info, String val)
{
char8* ptr = null;
curl_easy_getinfo(mCURL, info, &ptr);
if (ptr == null)
return .Err;
val.Append(ptr);
return .Ok;
}
public Result<void, ReturnCode> Perform() public Result<void, ReturnCode> Perform()
{ {
return WrapResult((ReturnCode)curl_easy_perform(mCURL)); return WrapResult((ReturnCode)curl_easy_perform(mCURL));

View file

@ -8,7 +8,8 @@ namespace CURL
{ {
class Transfer class Transfer
{ {
CURL.Easy mCurl = new CURL.Easy() ~ delete _; CURL.Easy mCurl;
bool mOwns;
bool mCancelling = false; bool mCancelling = false;
List<uint8> mData = new List<uint8>() ~ delete _; List<uint8> mData = new List<uint8>() ~ delete _;
Stopwatch mStatsTimer = new Stopwatch() ~ delete _; Stopwatch mStatsTimer = new Stopwatch() ~ delete _;
@ -59,7 +60,13 @@ namespace CURL
public this() public this()
{ {
mCurl = new CURL.Easy();
mOwns = true;
}
public this(CURL.Easy curl)
{
mCurl = curl;
} }
public ~this() public ~this()
@ -67,6 +74,9 @@ namespace CURL
mCancelling = true; mCancelling = true;
if (mRunning) if (mRunning)
mDoneEvent.WaitFor(); mDoneEvent.WaitFor();
if (mOwns)
delete mCurl;
} }
int GetCurBytesPerSecond() int GetCurBytesPerSecond()
@ -119,7 +129,7 @@ namespace CURL
return count; return count;
} }
public void Init(String url) public void Init(StringView url)
{ {
function int(void *p, int dltotal, int dlnow, int ultotal, int ulnow) callback = => Callback; function int(void *p, int dltotal, int dlnow, int ultotal, int ulnow) callback = => Callback;
mCurl.SetOptFunc(.XferInfoFunction, (void*)callback); mCurl.SetOptFunc(.XferInfoFunction, (void*)callback);
@ -133,6 +143,13 @@ namespace CURL
mCurl.SetOpt(.URL, url); mCurl.SetOpt(.URL, url);
mCurl.SetOpt(.NoProgress, false); mCurl.SetOpt(.NoProgress, false);
mCurl.SetOpt(.IPResolve, (int)CURL.Easy.IPResolve.V4); mCurl.SetOpt(.IPResolve, (int)CURL.Easy.IPResolve.V4);
mCurl.SetOpt(.HTTPGet, true);
}
public void InitPost(String url, String param)
{
Init(url);
mCurl.SetOpt(.Postfields, param);
} }
public Result<Span<uint8>> Perform() public Result<Span<uint8>> Perform()
@ -178,6 +195,11 @@ namespace CURL
return mResult; return mResult;
} }
public void GetContentType(String outContentType)
{
mCurl.GetInfo(.ContentType, outContentType);
}
public void Cancel(bool wait = false) public void Cancel(bool wait = false)
{ {
mCancelling = true; mCancelling = true;

View file

@ -421,8 +421,13 @@ void BFGC::RawShutdown()
gDbgErrorString = errorStr; gDbgErrorString = errorStr;
gDbgErrorString += "\n"; gDbgErrorString += "\n";
int passLeakCount = 0;
for (auto& rawLeak : mSweepInfo.mRawLeaks) for (auto& rawLeak : mSweepInfo.mRawLeaks)
{ {
if (passLeakCount == 20000) // Only display so many...
break;
Beefy::String typeName; Beefy::String typeName;
if (rawLeak.mRawAllocData->mType != NULL) if (rawLeak.mRawAllocData->mType != NULL)
typeName = rawLeak.mRawAllocData->mType->GetFullName() + "*"; typeName = rawLeak.mRawAllocData->mType->GetFullName() + "*";
@ -451,6 +456,8 @@ void BFGC::RawShutdown()
if (gDbgErrorString.length() < 256) if (gDbgErrorString.length() < 256)
gDbgErrorString += StrFormat(" %s\n", leakStr.c_str()); gDbgErrorString += StrFormat(" %s\n", leakStr.c_str());
passLeakCount++;
} }
BF_ASSERT(mSweepInfo.mLeakCount > 0); BF_ASSERT(mSweepInfo.mLeakCount > 0);

View file

@ -84,7 +84,7 @@ namespace bf
void*(*Alloc)(intptr size); void*(*Alloc)(intptr size);
void(*Free)(void* ptr); void(*Free)(void* ptr);
void(*Object_Delete)(bf::System::Object* obj); void(*Object_Delete)(bf::System::Object* obj);
void(*Object_ToString)(bf::System::Object* obj, bf::System::String* str); void* mUnused0;
bf::System::Type* (*Object_GetType)(bf::System::Object* obj); bf::System::Type* (*Object_GetType)(bf::System::Object* obj);
void(*Object_GCMarkMembers)(bf::System::Object* obj); void(*Object_GCMarkMembers)(bf::System::Object* obj);
bf::System::Object* (*Object_DynamicCastToTypeId)(bf::System::Object* obj, int typeId); bf::System::Object* (*Object_DynamicCastToTypeId)(bf::System::Object* obj, int typeId);

View file

@ -85,7 +85,6 @@ namespace bf
BFRT_EXPORT static void* UnsafeCastToPtr(Object* obj); BFRT_EXPORT static void* UnsafeCastToPtr(Object* obj);
BFRT_EXPORT static void ObjectDynCheck(Object* object, int typeId, bool allowNull); BFRT_EXPORT static void ObjectDynCheck(Object* object, int typeId, bool allowNull);
BFRT_EXPORT static void ObjectDynCheckFailed(Object* object, int typeId); BFRT_EXPORT static void ObjectDynCheckFailed(Object* object, int typeId);
BFRT_EXPORT static void Throw(Exception* ex);
BFRT_EXPORT static void ThrowIndexOutOfRange(intptr stackOffset); BFRT_EXPORT static void ThrowIndexOutOfRange(intptr stackOffset);
BFRT_EXPORT static void FatalError(String* error, intptr stackOffset = 0); BFRT_EXPORT static void FatalError(String* error, intptr stackOffset = 0);
BFRT_EXPORT static void MemCpy(void* dest, void* src, intptr length); BFRT_EXPORT static void MemCpy(void* dest, void* src, intptr length);
@ -215,17 +214,19 @@ static void TestReadCmd(Beefy::String& str);
static void Internal_FatalError(const char* error) static void Internal_FatalError(const char* error)
{ {
if (gClientPipe != NULL) if ((gClientPipe != NULL) && (!gTestBreakOnFailure))
{ {
Beefy::String str = ":TestFatal\t"; Beefy::String str = ":TestFatal\t";
str += error; str += error;
str.Replace('\n', '\r');
str += "\n"; str += "\n";
TestString(str); TestString(str);
Beefy::String result; Beefy::String result;
TestReadCmd(result); TestReadCmd(result);
exit(1);
} }
else
BfpSystem_FatalError(error, "BEEF FATAL ERROR"); BfpSystem_FatalError(error, "BEEF FATAL ERROR");
} }
@ -395,26 +396,21 @@ void* Internal::UnsafeCastToPtr(Object* obj)
return (void*)obj; return (void*)obj;
} }
void Internal::Throw(Exception* ex)
{
bf::System::String* exStr = gBfRtCallbacks.String_Alloc();
gBfRtCallbacks.Object_ToString(ex, exStr);
Beefy::String errorStr = StrFormat("FATAL: %s", exStr->CStr());
SETUP_ERROR(errorStr.c_str(), 1);
BF_DEBUG_BREAK();
gBfRtCallbacks.DebugMessageData_Fatal();
printf("Thrown: %s", errorStr.c_str());
//TODO: What about capturing callstack?
exit(3);
//throw ex;
}
void Internal::ThrowIndexOutOfRange(intptr stackOffset) void Internal::ThrowIndexOutOfRange(intptr stackOffset)
{ {
if (gClientPipe != NULL)
{
if (gTestBreakOnFailure)
{
SETUP_ERROR("Index out of range", (int)(2 + stackOffset));
BF_DEBUG_BREAK();
}
Beefy::String str = ":TestFail\tIndex out of range\n";
TestString(str);
exit(1);
}
if ((stackOffset != -1) && (::IsDebuggerPresent())) if ((stackOffset != -1) && (::IsDebuggerPresent()))
{ {
SETUP_ERROR("Index out of range", (int)(2 + stackOffset)); SETUP_ERROR("Index out of range", (int)(2 + stackOffset));
@ -426,6 +422,22 @@ void Internal::ThrowIndexOutOfRange(intptr stackOffset)
void Internal::FatalError(bf::System::String* error, intptr stackOffset) void Internal::FatalError(bf::System::String* error, intptr stackOffset)
{ {
if (gClientPipe != NULL)
{
if (gTestBreakOnFailure)
{
SETUP_ERROR(error->CStr(), (int)(2 + stackOffset));
BF_DEBUG_BREAK();
}
Beefy::String str = ":TestFail\t";
str += error->CStr();
str.Replace('\n', '\r');
str += "\n";
TestString(str);
exit(1);
}
if ((stackOffset != -1) && (::IsDebuggerPresent())) if ((stackOffset != -1) && (::IsDebuggerPresent()))
{ {
SETUP_ERROR(error->CStr(), (int)(2 + stackOffset)); SETUP_ERROR(error->CStr(), (int)(2 + stackOffset));
@ -659,6 +671,7 @@ void Internal::Test_Error(char* error)
{ {
Beefy::String str = ":TestFail\t"; Beefy::String str = ":TestFail\t";
str += error; str += error;
str.Replace('\n', '\r');
str += "\n"; str += "\n";
TestString(str); TestString(str);
} }
@ -670,12 +683,7 @@ void Internal::Test_Write(char* strPtr)
{ {
Beefy::String str = ":TestWrite\t"; Beefy::String str = ":TestWrite\t";
str += strPtr; str += strPtr;
for (char& c : str) str.Replace('\n', '\r');
{
if (c == '\n')
c = '\r';
}
str += "\n"; str += "\n";
TestString(str); TestString(str);
} }

View file

@ -53,12 +53,12 @@ void Thread::SetJoinOnDelete(bool joinOnDelete)
int Thread::GetPriorityNative() int Thread::GetPriorityNative()
{ {
return (int)BfpThread_GetPriority(GetInternalThread()->mThreadHandle, NULL); return (int)BfpThread_GetPriority(GetInternalThread()->mThreadHandle, NULL) + 2;
} }
void Thread::SetPriorityNative(int priority) void Thread::SetPriorityNative(int priority)
{ {
return BfpThread_SetPriority(GetInternalThread()->mThreadHandle, (BfpThreadPriority)priority, NULL); return BfpThread_SetPriority(GetInternalThread()->mThreadHandle, (BfpThreadPriority)(priority - 2), NULL);
} }
bool Thread::GetIsAlive() bool Thread::GetIsAlive()

View file

@ -234,9 +234,8 @@ namespace BeefPerf
mMainFrame = new MainFrame(); mMainFrame = new MainFrame();
mDockingFrame = mMainFrame.mDockingFrame; mDockingFrame = mMainFrame.mDockingFrame;
BFWindow.Flags windowFlags = BFWindow.Flags.Border | BFWindow.Flags.SysMenu | //| BFWindow.Flags.CaptureMediaKeys | BFWindow.Flags windowFlags = .Border | .SysMenu | .Caption | .Minimize | .Maximize |
BFWindow.Flags.Caption | BFWindow.Flags.Minimize | BFWindow.Flags.QuitOnClose | BFWindowBase.Flags.Resizable | .QuitOnClose | .Resizable | .Menu;
BFWindow.Flags.Menu | BFWindow.Flags.SysMenu;
if (mWantsFullscreen) if (mWantsFullscreen)
windowFlags |= BFWindowBase.Flags.Fullscreen; windowFlags |= BFWindowBase.Flags.Fullscreen;
@ -336,7 +335,7 @@ namespace BeefPerf
void SetupTab(TabbedView tabbedView, String label, Widget widget) void SetupTab(TabbedView tabbedView, String label, Widget widget)
{ {
var tabButton = tabbedView.AddTab(label, 0, widget, false); var tabButton = tabbedView.AddTab(label, 0, widget, false, 0);
tabButton.mCloseClickedEvent.Add(new () => tabButton.mCloseClickedEvent.Add(new () =>
{ {
var tabbedView = tabButton.mTabbedView; var tabbedView = tabButton.mTabbedView;
@ -921,7 +920,7 @@ namespace BeefPerf
TabbedView tabbedView = FindTabbedView(mDockingFrame, -1, 1); TabbedView tabbedView = FindTabbedView(mDockingFrame, -1, 1);
if (tabbedView != null) if (tabbedView != null)
{ {
tabButton = tabbedView.AddTab(name, width, tabContent, ownsContent); tabButton = tabbedView.AddTab(name, width, tabContent, ownsContent, 0);
result = ShowTabResult.OpenedNew; result = ShowTabResult.OpenedNew;
} }
} }

View file

@ -311,7 +311,7 @@ namespace BeefPerf
{ {
var str = scope::String(); var str = scope::String();
if (argView.UnQuoteString(str) case .Err) if (argView.UnQuoteString(str) case .Err)
Fail("Failed to unquote string"); Fail($"Failed to unquote string: {argView}\nCmd:{cmdLineView}");
args.Add(str); args.Add(str);
isLiteralString = false; isLiteralString = false;
} }
@ -322,7 +322,7 @@ namespace BeefPerf
case .Ok(let val): case .Ok(let val):
args.Add(scope:: box val); args.Add(scope:: box val);
case .Err: case .Err:
Fail("Failed to parse float"); Fail($"Failed to parse float: {argView}\nCmd:{cmdLineView}");
return; return;
} }
} }
@ -333,7 +333,7 @@ namespace BeefPerf
case .Ok(let val): case .Ok(let val):
args.Add(scope:: box val); args.Add(scope:: box val);
case .Err: case .Err:
Fail("Failed to parse double"); Fail($"Failed to parse double: {argView}\nCmd:{cmdLineView}");
return; return;
} }
} }
@ -344,7 +344,7 @@ namespace BeefPerf
case .Ok(let val): case .Ok(let val):
args.Add(scope:: box val); args.Add(scope:: box val);
case .Err: case .Err:
Fail("Failed to parse int"); Fail($"Failed to parse int: {argView}\nCmd:{cmdLineView}");
return; return;
} }
} }

View file

@ -610,6 +610,23 @@ BF_EXPORT void BF_CALLTYPE Gfx_DrawQuads(TextureSegment* textureSegment, Default
} }
} }
BF_EXPORT void BF_CALLTYPE Gfx_DrawIndexedVertices(int vertexSize, void* vtxData, int vtxCount, uint16* idxData, int idxCount)
{
DrawLayer* drawLayer = gBFApp->mRenderDevice->mCurDrawLayer;
uint16 idxOfs;
void* drawBatchVtxPtr;
uint16* drawBatchIdxPtr;
gBFApp->mRenderDevice->mCurDrawLayer->AllocIndexed(vtxCount, idxCount, (void**)&drawBatchVtxPtr, &drawBatchIdxPtr, &idxOfs);
BF_ASSERT(gBFApp->mRenderDevice->mCurDrawLayer->mCurDrawBatch->mVtxSize == vertexSize);
uint16* idxPtr = idxData;
for (int idxIdx = 0; idxIdx < idxCount; idxIdx++)
*(drawBatchIdxPtr++) = *(idxPtr++) + idxOfs;
memcpy(drawBatchVtxPtr, vtxData, vertexSize * vtxCount);
}
BF_EXPORT void BF_CALLTYPE Gfx_DrawIndexedVertices2D(int vertexSize, void* vtxData, int vtxCount, uint16* idxData, int idxCount, float a, float b, float c, float d, float tx, float ty, float z) BF_EXPORT void BF_CALLTYPE Gfx_DrawIndexedVertices2D(int vertexSize, void* vtxData, int vtxCount, uint16* idxData, int idxCount, float a, float b, float c, float d, float tx, float ty, float z)
{ {
DrawLayer* drawLayer = gBFApp->mRenderDevice->mCurDrawLayer; DrawLayer* drawLayer = gBFApp->mRenderDevice->mCurDrawLayer;
@ -643,14 +660,14 @@ BF_EXPORT void BF_CALLTYPE Gfx_DrawIndexedVertices2D(int vertexSize, void* vtxDa
} }
} }
BF_EXPORT void BF_CALLTYPE Gfx_SetShaderConstantData(int slotIdx, void* constData, int size) BF_EXPORT void BF_CALLTYPE Gfx_SetShaderConstantData(int usageIdx, int slotIdx, void* constData, int size)
{ {
gBFApp->mRenderDevice->mCurDrawLayer->SetShaderConstantData(slotIdx, constData, size); gBFApp->mRenderDevice->mCurDrawLayer->SetShaderConstantData(usageIdx, slotIdx, constData, size);
} }
BF_EXPORT void BF_CALLTYPE Gfx_SetShaderConstantDataTyped(int slotIdx, void* constData, int size, int* typeData, int typeCount) BF_EXPORT void BF_CALLTYPE Gfx_SetShaderConstantDataTyped(int usageIdx, int slotIdx, void* constData, int size, int* typeData, int typeCount)
{ {
gBFApp->mRenderDevice->mCurDrawLayer->SetShaderConstantDataTyped(slotIdx, constData, size, typeData, typeCount); gBFApp->mRenderDevice->mCurDrawLayer->SetShaderConstantDataTyped(usageIdx, slotIdx, constData, size, typeData, typeCount);
} }
BF_EXPORT void BF_CALLTYPE Gfx_QueueRenderCmd(RenderCmd* renderCmd) BF_EXPORT void BF_CALLTYPE Gfx_QueueRenderCmd(RenderCmd* renderCmd)
@ -678,6 +695,16 @@ BF_EXPORT void BF_CALLTYPE RenderState_Delete(RenderState* renderState)
delete renderState; delete renderState;
} }
BF_EXPORT void BF_CALLTYPE RenderState_SetTexWrap(RenderState* renderState, bool texWrap)
{
renderState->SetTexWrap(texWrap);
}
BF_EXPORT void BF_CALLTYPE RenderState_SetWireframe(RenderState* renderState, bool wireframe)
{
renderState->SetWireframe(wireframe);
}
BF_EXPORT void BF_CALLTYPE RenderState_SetClip(RenderState* renderState, float x, float y, float width, float height) BF_EXPORT void BF_CALLTYPE RenderState_SetClip(RenderState* renderState, float x, float y, float width, float height)
{ {
BF_ASSERT((width >= 0) && (height >= 0)); BF_ASSERT((width >= 0) && (height >= 0));
@ -715,6 +742,11 @@ BF_EXPORT void BF_CALLTYPE RenderState_SetDepthWrite(RenderState* renderState, i
renderState->SetWriteDepthBuffer(depthWrite != 0); renderState->SetWriteDepthBuffer(depthWrite != 0);
} }
BF_EXPORT void BF_CALLTYPE RenderState_SetTopology(RenderState* renderState, int topology)
{
renderState->SetTopology((Topology3D)topology);
}
BF_EXPORT Shader* BF_CALLTYPE Gfx_LoadShader(const char* fileName, VertexDefinition* vertexDefinition) BF_EXPORT Shader* BF_CALLTYPE Gfx_LoadShader(const char* fileName, VertexDefinition* vertexDefinition)
{ {
return gBFApp->mRenderDevice->LoadShader(fileName, vertexDefinition); return gBFApp->mRenderDevice->LoadShader(fileName, vertexDefinition);

View file

@ -445,6 +445,7 @@ copy /y "$(OutDir)$(TargetName).lib" "$(SolutionDir)\BeefLibs\Beefy2D\dist\"</Co
<ClCompile Include="FileStream.cpp" /> <ClCompile Include="FileStream.cpp" />
<ClCompile Include="gfx\DrawLayer.cpp" /> <ClCompile Include="gfx\DrawLayer.cpp" />
<ClCompile Include="gfx\FTFont.cpp" /> <ClCompile Include="gfx\FTFont.cpp" />
<ClCompile Include="gfx\glTF.cpp" />
<ClCompile Include="gfx\ModelDef.cpp" /> <ClCompile Include="gfx\ModelDef.cpp" />
<ClCompile Include="gfx\ModelInstance.cpp" /> <ClCompile Include="gfx\ModelInstance.cpp" />
<ClCompile Include="gfx\RenderCmd.cpp" /> <ClCompile Include="gfx\RenderCmd.cpp" />
@ -1929,16 +1930,20 @@ copy /y "$(OutDir)$(TargetName).lib" "$(SolutionDir)\BeefLibs\Beefy2D\dist\"</Co
<ClCompile Include="util\BSpline.cpp" /> <ClCompile Include="util\BSpline.cpp" />
<ClCompile Include="util\CatmullRom.cpp" /> <ClCompile Include="util\CatmullRom.cpp" />
<ClCompile Include="util\ChunkedDataBuffer.cpp" /> <ClCompile Include="util\ChunkedDataBuffer.cpp" />
<ClCompile Include="util\Compress.cpp" />
<ClCompile Include="util\CubicFuncSpline.cpp" /> <ClCompile Include="util\CubicFuncSpline.cpp" />
<ClCompile Include="util\CubicSpline.cpp" /> <ClCompile Include="util\CubicSpline.cpp" />
<ClCompile Include="util\Hash.cpp" /> <ClCompile Include="util\Hash.cpp" />
<ClCompile Include="util\Heap.cpp" /> <ClCompile Include="util\Heap.cpp" />
<ClCompile Include="util\Json.cpp" />
<ClCompile Include="util\MappedFile.cpp" /> <ClCompile Include="util\MappedFile.cpp" />
<ClCompile Include="util\MathUtils.cpp" />
<ClCompile Include="util\Matrix4.cpp" /> <ClCompile Include="util\Matrix4.cpp" />
<ClCompile Include="util\PerfTimer.cpp" /> <ClCompile Include="util\PerfTimer.cpp" />
<ClCompile Include="util\Point.cpp" /> <ClCompile Include="util\Point.cpp" />
<ClCompile Include="util\PolySpline.cpp" /> <ClCompile Include="util\PolySpline.cpp" />
<ClCompile Include="util\Quaternion.cpp" /> <ClCompile Include="util\Quaternion.cpp" />
<ClCompile Include="util\Sphere.cpp" />
<ClCompile Include="util\StackHelper.cpp" /> <ClCompile Include="util\StackHelper.cpp" />
<ClCompile Include="util\String.cpp" /> <ClCompile Include="util\String.cpp" />
<ClCompile Include="util\ThreadPool.cpp" /> <ClCompile Include="util\ThreadPool.cpp" />
@ -1958,6 +1963,7 @@ copy /y "$(OutDir)$(TargetName).lib" "$(SolutionDir)\BeefLibs\Beefy2D\dist\"</Co
<ClInclude Include="gfx\DrawLayer.h" /> <ClInclude Include="gfx\DrawLayer.h" />
<ClInclude Include="gfx\Font.h" /> <ClInclude Include="gfx\Font.h" />
<ClInclude Include="gfx\FTFont.h" /> <ClInclude Include="gfx\FTFont.h" />
<ClInclude Include="gfx\glTF.h" />
<ClInclude Include="gfx\ModelDef.h" /> <ClInclude Include="gfx\ModelDef.h" />
<ClInclude Include="gfx\ModelInstance.h" /> <ClInclude Include="gfx\ModelInstance.h" />
<ClInclude Include="gfx\RenderCmd.h" /> <ClInclude Include="gfx\RenderCmd.h" />
@ -2152,6 +2158,7 @@ copy /y "$(OutDir)$(TargetName).lib" "$(SolutionDir)\BeefLibs\Beefy2D\dist\"</Co
<ClInclude Include="util\CatmullRom.h" /> <ClInclude Include="util\CatmullRom.h" />
<ClInclude Include="Util\ChunkedDataBuffer.h" /> <ClInclude Include="Util\ChunkedDataBuffer.h" />
<ClInclude Include="util\ChunkedVector.h" /> <ClInclude Include="util\ChunkedVector.h" />
<ClInclude Include="util\Compress.h" />
<ClInclude Include="util\CritSect.h" /> <ClInclude Include="util\CritSect.h" />
<ClInclude Include="util\CubicFuncSpline.h" /> <ClInclude Include="util\CubicFuncSpline.h" />
<ClInclude Include="util\CubicSpline.h" /> <ClInclude Include="util\CubicSpline.h" />
@ -2161,7 +2168,9 @@ copy /y "$(OutDir)$(TargetName).lib" "$(SolutionDir)\BeefLibs\Beefy2D\dist\"</Co
<ClInclude Include="util\Hash.h" /> <ClInclude Include="util\Hash.h" />
<ClInclude Include="util\HashSet.h" /> <ClInclude Include="util\HashSet.h" />
<ClInclude Include="util\Heap.h" /> <ClInclude Include="util\Heap.h" />
<ClInclude Include="util\Json.h" />
<ClInclude Include="util\MappedFile.h" /> <ClInclude Include="util\MappedFile.h" />
<ClInclude Include="util\MathUtils.h" />
<ClInclude Include="util\Matrix4.h" /> <ClInclude Include="util\Matrix4.h" />
<ClInclude Include="util\MultiHashSet.h" /> <ClInclude Include="util\MultiHashSet.h" />
<ClInclude Include="util\PerfTimer.h" /> <ClInclude Include="util\PerfTimer.h" />
@ -2172,6 +2181,7 @@ copy /y "$(OutDir)$(TargetName).lib" "$(SolutionDir)\BeefLibs\Beefy2D\dist\"</Co
<ClInclude Include="util\Rect.h" /> <ClInclude Include="util\Rect.h" />
<ClInclude Include="util\SizedArray.h" /> <ClInclude Include="util\SizedArray.h" />
<ClInclude Include="util\SLIList.h" /> <ClInclude Include="util\SLIList.h" />
<ClInclude Include="util\Sphere.h" />
<ClInclude Include="util\StackHelper.h" /> <ClInclude Include="util\StackHelper.h" />
<ClInclude Include="util\String.h" /> <ClInclude Include="util\String.h" />
<ClInclude Include="util\ThreadPool.h" /> <ClInclude Include="util\ThreadPool.h" />

View file

@ -707,6 +707,21 @@
<ClCompile Include="util\Heap.cpp"> <ClCompile Include="util\Heap.cpp">
<Filter>src\util</Filter> <Filter>src\util</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="gfx\glTF.cpp">
<Filter>src\gfx</Filter>
</ClCompile>
<ClCompile Include="util\Json.cpp">
<Filter>src\util</Filter>
</ClCompile>
<ClCompile Include="util\MathUtils.cpp">
<Filter>src\util</Filter>
</ClCompile>
<ClCompile Include="util\Sphere.cpp">
<Filter>src\util</Filter>
</ClCompile>
<ClCompile Include="util\Compress.cpp">
<Filter>src\util</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="Common.h"> <ClInclude Include="Common.h">
@ -1075,6 +1090,21 @@
<ClInclude Include="util\Heap.h"> <ClInclude Include="util\Heap.h">
<Filter>src\util</Filter> <Filter>src\util</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="gfx\glTF.h">
<Filter>src\gfx</Filter>
</ClInclude>
<ClInclude Include="util\Json.h">
<Filter>src\util</Filter>
</ClInclude>
<ClInclude Include="util\MathUtils.h">
<Filter>src\util</Filter>
</ClInclude>
<ClInclude Include="util\Sphere.h">
<Filter>src\util</Filter>
</ClInclude>
<ClInclude Include="util\Compress.h">
<Filter>src\util</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<CustomBuild Include="third_party\libffi\i686-pc-cygwin\src\x86\win32.asm"> <CustomBuild Include="third_party\libffi\i686-pc-cygwin\src\x86\win32.asm">

View file

@ -278,6 +278,7 @@ file(GLOB SRC_FILES
util/BSpline.cpp util/BSpline.cpp
util/CatmullRom.cpp util/CatmullRom.cpp
util/ChunkedDataBuffer.cpp util/ChunkedDataBuffer.cpp
util/Compress.cpp
util/CubicFuncSpline.cpp util/CubicFuncSpline.cpp
util/CubicSpline.cpp util/CubicSpline.cpp
util/FileEnumerator.cpp util/FileEnumerator.cpp
@ -285,11 +286,13 @@ file(GLOB SRC_FILES
util/Heap.cpp util/Heap.cpp
util/Json.cpp util/Json.cpp
util/MappedFile.cpp util/MappedFile.cpp
util/MathUtils.cpp
util/Matrix4.cpp util/Matrix4.cpp
util/PerfTimer.cpp util/PerfTimer.cpp
util/Point.cpp util/Point.cpp
util/PolySpline.cpp util/PolySpline.cpp
util/Quaternion.cpp util/Quaternion.cpp
util/Sphere.cpp
util/String.cpp util/String.cpp
util/StackHelper.cpp util/StackHelper.cpp
util/ThreadPool.cpp util/ThreadPool.cpp

View file

@ -7,6 +7,7 @@
#include "platform/PlatformHelper.h" #include "platform/PlatformHelper.h"
#ifndef BF_SMALL #ifndef BF_SMALL
#define STB_SPRINTF_DECORATE(name) BF_stbsp_##name
#define STB_SPRINTF_IMPLEMENTATION #define STB_SPRINTF_IMPLEMENTATION
#include "third_party/stb/stb_sprintf.h" #include "third_party/stb/stb_sprintf.h"
#endif #endif
@ -811,7 +812,7 @@ String Beefy::vformat(const char* fmt, va_list argPtr)
{ {
String str; String str;
char buf[STB_SPRINTF_MIN]; char buf[STB_SPRINTF_MIN];
stbsp_vsprintfcb(StbspCallback, (void*)&str, buf, fmt, argPtr); BF_stbsp_vsprintfcb(StbspCallback, (void*)&str, buf, fmt, argPtr);
return str; return str;
} }
#endif #endif
@ -943,6 +944,21 @@ char* Beefy::LoadTextData(const StringImpl& path, int* size)
return data; return data;
} }
bool Beefy::LoadTextData(const StringImpl& path, StringImpl& str)
{
int size = 0;
char* data = LoadTextData(path, &size);
if (data == NULL)
return false;
if ((str.mAllocSizeAndFlags & StringImpl::DynAllocFlag) != 0)
str.Release();
str.mPtr = data;
str.mAllocSizeAndFlags = size | StringImpl::DynAllocFlag | StringImpl::StrPtrFlag;
str.mLength = size;
return true;
}
#ifdef BF_MINGW #ifdef BF_MINGW
unsigned long long __cdecl _byteswap_uint64(unsigned long long _Int64) unsigned long long __cdecl _byteswap_uint64(unsigned long long _Int64)
{ {
@ -1263,3 +1279,4 @@ void Beefy::BFFatalError(const char* message, const char* file, int line)
{ {
BFFatalError(String(message), String(file), line); BFFatalError(String(message), String(file), line);
} }

View file

@ -220,6 +220,7 @@ int32 GetHighestBitSet(int32 n);
uint8* LoadBinaryData(const StringImpl& path, int* size); uint8* LoadBinaryData(const StringImpl& path, int* size);
char* LoadTextData(const StringImpl& path, int* size); char* LoadTextData(const StringImpl& path, int* size);
bool LoadTextData(const StringImpl& path, StringImpl& str);
int64 GetFileTimeWrite(const StringImpl& path); int64 GetFileTimeWrite(const StringImpl& path);
String GetFileDir(const StringImpl& path); String GetFileDir(const StringImpl& path);
String GetFileName(const StringImpl& path); String GetFileName(const StringImpl& path);

View file

@ -49,6 +49,14 @@ public:
Read((void*) &val, sizeof(T)); Read((void*) &val, sizeof(T));
} }
template <typename T>
T ReadT()
{
T val;
Read((void*)&val, sizeof(T));
return val;
}
virtual void Write(float val); virtual void Write(float val);
virtual void Write(uint8 val); virtual void Write(uint8 val);
virtual void Write(int8 val); virtual void Write(int8 val);

View file

@ -219,7 +219,8 @@ void SysFileStream::SetSizeFast(int size)
int curPos = GetPos(); int curPos = GetPos();
SetPos(size); SetPos(size);
BfpFile_Truncate(mFile); BfpFileResult result = BfpFileResult_Ok;
BfpFile_Truncate(mFile, &result);
SetPos(curPos); SetPos(curPos);
return; return;
} }

View file

@ -9,7 +9,7 @@ class Span
{ {
public: public:
T* mVals; T* mVals;
int mSize; intptr mSize;
public: public:
struct Iterator struct Iterator
@ -47,16 +47,17 @@ public:
Span() Span()
{ {
}
Span(T* mPtr, int size)
{
mSize = (int)refVec.size();
mVals = NULL; mVals = NULL;
mSize = 0;
} }
T& operator[](int idx) const Span(T* mPtr, intptr size)
{
mVals = mPtr;
mSize = size;
}
T& operator[](intptr idx) const
{ {
return mVals[idx]; return mVals[idx];
} }
@ -76,7 +77,7 @@ public:
return mVals[mSize - 1]; return mVals[mSize - 1];
} }
int size() const intptr size() const
{ {
return mSize; return mSize;
} }
@ -91,7 +92,7 @@ public:
return mSize == 0; return mSize == 0;
} }
T Get(int idx) T Get(intptr idx)
{ {
if ((idx < 0) || (idx >= mSize)) if ((idx < 0) || (idx >= mSize))
return (T)0; return (T)0;
@ -99,7 +100,7 @@ public:
} }
template <typename T2> template <typename T2>
T2 GetAs(int idx) T2 GetAs(intptr idx)
{ {
if ((idx < 0) || (idx >= mSize)) if ((idx < 0) || (idx >= mSize))
return (T2)0; return (T2)0;
@ -120,7 +121,7 @@ public:
return mVals[0]; return mVals[0];
} }
void SetSize(int size) void SetSize(intptr size)
{ {
BF_ASSERT(size <= mSize); BF_ASSERT(size <= mSize);
mSize = size; mSize = size;

View file

@ -339,9 +339,9 @@ void DrawLayer::SetTexture(int texIdx, Texture* texture)
} }
} }
void DrawLayer::SetShaderConstantDataTyped(int slotIdx, void* constData, int size, int* typeData, int typeCount) void DrawLayer::SetShaderConstantDataTyped(int usageIdx, int slotIdx, void* constData, int size, int* typeData, int typeCount)
{ {
SetShaderConstantData(slotIdx, constData, size); SetShaderConstantData(usageIdx, slotIdx, constData, size);
} }
/// ///
@ -390,5 +390,6 @@ BF_EXPORT void BF_CALLTYPE DrawLayer_DrawToRenderTarget(DrawLayer* drawLayer, Te
renderDevice->PhysSetRenderState(renderDevice->mDefaultRenderState); renderDevice->PhysSetRenderState(renderDevice->mDefaultRenderState);
renderDevice->PhysSetRenderTarget(textureSegment->mTexture); renderDevice->PhysSetRenderTarget(textureSegment->mTexture);
drawLayer->Draw(); drawLayer->Draw();
drawLayer->Clear();
renderDevice->mCurRenderTarget = prevTarget; renderDevice->mCurRenderTarget = prevTarget;
} }

View file

@ -99,8 +99,8 @@ public:
virtual DrawBatch* AllocateBatch(int minVtxCount, int minIdxCount); virtual DrawBatch* AllocateBatch(int minVtxCount, int minIdxCount);
void QueueRenderCmd(RenderCmd* renderCmd); void QueueRenderCmd(RenderCmd* renderCmd);
virtual RenderCmd* CreateSetTextureCmd(int textureIdx, Texture* texture) = 0; virtual RenderCmd* CreateSetTextureCmd(int textureIdx, Texture* texture) = 0;
virtual void SetShaderConstantData(int slotIdx, void* constData, int size) = 0; virtual void SetShaderConstantData(int usageIdx, int slotIdx, void* constData, int size) = 0;
virtual void SetShaderConstantDataTyped(int slotIdx, void* constData, int size, int* typeData, int typeCount); virtual void SetShaderConstantDataTyped(int usageIdx, int slotIdx, void* constData, int size, int* typeData, int typeCount);
public: public:
DrawLayer(); DrawLayer();

View file

@ -144,7 +144,16 @@ bool FTFont::Load(const StringImpl& fileName, float pointSize)
face->mFileName = fileName; face->mFileName = fileName;
FT_Face ftFace = NULL; FT_Face ftFace = NULL;
auto error = FT_New_Face(gFTLibrary, fileName.c_str(), 0, &ftFace);
String useFileName = fileName;
int faceIdx = 0;
int atPos = (int)useFileName.IndexOf('@');
if (atPos != -1)
{
faceIdx = atoi(useFileName.c_str() + atPos + 1);
useFileName.RemoveToEnd(atPos);
}
auto error = FT_New_Face(gFTLibrary, useFileName.c_str(), faceIdx, &ftFace);
face->mFTFace = ftFace; face->mFTFace = ftFace;
} }
else else

Some files were not shown because too many files have changed in this diff Show more